Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@
"Bash(git -C * log:*)",
"Bash(git push origin overnight/*)",
"Bash(git -C * push origin overnight/*)",
"Bash(gh pr create:*)"
"Bash(git push origin chore/tasks-discover-*)",
"Bash(git -C * push origin chore/tasks-discover-*)",
"Bash(git push origin chore/tasks-plan-*)",
"Bash(git -C * push origin chore/tasks-plan-*)",
"Bash(git pull:*)",
"Bash(git -C * pull:*)",
"Bash(gh pr create:*)",
"Bash(gh pr merge chore/tasks-discover-*:*)",
"Bash(gh pr merge chore/tasks-plan-*:*)"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
],
"deny": [
"Bash(git push origin main:*)",
Expand Down
13 changes: 13 additions & 0 deletions .claude/skills/discover-tasks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ disable-model-invocation: true

A target repo is attached via --add-dir. Two independent sourcing phases: memory-mining (always runs) and repo-scanning (only with `--scan`).

## Multi-repo mode

Determine this from the attached directory's structure, never by assumption: does it have a `.git` at its own root?

- Yes: it's a single target repo. Phases 1–4 below apply directly, exactly as written — this is today's behavior, unchanged.
- No, but its immediate subdirectories do: the attached directory is `PROJECT_REPOS_DIR` itself, and the repo set is those subdirectories. Run this flow instead of a single Phases 1–4 pass:
1. Announce: "Found N repo(s) under `<dir>`."
2. Dispatch one `general-purpose` agent per repo — all in a single message, foreground, batched in groups of ~8 if there are more than that — each told to run Phase 1 + Phase 2 steps 1–3 for its one assigned repo (absolute path stated explicitly) and report back its candidate list (task text, rationale, source) — report only, never ask, never write. Use `general-purpose`, not `Plan`: a dispatch needs Agent-tool access itself to reach `task-scout` when `--scan` is passed, and `Plan`-type agents don't have that.
3. Once every dispatch returns, go through repos in the order they were listed. For each one: run Phase 2 step 4 (present its candidates, get my approval), then immediately Phase 3 (write) and Phase 4 (finalize) for that repo, before moving to the next.

Announce each phase to me in one line before starting it.

## Phase 1: locate memory
Expand Down Expand Up @@ -42,5 +52,8 @@ Uncommitted content in the target repo's working tree is dangerous — lost work
6. Commit as `chore(tasks): discover N candidate task(s)`, body listing each item and its memory source.
7. Push, open a PR (`gh pr create`) targeting the default branch — title matches the commit, body summarizes the additions.
8. Report the PR URL.
9. Merge it: `gh pr merge <branch-name> --squash --delete-branch`, using the exact branch name from step 4 (not a PR number — that's what the scoped `chore/tasks-discover-*` merge permission matches against). This is safe specifically because every item going in was already explicitly approved by me in Phase 2 step 4 — the merge completes something already signed off on, it doesn't approve anything new.
10. Merge command fails (e.g. branch protection requires a review)? Report the failure plainly and leave the PR open. Don't retry, don't force, don't fall back to raw `git merge` — that stays denied regardless.
11. Merge succeeds: `git -C <repo> checkout` the default branch and pull latest, so the working tree's TASKS.md reflects the merge before this session ends — that's what lets a later `/plan-tasks` or `overnight.sh` run see these additions without anyone merging by hand.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Do not implement any code in this session. Do not touch `docs/tasks-archive/` or `docs/nightlight-meta.json`.
29 changes: 19 additions & 10 deletions .claude/skills/plan-tasks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ disable-model-invocation: true

A target repo is attached via --add-dir. Read its TASKS.md, CLAUDE.md, and docs/nightlight-meta.json (if present — `nextTaskNumber` is the next number to assign; treat a missing file as `nextTaskNumber: 1`).

`## Discovered` holds raw, un-triaged candidates (no `#<n>`, no `[stack]`) — they're in scope below alongside native Agent-Ready/Verify/Research/Decisions items.
## Multi-repo mode

More than one repo attached via --add-dir (`plan.sh`'s no-arg mode passes one `--add-dir` per repo that has open, unchecked `TASKS.md` work): read TASKS.md/CLAUDE.md/docs/nightlight-meta.json for every attached repo, keeping each repo's state separate — `#<n>` numbering, `[stack]` names, and `nextTaskNumber` are all per-repo, never shared or cross-referenced across repos. Investigate (parallel) below dispatches across every attached repo's items in one combined batch; Synthesize then runs once per repo, in the order the repos were attached, each with its own approval, write, and finalize before moving to the next. One repo attached: today's flow, unchanged.

`## Discovered` holds raw, un-triaged candidates (no `#<n>`, no `[stack]`) — they're in scope below alongside native Agent-Ready/Verify/Research/Decisions items, for every attached repo.

## Investigate (parallel)

Every unchecked item (including Discovered ones) gets its own investigation — dispatch one `Plan`-type agent per item, all as parallel foreground tool calls in a single message. Never investigate items one at a time in the main thread; that's the slow path this phase replaces. If there are more than ~8 items, dispatch in batches of that size rather than serially one-by-one.
Every unchecked item across every attached repo (including Discovered ones) gets its own investigation — dispatch one `Plan`-type agent per item, all as parallel foreground tool calls in a single message, regardless of which repo it belongs to. Never investigate items one at a time in the main thread; that's the slow path this phase replaces. If there are more than ~8 items total, dispatch in batches of that size rather than serially one-by-one.

Each dispatch is self-contained (the agent has no memory of this session) and must state: the item's exact text, the target repo's absolute path, and that it should read that repo's CLAUDE.md itself for conventions. Ask each agent to report back — never implement — with:
Each dispatch is self-contained (the agent has no memory of this session) and must state: the item's exact text, its repo's absolute path, and that it should read that repo's CLAUDE.md itself for conventions. Ask each agent to report back — never implement — with:

1. For a Discovered item: which section it actually belongs in — Agent-Ready (the common case), Verify, Research, or Decisions (flag for my judgment).
2. A sub-task breakdown with file-level hints and any missing acceptance criteria.
Expand All @@ -21,21 +25,23 @@ Each dispatch is self-contained (the agent has no memory of this session) and mu

## Synthesize

Once every dispatched investigation has returned:
Once every dispatched investigation has returned, process repos one at a time, in the order they were attached (single-repo mode: just the one). For each repo:

1. Cross-reference reported touch-points and dependencies across all items: share `[stack: <name>]`, in execution order, if they depend on each other or touch the same files; independent items get `[stack: solo]`. When in doubt, stack.
2. Assign each item a stable `#<n>`, starting from `nextTaskNumber` and incrementing per item, in write order.
1. Cross-reference reported touch-points and dependencies across that repo's items only — stacks and numbering never cross repos: share `[stack: <name>]`, in execution order, if they depend on each other or touch the same files; independent items get `[stack: solo]`. When in doubt, stack.
2. Assign each item a stable `#<n>`, starting from that repo's own `nextTaskNumber` and incrementing per item, in write order.
3. Propose where each item lands in its target section's existing list — default to the bottom, but ask me explicitly where I want each one; I may want something worked first (e.g. a quick bug fix ahead of a bigger feature).

Present the full proposal for my approval BEFORE writing anything — triage decisions (for former Discovered items), breakdowns/numbers/stack tags, and proposed position per item. After I approve:

- Write the breakdowns, `#<n>` numbers, and `[stack]` tags into TASKS.md at the approved position — every checkbox line gets its number right after the checkbox, before the stack tag (e.g. `- [ ] #48 [stack: auth] Add rate limiting to login endpoint`).
- Remove triaged items from `## Discovered`.
- Update `docs/nightlight-meta.json`'s `nextTaskNumber` to one past the highest number assigned (create it with `nextTaskNumber`, `tasksCompleted: 0`, `tasksBlocked: 0` if missing).
- Write the breakdowns, `#<n>` numbers, and `[stack]` tags into that repo's TASKS.md at the approved position — every checkbox line gets its number right after the checkbox, before the stack tag (e.g. `- [ ] #48 [stack: auth] Add rate limiting to login endpoint`).
- Remove triaged items from that repo's `## Discovered`.
- Update that repo's `docs/nightlight-meta.json`'s `nextTaskNumber` to one past the highest number assigned (create it with `nextTaskNumber`, `tasksCompleted: 0`, `tasksBlocked: 0` if missing).

Then immediately run Finalize (below) for that repo before starting the next repo's Synthesize.

## Finalize

Uncommitted content in the target repo's working tree is dangerous — lost work, or silently swept into unrelated commits. Don't leave the TASKS.md/nightlight-meta.json edits uncommitted. Once written:
Uncommitted content in the target repo's working tree is dangerous — lost work, or silently swept into unrelated commits. Don't leave the TASKS.md/nightlight-meta.json edits uncommitted. Once written, for this repo:

1. Confirm planning is done and I want these changes committed + PR'd. Don't proceed without an explicit yes.
2. Resolve the default branch: `git -C <repo> symbolic-ref --quiet --short refs/remotes/origin/HEAD` (strip `origin/`), falling back to local `main` then `master` — same resolution `overnight.sh`'s `default_branch()` uses.
Expand All @@ -45,5 +51,8 @@ Uncommitted content in the target repo's working tree is dangerous — lost work
6. Commit as `chore(tasks): number and stack N task(s)`, body listing the task numbers and stack names assigned.
7. Push, open a PR (`gh pr create`) targeting the default branch — title matches the commit, body summarizes the assignments.
8. Report the PR URL.
9. Merge it: `gh pr merge <branch-name> --squash --delete-branch`, using the exact branch name from step 4 (not a PR number — that's what the scoped `chore/tasks-plan-*` merge permission matches against). This is safe specifically because the breakdown/numbering/stacking going in was already explicitly approved by me in Synthesize — the merge completes something already signed off on, it doesn't approve anything new.
10. Merge command fails (e.g. branch protection requires a review)? Report the failure plainly and leave the PR open. Don't retry, don't force, don't fall back to raw `git merge` — that stays denied regardless.
11. Merge succeeds: `git -C <repo> checkout` the default branch and pull latest, so the working tree's TASKS.md reflects the merge before this repo's finalize is done — that's what lets a later `overnight.sh` run see the numbering/stacking without anyone merging by hand.

Do not implement any code in this session.
Loading