Skip to content

Configure labels and harnesses

Use dreamcatcher.toml to decide which GitHub labels start assignments, campaigns or issue conversations, and which dispatch recipe each label uses. Put the file in the root of the repository's main checkout and commit it when everyone watching the repository should use the same routes.

You need the harness CLIs you configure on PATH, plus an authenticated gh. dreamcatcher reads the file when the daemon starts, so restart a running daemon after changing it.

dreamcatcher init writes a starting file with routes for the dream plugin's skills, when the checkout has none. Edit that file, or write your own. init installs the dream plugin for each harness the file uses, even when its prompts invoke other skills.

Start with distinct labels

Choose labels that say what kind of work they invite. The following file gives Claude one assignment route, one campaign route and one conversation route:

[[assignment]]
label = "agent-assignment"

[assignment.claude]
prompt = "/dream:smith GH{issue}"
model = "opus[1m]"
effort = "high"

[[campaign]]
label = "agent-campaign"

[campaign.claude]
prompt = "/dream:big GH{issue}"
model = "opus[1m]"
effort = "high"

[[conversation]]
label = "discuss"

[conversation.claude]
prompt = "Investigate the question on GH{issue} and return a concise answer."
model = "opus[1m]"
effort = "high"

Run dreamcatcher init to create any of the file's labels that the GitHub repository lacks. Label matching is case-insensitive, but using the same spelling everywhere makes the route easier to recognise.

An assignment prompt normally invokes an installed assignment skill. The skill must know how to adopt dreamcatcher's branch and draft pull request; authors can find the exact requirements in the assignment skill contract. A campaign prompt normally invokes a campaign skill such as dream:big, whose requirements are in the campaign skill contract. A conversation prompt normally invokes a conversation skill, but it can be plain instructions, as above, because dreamcatcher adds the input and publication instructions itself. Authors can find the conversation skill's requirements in the conversation skill contract.

Match the recipe to how hard the work is

Give work of one kind more than one route when it varies in how much capability it needs. Each route's recipe sets that capability through the skill that its prompt runs, its model and its effort. The file that init writes has two assignment routes, and Customise skills says what the skill of each one does. agent-assignment-easy runs a lighter skill on a smaller model than agent-assignment does. Put agent-assignment-easy on an issue only when the work is easy to get right, such as a typo or a renamed setting. A small change can still be hard, and then it needs agent-assignment.

To give the hardest work a stronger recipe, add an assignment route under a label of its own, such as agent-assignment-hard.

Decide which harness runs a route

Each route needs a claude recipe, a codex recipe, or both. The recipe fixes the prompt, model, effort and any harness config that new work is created with.

The --harness value on dreamcatcher run is the preference for a route that offers both harnesses. A route that offers only Claude always uses Claude; a route that offers only Codex always uses Codex. At startup dreamcatcher checks that the preferred harness and every harness mentioned anywhere in the file is installed.

A codex recipe can also give Codex settings of its own, such as a larger context window:

[assignment.codex]
prompt = "$dream:smith GH{issue}"
model = "gpt-5.6-sol"
effort = "high"
config = { model_context_window = 1000000, model_auto_compact_token_limit = 900000 }

dreamcatcher passes each entry to every Codex round. The configuration reference says which values it accepts and which settings it keeps for itself.

Existing agent work keeps the label, harness and recipe it started with, even if its route is later removed.

See the configuration reference for a two-harness example and every accepted setting.

Label an issue for agent work

An issue is available for a new assignment when it:

  • is open and assigned to the account authenticated through gh;
  • carries exactly one configured assignment label, which you applied yourself;
  • has no open assignment already managed by this checkout;
  • has no other open pull request linked to it; and
  • has no open issue recorded by GitHub as blocking it.

If an issue carries two configured assignment labels, dreamcatcher reports a routing conflict instead of guessing which recipe to use. Removing an assignment label after dispatch does not stop the active assignment: its saved route and pull request continue to govern later rounds. Use the controls in Stop and recover work when you need to intervene.

A conversation starts on an open issue that is assigned to the authenticated account and carries exactly one configured conversation label, which you applied yourself, once you post a comment. Unassigning the issue or removing the conversation's label pauses the conversation, adding a second conversation label or another account applying its label holds it back too, and closing the issue ends it. Discuss an issue explains both.

A campaign starts on an open parent issue that is assigned to the authenticated account, carries exactly one configured campaign label, which you applied yourself, and has no open issue recorded by GitHub as blocking it. It pauses, is held back and ends as a conversation does. Start a campaign explains how.

Labels of different kinds may coexist on an issue because they select different kinds of work.

Apply a dispatch label yourself, once the issue is assigned to you. Work starts, and paused work resumes, only on a label that the authenticated account applied. A label that a colleague puts on an issue assigned to you starts nothing, and the status report shows its request as held, naming who labelled the issue. Remove the label and add it again yourself to start the work.

Apply and check the configuration

Commit and push dreamcatcher.toml and any project instructions or setup files the agents need. Every agent's worktree starts from fetched origin/main, so local uncommitted files are not available to it.

Then start or restart the daemon from the ordinary main checkout:

dreamcatcher run --harness claude

A missing harness, invalid setting or duplicate label is reported before the daemon begins scheduling. For all daemon options, see the run command reference.