Workflow sources (Global vs Project)

Where Roscoe looks for workflow files and which one wins on collision.

Global vs project is about where a workflow lives and who it's for. Roscoe reads workflows from two directories: a personal global library at ~/.roscoe/workflows/, and a team-shared project library at <repo>/.roscoe/workflows/. A global workflow is yours in every repo; a project workflow ships with one repo. This page covers how the two resolve, which wins on collision, and how to move a workflow between them.

The two sources#

Source Location When to use
Global ~/.roscoe/workflows/ Personal, cross-project: your scratch library, seeded examples
Project <repo>/.roscoe/workflows/ Team-shared, committed to the repo so everyone gets the same copy

Both are scanned on every list, lookup, and run. Workflows are plain *.workflow.yaml files; the file stem is the workflow id (e.g. demo-3-name-tournament.workflow.yaml is demo-3-name-tournament).

The Global path can be redirected with ROSCOE_HOME. The Project path is detected from the current working directory's git root, or pinned with ROSCOE_REPO_HOME. See /docs/configuration/environment.

Resolution: repo wins#

When the same id exists in both sources, the project copy is the one that runs. The displaced global entry is still listed and marked as shadowed, so you can see what's being masked:

Surface What you see
CLI roscoe list prints the global row with a [shadowed by repo] marker
Web UI The Workflows page dims the row and adds a shadow indicator to the source chip
MCP list_workflows sets a shadowed: true flag on the displaced entry

When you roscoe run <id> without --source, the runner picks repo first if present, otherwise global. A # resolved 'X' from repo (shadows global) — use --source global to override notice is printed when the repo copy wins over an existing global entry, so you always know which file ran.

Forcing a source#

Pass --source to bypass the default repo-first rule:

roscoe run demo-1-the-panel --source global   # run the global copy even if repo has one
roscoe run demo-1-the-panel --source repo     # require the project copy; fail if missing

MCP tools that resolve a workflow (get_workflow, start_workflow, validate_workflow, lint_workflow, update_workflow, delete_workflow, rename_workflow) accept the same optional source parameter. Omitting it resolves repo-first.

Moving workflows between sources#

Two routes: from the web UI, open the workflow detail page and pick Move to Project or Move to Global from the kebab menu; or, over MCP, call move_workflow with to: 'global' | 'repo'.

Both round-trip through POST /api/workflows/:id/move. The move refuses if the target source already has a workflow with that id. Duplicate first, then delete, if you really want to overwrite.

duplicate_workflow is the close cousin: copies a workflow under a new id and updates the duplicate's name field, optionally landing it in the other source.

What roscoe init does#

roscoe init creates ~/.roscoe/workflows/ unconditionally and <repo>/.roscoe/workflows/ when run inside a git repo. It seeds nine example workflows (demo-1-the-panel, demo-2-week-of-dinners, demo-3-name-tournament, demo-4-second-draft, demo-5-reality-check, demo-6-gift-shortlist, demo-7-fair-price, demo-8-smell-test, demo-9-check-one-claim) into Global only. Project starts empty, leaving the team to fill it deliberately.

The init scope can be narrowed:

roscoe init --global-only   # skip the repo scaffolding entirely
roscoe init --repo-only     # skip the global init

See /docs/running/cli for the full init flag list.

See also#

View this page as Markdown

Predictable workflows from unpredictable AI