From parent issue to merged pull requests¶
Some work spans several issues, each needing its own pull request. They may be steps towards one feature, some waiting on others, or unrelated fixes that could all go at once. With assignments alone, you'd shepherd each one yourself: start it, review its pull request, merge it, and start whatever was waiting on it.
A campaign hands that shepherding to an agent, called the lead. You gather the issues as sub-issues of one parent issue, and label the parent. The lead sets up an assignment for each sub-issue, and dreamcatcher starts each one once nothing blocks it. The lead reviews each pull request against what its sub-issue says done looks like, merges it, and asks you on the parent when a decision is needed.
The lead merges pull requests without waiting for your review. Use a
repository that has a README.md, and where you are happy for the lead
to merge under your GitHub account. If main requires an approving
review before a merge, the lead cannot merge, because GitHub does not
let an account approve its own pull request.
This tutorial creates a parent issue with two sub-issues. The second is
blocked by the first, so the lead carries their pull requests to main
in order. At the end, you close the parent.
1. Set up dreamcatcher¶
Follow steps 1 to 4 of From issue to pull request, and
stop once you have pushed dreamcatcher.toml at the end of
step 4. Don't prepare an issue or
start dreamcatcher yet. Those steps install the tools, sign you in and
write a dreamcatcher.toml that routes the dream:lead label to
campaigns.
If you already run dreamcatcher on the repository, check that your
tools meet step 1 of that tutorial.
Its dreamcatcher.toml needs the dream:lead campaign route and at
least one assignment route for the lead to give the sub-issues.
Configure a campaign route
says how to add the route and update the dream plugin.
2. Write the plan¶
A campaign's plan is a parent issue that holds the goal, with the work divided among its sub-issues. Each sub-issue says how to tell that its work is done, and the lead checks that before it merges.
From the main checkout, create the parent issue and assign it to yourself:
gh issue create --assignee "@me" --title "Add a project glossary" --body "Give the project a glossary that readers can reach from the README. Divide the work between its sub-issues."
gh prints the address of the new issue. Suppose it ends in
/issues/123. The commands below call the parent 123 and the sub-issues
124 and 125; replace each number with the one that gh prints for you.
Create the first sub-issue of the parent:
gh issue create --parent 123 --title "Add GLOSSARY.md" --body "Add GLOSSARY.md at the root of the repository, with one entry that defines the project's name in one sentence. Done when GLOSSARY.md is on main with that entry."
Create the second sub-issue, blocked by the first:
gh issue create --parent 123 --blocked-by 124 --title "Link the glossary from the README" --body "Add a line to README.md that links to GLOSSARY.md. Done when README.md on main links to GLOSSARY.md."
Open the parent on GitHub. It lists both sub-issues, and issue 125 shows that issue 124 blocks it. dreamcatcher starts no assignment for a blocked issue, so the second sub-issue waits until the first one closes.
3. Start dreamcatcher¶
From the main checkout, start the daemon in its own terminal:
dreamcatcher run --harness claude --interval 30 --max-agents 2
Keep this terminal open. dreamcatcher looks for work, waits 30 seconds after each look, and runs at most two agent rounds at once, so the lead and an assignment's agent can work at the same time. Your browser opens the web home page.
4. Start the campaign¶
Add the dream:lead label to the parent:
gh issue edit 123 --add-label dream:lead
At its next update, dreamcatcher starts the lead. On the web home
page, open the Campaigns tab. The campaign's card shows the parent,
the lead's status and + 0 of 2 sub-issues closed. Select the count to
show the sub-issues.
In its first round, the lead reads the plan and sets up an assignment
for each sub-issue. It assigns each sub-issue to you and adds an
assignment label, such as dream:smith. Then it ends its turn, and the
campaign shows as idle. Under the card:
- issue 124 gets an assignment, which opens a draft pull request and starts work; and
- issue 125 shows as blocked by #124.
The lead does not post on the parent to say what it set up. Follow it in its feed instead, on the campaign's page or in a second terminal:
dreamcatcher feed GH123
5. Watch the first sub-issue¶
The first assignment's agent implements what the sub-issue asks for, and marks the pull request ready for review when it is done. You don't need to review it yourself, but you can comment on it as you would on any pull request.
Once the assignment's agent has finished its turn, dreamcatcher wakes the lead, and the lead reviews the pull request. It checks the sub-issue's "Done when" at the pull request's head. If something is missing, it comments on the pull request, the assignment's agent answers in its next round, and the lead reviews again.
When the sub-issue is done and its checks pass, the lead merges the pull
request. The merge closes issue 124, and the card shows
+ 1 of 2 sub-issues closed. The first sub-issue's assignment takes one
last wrap-up round, then shows as completed.
6. Watch the handoff¶
Issue 124 is closed, so issue 125 is no longer blocked. At the next
update, dreamcatcher starts the second sub-issue's assignment from
main, which now holds GLOSSARY.md. If the second sub-issue needs to
know something from the first, the lead comments on issue 125 before it
merges the first pull request, and the second assignment's agent reads
that comment when it starts.
The second assignment then goes the same way as the first: its agent
works, the lead reviews and merges, and the card shows
+ 2 of 2 sub-issues closed.
7. Answer the lead when it asks¶
The lead asks you on the parent when a decision is needed, for example:
- no assignment route clearly fits a sub-issue;
- an assignment's agent asks something that the plan does not settle;
- a sub-issue falls into fault, or its pull request is closed without a merge; or
- the plan itself would need to change.
The lead posts under your account, so GitHub does not notify you of its comments. Its posts end with "written by an agent". If the sub-issues stop moving while the campaign shows as idle, read the parent:
gh issue view 123 --comments
Answer with a comment on the parent. At the next update, the lead is given your comment and carries on from where it stopped.
8. Close the parent¶
When every sub-issue is closed, the lead posts once on the parent to say
so. Open README.md on GitHub, and follow its link to GLOSSARY.md.
If you are satisfied, close the parent:
gh issue close 123
The campaign ends once any running round finishes, and its card moves to the ended list. If you want more work instead, add another sub-issue to the parent, and the lead sets up its assignment.
When you have no more work for dreamcatcher, press Ctrl-C in the terminal where it runs to stop it.
Continue with Start a campaign to give the lead a plan of your own, talk to it on the parent, or pause the campaign.