claudius-core 0.11.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/manager.md +13 -0
- package/.claude/agents/product-engineer.md +1 -1
- package/.claude/agents/worker.md +126 -274
- package/.claude/hooks/continue-or-stop.ts +5 -5
- package/.claude/rules/claudius.md +10 -11
- package/.claude/skills/backlog/SKILL.md +2 -4
- package/.claude/skills/build/SKILL.md +2 -2
- package/.claude/skills/setup/references/claude-md-template.md +2 -3
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -4
- package/dist/cli/studio.js +1 -1
- package/dist/cli/studio.js.map +1 -1
- package/dist/config-migrations.d.ts.map +1 -1
- package/dist/config-migrations.js +12 -0
- package/dist/config-migrations.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -8
- package/dist/config.js.map +1 -1
- package/dist/daemon/constraints.js +12 -12
- package/dist/daemon/constraints.js.map +1 -1
- package/dist/daemon/{pulse.d.ts → daemon-engine.d.ts} +9 -12
- package/dist/daemon/daemon-engine.d.ts.map +1 -0
- package/dist/daemon/{pulse.js → daemon-engine.js} +19 -49
- package/dist/daemon/daemon-engine.js.map +1 -0
- package/dist/daemon/{pulse-state.d.ts → daemon-state.d.ts} +15 -15
- package/dist/daemon/daemon-state.d.ts.map +1 -0
- package/dist/daemon/{pulse-state.js → daemon-state.js} +14 -14
- package/dist/daemon/daemon-state.js.map +1 -0
- package/dist/daemon/ideation.d.ts +1 -1
- package/dist/daemon/ideation.js +1 -1
- package/dist/daemon/index.d.ts +2 -2
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +1 -1
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/scheduler.js +3 -3
- package/dist/daemon/scheduler.js.map +1 -1
- package/dist/index.js +45 -78
- package/dist/index.js.map +1 -1
- package/dist/init.js +3 -3
- package/dist/studio/assets/{_basePickBy-SgrcV4p1.js → _basePickBy-C0C1UMqb.js} +1 -1
- package/dist/studio/assets/{_baseUniq-CiukiKHL.js → _baseUniq-lLYar-5Y.js} +1 -1
- package/dist/studio/assets/{arc-0_bnzzzz.js → arc-B4B0Sc8l.js} +1 -1
- package/dist/studio/assets/{architectureDiagram-VXUJARFQ-BNCCzuHj.js → architectureDiagram-VXUJARFQ-UrceXxEH.js} +1 -1
- package/dist/studio/assets/{blockDiagram-VD42YOAC-D5esiyUw.js → blockDiagram-VD42YOAC-CvYK8VWA.js} +1 -1
- package/dist/studio/assets/{c4Diagram-YG6GDRKO-DMdccA3n.js → c4Diagram-YG6GDRKO-_ckzdZuX.js} +1 -1
- package/dist/studio/assets/channel-DRNVimKP.js +1 -0
- package/dist/studio/assets/{chunk-4BX2VUAB-OVrqps1h.js → chunk-4BX2VUAB-D1WHj5fM.js} +1 -1
- package/dist/studio/assets/{chunk-55IACEB6-DWH6itPv.js → chunk-55IACEB6-BSHXVvS_.js} +1 -1
- package/dist/studio/assets/{chunk-B4BG7PRW-nwXv1-Ab.js → chunk-B4BG7PRW-DMnqWEap.js} +1 -1
- package/dist/studio/assets/{chunk-DI55MBZ5-1FXag2Ue.js → chunk-DI55MBZ5-DRxXXjD7.js} +1 -1
- package/dist/studio/assets/{chunk-FMBD7UC4-YfUfI5D0.js → chunk-FMBD7UC4-Dw-LAyOV.js} +1 -1
- package/dist/studio/assets/{chunk-QN33PNHL-6DlGBXbx.js → chunk-QN33PNHL-BxwIhM7e.js} +1 -1
- package/dist/studio/assets/{chunk-QZHKN3VN-DjZzE3f2.js → chunk-QZHKN3VN-BPcNLqG7.js} +1 -1
- package/dist/studio/assets/{chunk-TZMSLE5B-ID9EuE6l.js → chunk-TZMSLE5B-DV6JBoyK.js} +1 -1
- package/dist/studio/assets/classDiagram-2ON5EDUG-uk4oDEHA.js +1 -0
- package/dist/studio/assets/classDiagram-v2-WZHVMYZB-uk4oDEHA.js +1 -0
- package/dist/studio/assets/clone-BVy51j3M.js +1 -0
- package/dist/studio/assets/{cose-bilkent-S5V4N54A-BBwTMNFL.js → cose-bilkent-S5V4N54A-sRKlNOYM.js} +1 -1
- package/dist/studio/assets/{dagre-6UL2VRFP-BjSLIZIo.js → dagre-6UL2VRFP-_B7iBqja.js} +1 -1
- package/dist/studio/assets/{diagram-PSM6KHXK-D2gnzlsb.js → diagram-PSM6KHXK-B9huHO5_.js} +1 -1
- package/dist/studio/assets/{diagram-QEK2KX5R-CMigGtNf.js → diagram-QEK2KX5R-Z1hdHclc.js} +1 -1
- package/dist/studio/assets/{diagram-S2PKOQOG-DGsBcbGW.js → diagram-S2PKOQOG-HHCLRNNa.js} +1 -1
- package/dist/studio/assets/{erDiagram-Q2GNP2WA-DbegKR3G.js → erDiagram-Q2GNP2WA-Hpuoow8L.js} +1 -1
- package/dist/studio/assets/{flowDiagram-NV44I4VS-Dp8Pw2Wj.js → flowDiagram-NV44I4VS-C5l5sNY5.js} +1 -1
- package/dist/studio/assets/{ganttDiagram-JELNMOA3-BhpF9Gaf.js → ganttDiagram-JELNMOA3-BPt6zdfq.js} +1 -1
- package/dist/studio/assets/{gitGraphDiagram-V2S2FVAM-DLnpSbRP.js → gitGraphDiagram-V2S2FVAM-Bk-tICWY.js} +1 -1
- package/dist/studio/assets/{graph-CjocBAsl.js → graph-WM8Y6m48.js} +1 -1
- package/dist/studio/assets/{index-DT45VjXz.js → index-ChqmS6oM.js} +2 -2
- package/dist/studio/assets/{infoDiagram-HS3SLOUP-BRKALnQb.js → infoDiagram-HS3SLOUP-CD8BFlwg.js} +1 -1
- package/dist/studio/assets/{journeyDiagram-XKPGCS4Q-hAAow5Jv.js → journeyDiagram-XKPGCS4Q-BFqCHFja.js} +1 -1
- package/dist/studio/assets/{kanban-definition-3W4ZIXB7-pKazrLTO.js → kanban-definition-3W4ZIXB7-DjHo-B8G.js} +1 -1
- package/dist/studio/assets/{layout-QxBo3r_q.js → layout-DkBGam51.js} +1 -1
- package/dist/studio/assets/{linear-B9XrRzwF.js → linear-D0MP_1im.js} +1 -1
- package/dist/studio/assets/{mermaid.core-DBxi-BMu.js → mermaid.core-ja7cWubO.js} +4 -4
- package/dist/studio/assets/{mindmap-definition-VGOIOE7T-BtMHjUvJ.js → mindmap-definition-VGOIOE7T-B37HFYZb.js} +1 -1
- package/dist/studio/assets/{pieDiagram-ADFJNKIX-Bpz9F1Av.js → pieDiagram-ADFJNKIX-CJXN3q3o.js} +1 -1
- package/dist/studio/assets/{quadrantDiagram-AYHSOK5B-CqSKzYQJ.js → quadrantDiagram-AYHSOK5B-CFxFeuML.js} +1 -1
- package/dist/studio/assets/{requirementDiagram-UZGBJVZJ-DTWE3aty.js → requirementDiagram-UZGBJVZJ-CA0Fmoy_.js} +1 -1
- package/dist/studio/assets/{sankeyDiagram-TZEHDZUN-BCuEE_Vt.js → sankeyDiagram-TZEHDZUN-B3CovvaL.js} +1 -1
- package/dist/studio/assets/{sequenceDiagram-WL72ISMW-C0ZuURhF.js → sequenceDiagram-WL72ISMW-CuGMCJnC.js} +1 -1
- package/dist/studio/assets/{stateDiagram-FKZM4ZOC-C8UQSkhj.js → stateDiagram-FKZM4ZOC-hhl-S44t.js} +1 -1
- package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-HlW_YpPI.js +1 -0
- package/dist/studio/assets/{timeline-definition-IT6M3QCI-GXp3yL7Q.js → timeline-definition-IT6M3QCI-CRoP1Wio.js} +1 -1
- package/dist/studio/assets/{treemap-GDKQZRPO-DjcsiRVj.js → treemap-GDKQZRPO-C7_RGSEw.js} +1 -1
- package/dist/studio/assets/{xychartDiagram-PRI3JC2R-CpjYnaqR.js → xychartDiagram-PRI3JC2R-BQM7ZyVn.js} +1 -1
- package/dist/studio/index.html +1 -1
- package/dist/templates/templates/config.yaml +2 -2
- package/global/agents/sleepless.md +22 -9
- package/package.json +2 -1
- package/.claude/agents/pulsar.md +0 -212
- package/.claude/skills/pulse/SKILL.md +0 -84
- package/dist/daemon/pulse-state.d.ts.map +0 -1
- package/dist/daemon/pulse-state.js.map +0 -1
- package/dist/daemon/pulse.d.ts.map +0 -1
- package/dist/daemon/pulse.js.map +0 -1
- package/dist/studio/assets/channel-fRwIR1da.js +0 -1
- package/dist/studio/assets/classDiagram-2ON5EDUG-C3PW7gnd.js +0 -1
- package/dist/studio/assets/classDiagram-v2-WZHVMYZB-C3PW7gnd.js +0 -1
- package/dist/studio/assets/clone-BAcz-K3F.js +0 -1
- package/dist/studio/assets/stateDiagram-v2-4FDKWEC3-BcMsNBZX.js +0 -1
- package/global/agents/global-pulsar.md +0 -107
|
@@ -45,6 +45,19 @@ Use the Agent tool with `subagent_type: "developer"`. Include in the prompt:
|
|
|
45
45
|
|
|
46
46
|
The developer runs in an isolated worktree, implements via TDD, validates (test + lint + build), and returns its output. After it completes, verify the developer reported all three validations passing, then create the PR: `gh pr create`.
|
|
47
47
|
|
|
48
|
+
**CRITICAL — after developer completes, NEVER `cd` into the worktree directory.** The Bash tool preserves working directory between calls — one `cd` into a worktree pollutes every subsequent command. Instead, inspect the developer's work using remote refs from the main checkout:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Inspect commits and diff (from main checkout, no cd)
|
|
52
|
+
git log origin/worktree-agent-XXXX --oneline -5
|
|
53
|
+
git diff origin/main...origin/worktree-agent-XXXX --stat
|
|
54
|
+
|
|
55
|
+
# Create PR directly
|
|
56
|
+
gh pr create --head worktree-agent-XXXX ...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The developer already validated tests/lint/build. Manager's job is: confirm branch on remote → create PR → merge.
|
|
60
|
+
|
|
48
61
|
**Reviewer** (for M+ work, after PR is created):
|
|
49
62
|
Use the Agent tool with `subagent_type: "reviewer"`. Include in the prompt:
|
|
50
63
|
- The PR number to review
|
|
@@ -108,7 +108,7 @@ For each gap, create a GitHub issue labeled `ready`:
|
|
|
108
108
|
- After `/product` completes — check if design/solution need updates
|
|
109
109
|
- After `/design` completes — full integrity check
|
|
110
110
|
- After `/solution` completes — check design system alignment
|
|
111
|
-
- On
|
|
111
|
+
- On daemon job run — periodic integrity sweep
|
|
112
112
|
- Manually via manager
|
|
113
113
|
|
|
114
114
|
## Rules
|
package/.claude/agents/worker.md
CHANGED
|
@@ -1,357 +1,209 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
|
-
description: Per-repo
|
|
3
|
+
description: Per-repo wave-planning orchestrator. Reads entire backlog, maps dependencies into waves, fires developers in parallel (max 3 concurrent), cascades immediately when deps complete. Runs until backlog is empty or 60-min timeout.
|
|
4
4
|
model: sonnet
|
|
5
5
|
memory: user
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Worker —
|
|
8
|
+
# Worker — Wave-Planning Orchestrator
|
|
9
9
|
|
|
10
|
-
You are spawned by the global sleepless orchestrator to
|
|
11
|
-
|
|
10
|
+
You are spawned by the global sleepless orchestrator to drain this repo's ready backlog.
|
|
11
|
+
Read all ready issues, map dependencies into execution waves, fire developers in parallel,
|
|
12
|
+
and cascade immediately as issues complete. Keep going until the backlog is empty or you
|
|
13
|
+
hit the 60-minute safety timeout.
|
|
12
14
|
|
|
13
|
-
## Pre-flight
|
|
15
|
+
## Pre-flight
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
If the global dir path was not provided, check `../.claudius/HALT` (the parent dir convention
|
|
20
|
-
for repos managed from a sibling-level global orchestrator).
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
# Example (adapt path from prompt):
|
|
24
|
-
test -f ../.claudius/HALT && echo "HALTED" && exit 0 || true
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Startup: Recover Stale Claims
|
|
28
|
-
|
|
29
|
-
Check for issues labeled `in-progress` (with OR without the `claude` label) that have no open
|
|
30
|
-
PR — stale claims from a crashed prior run. Restore them:
|
|
17
|
+
**Global halt check** — the sleepless agent passes the global dir path in the prompt.
|
|
18
|
+
Check `<global-dir>/.claudius/HALT` (or `../.claudius/HALT` as fallback).
|
|
19
|
+
If it exists → exit `WORKER_HALTED`.
|
|
31
20
|
|
|
21
|
+
**Recover stale claims** — find issues labeled `in-progress` with no open PR. These are
|
|
22
|
+
stale claims from crashed prior runs. Restore them to `ready`:
|
|
32
23
|
```bash
|
|
33
24
|
gh issue list --label in-progress --state open --json number,title --limit 20
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
For each in-progress issue, check if an open PR references it:
|
|
37
|
-
```bash
|
|
25
|
+
# For each: check if an open PR references it
|
|
38
26
|
gh pr list --search "Closes #<N> in:body" --state open --json number --limit 1
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
If no open PR found → stale claim → restore to ready:
|
|
42
|
-
```bash
|
|
27
|
+
# If no PR → restore:
|
|
43
28
|
gh issue edit <N> --remove-label "in-progress,claude" --add-label "ready"
|
|
44
29
|
```
|
|
45
30
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Exit `WORKER_OK` immediately if any fail:
|
|
31
|
+
**Guard checks** — read `.claudius/config.yaml` for `activeHours`, `budgetCapUsd`, goals.
|
|
32
|
+
Check `job-runs.jsonl` for 3 consecutive failures. Exit `WORKER_OK` if any guard fails.
|
|
49
33
|
|
|
34
|
+
**Heartbeat** — periodically (every 10 min) update `active-builds.jsonl` in the global dir
|
|
35
|
+
with a `lastHeartbeat` timestamp so sleepless knows you're alive:
|
|
50
36
|
```bash
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
GLOBAL_DIR="<path-from-prompt>"
|
|
38
|
+
REPO_NAME="<this-repo>"
|
|
39
|
+
node -e "
|
|
40
|
+
const fs = require('fs');
|
|
41
|
+
const f = '$GLOBAL_DIR/.claudius/active-builds.jsonl';
|
|
42
|
+
if (!fs.existsSync(f)) process.exit(0);
|
|
43
|
+
const lines = fs.readFileSync(f,'utf8').split('\n').filter(Boolean);
|
|
44
|
+
const updated = lines.map(l => {
|
|
45
|
+
try { const e = JSON.parse(l); if (e.repo === '$REPO_NAME') e.lastHeartbeat = new Date().toISOString(); return JSON.stringify(e); }
|
|
46
|
+
catch { return l; }
|
|
47
|
+
});
|
|
48
|
+
fs.writeFileSync(f, updated.join('\n') + '\n');
|
|
49
|
+
" 2>/dev/null || true
|
|
54
50
|
```
|
|
55
51
|
|
|
56
|
-
- Outside `activeHours` (respect timezone in config) → exit `WORKER_OK`
|
|
57
|
-
- Last 3 job-runs all `success:false` → exit `WORKER_OK` (avoid compounding failures)
|
|
58
|
-
- Budget already > 80% of `budgetCapUsd` → exit `WORKER_OK`
|
|
59
|
-
|
|
60
52
|
## Step 1: Merge Open PRs
|
|
61
53
|
|
|
62
|
-
Before picking new work, merge any open
|
|
63
|
-
|
|
54
|
+
Before picking new work, merge any open PRs with passing CI:
|
|
64
55
|
```bash
|
|
65
56
|
gh pr list --json number,title,headRefName,statusCheckRollup --limit 20
|
|
66
57
|
bash .claude/scripts/merge-pr.sh <N>
|
|
67
58
|
gh issue close <issue-N> --comment "Closed by PR #<N>."
|
|
68
59
|
```
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
Send Slack thread reply after each merge (best-effort).
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
IN_FLIGHT=$(gh issue list --label in-progress --label claude --state open \
|
|
75
|
-
--json number --jq 'length' 2>/dev/null || echo "0")
|
|
76
|
-
MAX_SLOTS=3
|
|
77
|
-
OPEN_SLOTS=$(( MAX_SLOTS - IN_FLIGHT ))
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
If `OPEN_SLOTS <= 0` → no capacity, skip to Step 1 (merge/review only), then exit `WORKER_OK`.
|
|
63
|
+
## Step 2: Read the Entire Backlog
|
|
81
64
|
|
|
65
|
+
Fetch ALL ready issues — not just 3:
|
|
82
66
|
```bash
|
|
83
|
-
gh issue list --label ready --state open --json number,title,labels,body --limit
|
|
67
|
+
gh issue list --label ready --state open --json number,title,labels,body --limit 50
|
|
84
68
|
```
|
|
85
69
|
|
|
86
|
-
|
|
70
|
+
Filter out any issue carrying the `codex` label. For each remaining issue, also check:
|
|
71
|
+
- **Attempt count** — count `claudius:workpad` comments. If ≥ 3 attempts → mark `blocked`, skip.
|
|
72
|
+
- **Recent PR guard** — if a PR for this issue was created in the last 6 hours → skip.
|
|
87
73
|
|
|
88
|
-
|
|
74
|
+
Read each issue's full body. You need the body to understand dependencies.
|
|
89
75
|
|
|
90
|
-
|
|
91
|
-
configured `goals`. Prefer smaller scope.
|
|
76
|
+
## Step 3: Map Dependencies and Plan Waves
|
|
92
77
|
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
candidates
|
|
97
|
-
- **Recent PR guard** — any issue that already had a PR created in the last 6 hours is skipped,
|
|
98
|
-
even if the PR was closed. This prevents duplicate PRs from retry storms.
|
|
99
|
-
- **Cluster momentum** — issues in partially-complete clusters get +15 priority boost
|
|
100
|
-
- **Standard scoring** — label priorities, scope size, goal alignment
|
|
78
|
+
Build a dependency graph from the issue bodies. Look for patterns like:
|
|
79
|
+
- "Requires #N", "Blocked by #N", "Depends on #N", "After #N"
|
|
80
|
+
- GitHub's `blocked-by` relationships (via `gh api`)
|
|
101
81
|
|
|
102
|
-
**
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
--search "Closes #$CANDIDATE in:body" --state all --json number,createdAt,state \
|
|
107
|
-
--jq "[.[] | select((.createdAt | fromdateiso8601) > (now - 21600))] | length" 2>/dev/null)
|
|
108
|
-
if [ "${RECENT_PR:-0}" -gt "0" ]; then
|
|
109
|
-
echo "Skipping #$CANDIDATE — PR created in last 6 hours"
|
|
110
|
-
continue
|
|
111
|
-
fi
|
|
112
|
-
done
|
|
113
|
-
```
|
|
82
|
+
**Topologically sort** into execution waves:
|
|
83
|
+
- **Wave 1** — issues with no unmet dependencies (or whose deps are already closed)
|
|
84
|
+
- **Wave 2** — issues that depend only on Wave 1 issues
|
|
85
|
+
- **Wave N** — issues that depend only on issues in earlier waves
|
|
114
86
|
|
|
115
|
-
|
|
87
|
+
If an issue has a dependency on something not in the ready backlog and not closed,
|
|
88
|
+
it's externally blocked — skip it, optionally mark `blocked`.
|
|
116
89
|
|
|
117
|
-
|
|
118
|
-
MAX_ATTEMPTS=3
|
|
119
|
-
PRIOR_ATTEMPTS=$(gh api "repos/{owner}/{repo}/issues/<N>/comments" \
|
|
120
|
-
--jq '[.[] | select(.body | contains("claudius:workpad"))] | length' 2>/dev/null || echo "0")
|
|
121
|
-
if [ "${PRIOR_ATTEMPTS:-0}" -ge "$MAX_ATTEMPTS" ]; then
|
|
122
|
-
gh issue edit <N> --remove-label "ready" --add-label "blocked"
|
|
123
|
-
gh issue comment <N> --body "Claudius: exceeded ${MAX_ATTEMPTS} build attempts. Needs human review before retrying."
|
|
124
|
-
bash .claude/scripts/project-status.sh <N> "Blocked" "Blocked"
|
|
125
|
-
# skip this issue — continue to next candidate
|
|
126
|
-
fi
|
|
127
|
-
```
|
|
90
|
+
## Step 4: Execute Waves
|
|
128
91
|
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
gh issue edit <N> --add-label "in-progress,claude" --remove-label "ready"
|
|
132
|
-
gh issue view <N> # read full body + acceptance criteria
|
|
133
|
-
```
|
|
92
|
+
Process waves sequentially. Within each wave, fire developers in parallel (max 3 concurrent).
|
|
134
93
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
```
|
|
94
|
+
For each wave:
|
|
95
|
+
|
|
96
|
+
### 4a. Claim Issues
|
|
139
97
|
|
|
140
|
-
|
|
98
|
+
For each issue in the wave (up to 3 concurrent):
|
|
141
99
|
```bash
|
|
100
|
+
gh issue edit <N> --add-label "in-progress,claude" --remove-label "ready"
|
|
101
|
+
bash .claude/scripts/workpad-upsert.sh <N> "🔄 Claimed — wave <W>, attempt <A>"
|
|
142
102
|
bash .claude/scripts/project-status.sh <N> "In Progress" "Running"
|
|
143
103
|
```
|
|
144
104
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
**CRITICAL: One issue = one developer = one PR.** Never combine multiple issues into a single
|
|
148
|
-
developer agent or a single PR. Each issue gets its own isolated developer in its own worktree.
|
|
149
|
-
Violating this causes review failures, duplicate PRs, and retry storms.
|
|
150
|
-
|
|
151
|
-
Each developer runs in its own isolated worktree. Do NOT derive or provide branch names.
|
|
105
|
+
### 4b. Fire Developers
|
|
152
106
|
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
AGENT_COMMAND=$(bun -e "
|
|
156
|
-
import { parse } from 'yaml';
|
|
157
|
-
import { readFileSync } from 'fs';
|
|
158
|
-
const c = parse(readFileSync('.claudius/config.yaml', 'utf8'));
|
|
159
|
-
process.stdout.write(c.agent?.command ?? 'claude');
|
|
160
|
-
" 2>/dev/null || echo 'claude')
|
|
161
|
-
```
|
|
107
|
+
Read `agent.command` from `.claudius/config.yaml` (default: `claude`).
|
|
162
108
|
|
|
163
|
-
**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
109
|
+
Spawn **one developer per issue** using the `Agent` tool **concurrently** (all in one
|
|
110
|
+
tool call), using `subagent_type: "developer"`. Each developer gets:
|
|
111
|
+
- Full issue body and acceptance criteria
|
|
112
|
+
- Issue number for commit format (`type(scope): description (#N)`)
|
|
113
|
+
- Constraint: implement only what the issue asks, no scope creep
|
|
114
|
+
- Instruction: use your current branch (the worktree branch), commit, push with
|
|
115
|
+
`git push -u origin HEAD`, report branch name. Do NOT create a PR.
|
|
116
|
+
- Request: include a **handoff summary** (what was built, how to test, AC coverage)
|
|
167
117
|
|
|
168
|
-
**
|
|
169
|
-
Spawn via Bash: `codex -p --model <agent.model> <agent.flags> "<prompt>" &` — one per issue.
|
|
118
|
+
**CRITICAL: One issue = one developer = one PR.** Never combine issues.
|
|
170
119
|
|
|
171
|
-
|
|
172
|
-
- Full issue body and all acceptance criteria
|
|
173
|
-
- Issue number for commit message format (`type(scope): description (#N)`)
|
|
174
|
-
- Constraint: implement only what the issue asks, no scope creep
|
|
175
|
-
- Instruction: use your current branch (the worktree branch), do NOT create a new branch.
|
|
176
|
-
Implement, commit, push with `git push -u origin HEAD`, then report the branch name you
|
|
177
|
-
pushed. Do not create the PR (worker creates PRs).
|
|
178
|
-
- In your final output, include a structured **handoff summary** (what was built, how to test,
|
|
179
|
-
AC coverage) so the worker can post it to the PR and update the workpad.
|
|
120
|
+
### 4c. Process Completions Immediately
|
|
180
121
|
|
|
181
|
-
|
|
122
|
+
As each developer completes (don't wait for all in the wave):
|
|
182
123
|
|
|
183
|
-
**On
|
|
124
|
+
**On failure:** Restore labels, comment, continue with rest of wave.
|
|
184
125
|
```bash
|
|
185
126
|
gh issue edit <N> --remove-label "in-progress,claude" --add-label "ready"
|
|
186
127
|
gh issue comment <N> --body "Worker: developer failed. Restored to ready queue."
|
|
187
128
|
```
|
|
188
|
-
Remove it from the active set and continue with the rest.
|
|
189
|
-
|
|
190
|
-
## Step 4: Validate & Create PRs
|
|
191
|
-
|
|
192
|
-
For each successful developer result, **validate before creating the PR**.
|
|
193
|
-
|
|
194
|
-
**Pre-PR validation** — check the developer's branch in its worktree:
|
|
195
|
-
```bash
|
|
196
|
-
cd <worktree-path>
|
|
197
|
-
bun run lint 2>&1 | tail -5
|
|
198
|
-
bun run build 2>&1 | tail -5
|
|
199
|
-
```
|
|
200
|
-
If lint or build fails: re-spawn the developer with the errors and ask it to fix them.
|
|
201
|
-
Only create the PR once validation passes. Never create a PR with known lint/build failures.
|
|
202
129
|
|
|
203
|
-
|
|
204
|
-
gh pr create \
|
|
205
|
-
--head <branch-from-developer-output> \
|
|
206
|
-
--title "type(scope): description (#N)" \
|
|
207
|
-
--body "$(cat <<'EOF'
|
|
208
|
-
## Summary
|
|
209
|
-
- <bullet from developer output>
|
|
210
|
-
|
|
211
|
-
## Closes
|
|
212
|
-
Closes #N
|
|
213
|
-
|
|
214
|
-
## Test Plan
|
|
215
|
-
- [ ] <scenario>
|
|
216
|
-
EOF
|
|
217
|
-
)"
|
|
218
|
-
```
|
|
130
|
+
**On success:** Validate → PR → Review → Merge, then cascade.
|
|
219
131
|
|
|
220
|
-
|
|
221
|
-
|
|
132
|
+
1. **Validate** — check developer's branch in its worktree:
|
|
133
|
+
```bash
|
|
134
|
+
cd <worktree-path>
|
|
135
|
+
bun run lint 2>&1 | tail -5
|
|
136
|
+
bun run build 2>&1 | tail -5
|
|
137
|
+
```
|
|
138
|
+
If lint/build fails: re-spawn developer with errors to fix. Only proceed when clean.
|
|
222
139
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
```
|
|
140
|
+
2. **Create PR:**
|
|
141
|
+
```bash
|
|
142
|
+
gh pr create --head <branch> --title "type(scope): description (#N)" --body "..."
|
|
143
|
+
```
|
|
144
|
+
Post handoff comment (`<!-- claudius:handoff -->`).
|
|
145
|
+
Send Slack notification (best-effort).
|
|
146
|
+
Update board:
|
|
147
|
+
```bash
|
|
148
|
+
bash .claude/scripts/workpad-upsert.sh <N> "🔍 Under review — PR #<M>"
|
|
149
|
+
bash .claude/scripts/project-status.sh <N> "Under Review" "Review"
|
|
150
|
+
```
|
|
234
151
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
import { readFileSync } from 'fs';
|
|
240
|
-
const c = parse(readFileSync('.claudius/config.yaml', 'utf8'));
|
|
241
|
-
process.stdout.write(c.slack?.channel ?? '');
|
|
242
|
-
" 2>/dev/null)
|
|
243
|
-
if [ -n "$SLACK_CHANNEL" ]; then
|
|
244
|
-
PR_TITLE=$(gh pr view $PR_NUMBER --json title --jq '.title')
|
|
245
|
-
PR_URL=$(gh pr view $PR_NUMBER --json url --jq '.url')
|
|
246
|
-
THREAD_REF=$(bun .claude/scripts/slack.ts send \
|
|
247
|
-
--channel "$SLACK_CHANNEL" \
|
|
248
|
-
--text "🔍 *PR #$PR_NUMBER ready for review* — $PR_TITLE $PR_URL" | tail -1) \
|
|
249
|
-
&& printf '<!-- slack-thread: %s -->' "$THREAD_REF" | gh pr comment $PR_NUMBER --body-file - \
|
|
250
|
-
|| true
|
|
251
|
-
fi
|
|
252
|
-
```
|
|
152
|
+
3. **Review** — spawn reviewer (`subagent_type: "reviewer"`) with PR number and issue number.
|
|
153
|
+
- `approve` → merge
|
|
154
|
+
- `request-changes` → re-spawn developer once with feedback, then re-review. Still failing → `block`
|
|
155
|
+
- `block` → restore labels, comment with reason
|
|
253
156
|
|
|
254
|
-
**
|
|
255
|
-
```bash
|
|
256
|
-
bash .claude/scripts/
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
Spawn one reviewer agent per PR using the `Agent` tool **concurrently** (all in one message).
|
|
263
|
-
|
|
264
|
-
For each PR, use `subagent_type: "reviewer"`. Each reviewer prompt must include:
|
|
265
|
-
- PR number to review
|
|
266
|
-
- Issue number for AC verification
|
|
267
|
-
- Return structured verdict: `approve` / `request-changes` / `block`
|
|
268
|
-
|
|
269
|
-
Wait for all reviewer agents to complete.
|
|
157
|
+
4. **Merge:**
|
|
158
|
+
```bash
|
|
159
|
+
bash .claude/scripts/merge-pr.sh <PR-number>
|
|
160
|
+
gh issue close <N> --comment "Closed by PR #<M>."
|
|
161
|
+
bash .claude/scripts/workpad-upsert.sh <N> "✅ Merged — PR #<M>"
|
|
162
|
+
```
|
|
163
|
+
Send Slack thread reply (best-effort).
|
|
164
|
+
Log outcome to `.claudius/daemon-state.md` (appended by the scheduler).
|
|
270
165
|
|
|
271
|
-
**
|
|
166
|
+
5. **Cascade** — when an issue merges, check if it unblocks any issues in later waves.
|
|
167
|
+
If so, fire those developers immediately (respecting max 3 concurrent). Don't wait
|
|
168
|
+
for the rest of the current wave to finish.
|
|
272
169
|
|
|
273
|
-
|
|
274
|
-
(max 1 retry). After retry: push, update PR, re-spawn reviewer. If still `request-changes`
|
|
275
|
-
→ treat as `block`.
|
|
170
|
+
### 4d. Heartbeat
|
|
276
171
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
gh issue comment <N> --body "Worker: reviewer blocked. Reason: <reason>."
|
|
281
|
-
```
|
|
172
|
+
After processing each wave, update the heartbeat timestamp in `active-builds.jsonl`.
|
|
173
|
+
If total runtime exceeds 60 minutes, drain active work (let in-flight developers finish)
|
|
174
|
+
but don't start new issues. Exit after draining.
|
|
282
175
|
|
|
283
|
-
|
|
284
|
-
```bash
|
|
285
|
-
bash .claude/scripts/project-status.sh <N> "Blocked" "Blocked"
|
|
286
|
-
```
|
|
176
|
+
## Cleanup
|
|
287
177
|
|
|
288
|
-
|
|
178
|
+
After all waves are processed (or timeout reached):
|
|
289
179
|
|
|
290
|
-
For each approved PR:
|
|
291
|
-
```bash
|
|
292
|
-
bash .claude/scripts/merge-pr.sh <PR-number>
|
|
293
|
-
gh issue close <N> --comment "Closed by PR #<M>."
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
**Update workpad + close issue** (closing removes it from the board via project-sync):
|
|
297
|
-
```bash
|
|
298
|
-
bash .claude/scripts/workpad-upsert.sh <N> "✅ Merged — PR #<M>"
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
After each merge, reply in the PR's Slack thread (best-effort):
|
|
302
|
-
```bash
|
|
303
|
-
THREAD_REF=$(gh pr view $PR_NUMBER --json comments \
|
|
304
|
-
--jq '[.comments[].body | select(contains("slack-thread:"))] | first' \
|
|
305
|
-
| grep -oE '[A-Z][A-Z0-9]{8,}:[0-9]+\.[0-9]+')
|
|
306
|
-
if [ -n "$THREAD_REF" ] && [ "$THREAD_REF" != "null" ]; then
|
|
307
|
-
bun .claude/scripts/slack.ts reply \
|
|
308
|
-
--thread "$THREAD_REF" \
|
|
309
|
-
--text "✅ Merged PR #$PR_NUMBER" 2>/dev/null || true
|
|
310
|
-
fi
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
Append one line per merged issue to `.claude/memory/pulse.md` under `## Recent Build Outcomes`:
|
|
314
|
-
```
|
|
315
|
-
- 2026-03-03: built #N → PR#M merged (Xs)
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## Step 7: Cleanup
|
|
321
|
-
|
|
322
|
-
After all merges, remove stale agent sub-worktrees (best-effort):
|
|
323
180
|
```bash
|
|
181
|
+
# Remove stale worktrees
|
|
324
182
|
git worktree list --porcelain | grep '^worktree' | grep 'agent-' | awk '{print $2}' | while read p; do
|
|
325
|
-
git worktree remove --force "$p" 2>/dev/null
|
|
183
|
+
git worktree remove --force "$p" 2>/dev/null || true
|
|
326
184
|
done
|
|
327
|
-
```
|
|
328
185
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
REPO_NAME="<this-repo-name>" # the repo name sleepless used in the entry
|
|
186
|
+
# Remove active-builds entry
|
|
187
|
+
GLOBAL_DIR="<path-from-prompt>"
|
|
188
|
+
REPO_NAME="<this-repo>"
|
|
333
189
|
node -e "
|
|
334
190
|
const fs = require('fs');
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
try { return JSON.parse(l).repo !== '$REPO_NAME'; } catch { return true; }
|
|
341
|
-
});
|
|
342
|
-
fs.writeFileSync(file, kept.join('\n') + (kept.length ? '\n' : ''));
|
|
191
|
+
const f = '$GLOBAL_DIR/.claudius/active-builds.jsonl';
|
|
192
|
+
if (!fs.existsSync(f)) process.exit(0);
|
|
193
|
+
const lines = fs.readFileSync(f,'utf8').split('\n').filter(Boolean);
|
|
194
|
+
const kept = lines.filter(l => { try { return JSON.parse(l).repo !== '$REPO_NAME'; } catch { return true; } });
|
|
195
|
+
fs.writeFileSync(f, kept.join('\n') + (kept.length ? '\n' : ''));
|
|
343
196
|
" 2>/dev/null || true
|
|
344
197
|
```
|
|
345
198
|
|
|
346
|
-
Exit
|
|
347
|
-
|
|
348
|
-
---
|
|
199
|
+
Exit `WORKER_OK`.
|
|
349
200
|
|
|
350
201
|
## Headless Execution Notes
|
|
351
202
|
|
|
352
203
|
- Never use `EnterPlanMode`, `ExitPlanMode`, or `AskUserQuestion` — no human present
|
|
353
204
|
- Never provide branch names to developers — they run in isolated worktrees
|
|
354
|
-
- Skip any issue with the `codex` label —
|
|
205
|
+
- Skip any issue with the `codex` label — Codex territory
|
|
355
206
|
- Always restore both `in-progress` AND `claude` labels on failure/block
|
|
356
|
-
- Exit with `WORKER_OK` when the cycle completes (0 or up to OPEN_SLOTS issues processed)
|
|
357
207
|
- On unrecoverable error per issue: restore labels, comment, continue — never abort the whole run
|
|
208
|
+
- Max 3 concurrent developers at any time — this is a slot limit, not a batch size
|
|
209
|
+
- 60-minute safety timeout — drain active work, then exit
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 1. Ready issues exist → /build #N
|
|
7
7
|
* 2. No ready issues → check session-state.md Next Actions
|
|
8
8
|
* 3. No session actions → check open backlog (any open issues)
|
|
9
|
-
* 4. Empty backlog → Slack owner if configured, else suggest /
|
|
9
|
+
* 4. Empty backlog → Slack owner if configured, else suggest /backlog --ideate
|
|
10
10
|
* 5. Always exit 2 — never silently stop and never ask the user
|
|
11
11
|
*
|
|
12
12
|
* Exit codes:
|
|
@@ -27,7 +27,7 @@ interface Issue {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function getConsecutiveFailures(projectDir: string): number {
|
|
30
|
-
const statePath = resolve(projectDir, ".claudius/
|
|
30
|
+
const statePath = resolve(projectDir, ".claudius/daemon-state.md");
|
|
31
31
|
if (!existsSync(statePath)) return 0;
|
|
32
32
|
const content = readFileSync(statePath, "utf-8");
|
|
33
33
|
const match = content.match(/Consecutive failures:\s*(\d+)/);
|
|
@@ -170,7 +170,7 @@ async function main() {
|
|
|
170
170
|
);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
// 4. Backlog empty — Slack owner or suggest /
|
|
173
|
+
// 4. Backlog empty — Slack owner or suggest /backlog --ideate
|
|
174
174
|
const slackUserId = getSlackUserId(projectDir);
|
|
175
175
|
if (slackUserId) {
|
|
176
176
|
await sendSlackMessage(
|
|
@@ -180,7 +180,7 @@ async function main() {
|
|
|
180
180
|
block(
|
|
181
181
|
[
|
|
182
182
|
"Backlog is empty. Sent Slack message to owner for next direction.",
|
|
183
|
-
"Run /
|
|
183
|
+
"Run /backlog --ideate to check for background ideation or triage work.",
|
|
184
184
|
].join("\n"),
|
|
185
185
|
);
|
|
186
186
|
}
|
|
@@ -188,7 +188,7 @@ async function main() {
|
|
|
188
188
|
block(
|
|
189
189
|
[
|
|
190
190
|
"Backlog is empty. Options:",
|
|
191
|
-
" 1. Run /
|
|
191
|
+
" 1. Run /backlog --ideate — scan for ideation, memory gaps, or triage work",
|
|
192
192
|
" 2. Run /backlog — identify and create new issues from current goals",
|
|
193
193
|
" 3. If truly nothing to do, respond: 'All work complete. Backlog is empty.'",
|
|
194
194
|
].join("\n"),
|
|
@@ -52,17 +52,16 @@ Use claudius skills instead of doing things manually:
|
|
|
52
52
|
- After `/clear` or new session: read session-state.md, config.yaml goals, then resume.
|
|
53
53
|
- Don't ask "what should I do next?" — check goals and backlog, pick the highest priority.
|
|
54
54
|
|
|
55
|
-
##
|
|
55
|
+
## Daemon & Jobs
|
|
56
56
|
|
|
57
|
-
The
|
|
57
|
+
The daemon runs scheduled jobs from `.claudius/jobs/`. Worker agents handle autonomous builds.
|
|
58
58
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
- **`claudius
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
- On 3 consecutive failures, pause and escalate (`pulse.pauseOnFailure`).
|
|
59
|
+
- **`claudius daemon`** — preflight health dashboard
|
|
60
|
+
- **`claudius daemon start`** — start the scheduler daemon (runs cron jobs)
|
|
61
|
+
- **`claudius jobs`** — list all jobs with schedule and status
|
|
62
|
+
- **`claudius jobs run <name>`** — trigger a specific job immediately
|
|
63
|
+
|
|
64
|
+
Config: `daemon:` section in `.claudius/config.yaml` controls enabled, activeHours, budget, etc.
|
|
66
65
|
|
|
67
66
|
## What to Commit
|
|
68
67
|
|
|
@@ -87,8 +86,8 @@ Commit everything `claudius init` distributes — skills, rules, hooks, agents,
|
|
|
87
86
|
| Command | Purpose |
|
|
88
87
|
|---------|---------|
|
|
89
88
|
| `claudius init` | Initialize project for claudius |
|
|
90
|
-
| `claudius daemon` |
|
|
91
|
-
| `claudius
|
|
89
|
+
| `claudius daemon` | Preflight health dashboard |
|
|
90
|
+
| `claudius daemon start` | Start the scheduler daemon |
|
|
92
91
|
| `claudius status` | Show project status |
|
|
93
92
|
| `claudius jobs` | Manage background jobs |
|
|
94
93
|
| `claudius scope` | Classify issue scope (XS/S/M/L/XL) |
|
|
@@ -142,9 +142,7 @@ Comprehensive backlog health check across all open issues.
|
|
|
142
142
|
- Posts findings as comments on affected issues
|
|
143
143
|
- Outputs a health summary
|
|
144
144
|
|
|
145
|
-
**
|
|
146
|
-
1. Rewrite **Queue** — cluster ready issues by theme/dependency, note sequencing rationale
|
|
147
|
-
2. Append to **Grooming Log**: `### <date> — groom-backlog\n- <summary of changes and key findings>`
|
|
145
|
+
**After grooming, update `.claudius/session-state.md`** with a summary of changes and key findings.
|
|
148
146
|
|
|
149
147
|
#### `--check-stale`: Staleness Detection
|
|
150
148
|
|
|
@@ -193,7 +191,7 @@ The `ready` label is the contract between `/backlog` and `/build`. It means:
|
|
|
193
191
|
- Native GitHub relationships are wired (sub-issue of epic, blocked-by dependencies)
|
|
194
192
|
- A human approved the work item
|
|
195
193
|
|
|
196
|
-
`/build` only picks up `ready` items.
|
|
194
|
+
`/build` only picks up `ready` items. The daemon only runs `ready` items. This gate ensures autonomous agents execute pre-approved plans, not make design decisions on the fly.
|
|
197
195
|
|
|
198
196
|
## GitHub Relationship Script Reference
|
|
199
197
|
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Autonomous implementation — picks up `ready`-labeled work items and builds them.
|
|
5
5
|
Reads the work item, implements with TDD, creates PR, runs review gate, merges.
|
|
6
6
|
No planning or design decisions — those are settled upstream by /backlog.
|
|
7
|
-
Can be delegated to
|
|
7
|
+
Can be delegated to the daemon for autonomous execution.
|
|
8
8
|
Triggers on: "build this", "implement this issue", "/build", "start building",
|
|
9
9
|
"pick up the next task", "implement #N".
|
|
10
10
|
This is Stage 5 of the development lifecycle (/product → /solution → /design → /spec → /backlog → /build).
|
|
@@ -17,7 +17,7 @@ Pure executor. Picks up `ready`-labeled work items and builds them. No explorati
|
|
|
17
17
|
|
|
18
18
|
This is **Stage 5** of the development lifecycle (/product → /solution → /design → /spec → /backlog → /build). It reads work items from `/backlog` (Stage 4) and produces branches, PRs, and merged code.
|
|
19
19
|
|
|
20
|
-
Because `/build` makes no design decisions, it can be delegated to
|
|
20
|
+
Because `/build` makes no design decisions, it can be delegated to the daemon for autonomous execution.
|
|
21
21
|
|
|
22
22
|
## Usage
|
|
23
23
|
```
|