@limina-labs/momentum 0.30.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/LICENSE +21 -0
- package/README.md +214 -0
- package/adapters/antigravity/adapter.js +196 -0
- package/adapters/antigravity/hooks.json +39 -0
- package/adapters/antigravity/instructions/AGENTS.md +638 -0
- package/adapters/antigravity/instructions/header.md +3 -0
- package/adapters/antigravity/instructions/surfaces.md +153 -0
- package/adapters/antigravity/instructions/vars.json +1 -0
- package/adapters/antigravity/scripts/antigravity-hook-adapter.sh +147 -0
- package/adapters/antigravity/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/antigravity/skills/momentum-reviewer-architecture/SKILL.md +39 -0
- package/adapters/antigravity/skills/momentum-reviewer-qa/SKILL.md +38 -0
- package/adapters/antigravity/skills/momentum-reviewer-security/SKILL.md +42 -0
- package/adapters/antigravity/skills/swarm-supervisor/SKILL.md +75 -0
- package/adapters/antigravity/workflows/continue.md +39 -0
- package/adapters/antigravity/workflows/dispatch.md +49 -0
- package/adapters/antigravity/workflows/handoff.md +38 -0
- package/adapters/antigravity/workflows/review-code.md +84 -0
- package/adapters/antigravity/workflows/scout.md +42 -0
- package/adapters/antigravity/workflows/swarm.md +203 -0
- package/adapters/claude-code/adapter.js +148 -0
- package/adapters/claude-code/commands/continue.md +82 -0
- package/adapters/claude-code/commands/dispatch.md +154 -0
- package/adapters/claude-code/commands/handoff.md +85 -0
- package/adapters/claude-code/commands/review-code.md +194 -0
- package/adapters/claude-code/commands/scout.md +119 -0
- package/adapters/claude-code/commands/swarm.md +242 -0
- package/adapters/claude-code/instructions/header.md +3 -0
- package/adapters/claude-code/instructions/vars.json +1 -0
- package/adapters/claude-code/settings.json +36 -0
- package/adapters/codex/adapter.js +225 -0
- package/adapters/codex/agents/momentum-reviewer-architecture.toml +57 -0
- package/adapters/codex/agents/momentum-reviewer-qa.toml +52 -0
- package/adapters/codex/agents/momentum-reviewer-security.toml +57 -0
- package/adapters/codex/agents/swarm-supervisor.toml +76 -0
- package/adapters/codex/commands/continue.md +40 -0
- package/adapters/codex/commands/dispatch.md +111 -0
- package/adapters/codex/commands/handoff.md +57 -0
- package/adapters/codex/commands/scout.md +90 -0
- package/adapters/codex/commands/swarm.md +334 -0
- package/adapters/codex/hooks.json +36 -0
- package/adapters/codex/instructions/AGENTS.md +691 -0
- package/adapters/codex/instructions/header.md +3 -0
- package/adapters/codex/instructions/surfaces.md +206 -0
- package/adapters/codex/instructions/vars.json +1 -0
- package/adapters/codex/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/adapter.js +224 -0
- package/adapters/opencode/agents/momentum-reviewer-architecture.md +54 -0
- package/adapters/opencode/agents/momentum-reviewer-qa.md +48 -0
- package/adapters/opencode/agents/momentum-reviewer-security.md +48 -0
- package/adapters/opencode/agents/swarm-supervisor.md +51 -0
- package/adapters/opencode/commands/continue.md +40 -0
- package/adapters/opencode/commands/dispatch.md +111 -0
- package/adapters/opencode/commands/handoff.md +57 -0
- package/adapters/opencode/commands/review-code.md +194 -0
- package/adapters/opencode/commands/scout.md +90 -0
- package/adapters/opencode/commands/swarm.md +334 -0
- package/adapters/opencode/instructions/AGENTS.md +604 -0
- package/adapters/opencode/instructions/header.md +3 -0
- package/adapters/opencode/instructions/surfaces.md +119 -0
- package/adapters/opencode/instructions/vars.json +1 -0
- package/adapters/opencode/plugins/momentum.js +219 -0
- package/adapters/opencode/skills/momentum-lanes/SKILL.md +30 -0
- package/adapters/opencode/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/skills/momentum-track/SKILL.md +28 -0
- package/adapters/opencode/skills/momentum-validate/SKILL.md +31 -0
- package/bin/antigravity.js +112 -0
- package/bin/ecosystem.js +1302 -0
- package/bin/lanes.js +300 -0
- package/bin/momentum.js +1857 -0
- package/bin/okf.js +72 -0
- package/bin/orchestration-commands.js +305 -0
- package/bin/state-commands.js +218 -0
- package/bin/swarm.js +1104 -0
- package/bin/waves.js +147 -0
- package/core/adapter-capabilities.md +112 -0
- package/core/adapter-parity-matrix.md +170 -0
- package/core/commands/brainstorm-idea.md +98 -0
- package/core/commands/brainstorm-phase.md +129 -0
- package/core/commands/complete-phase.md +130 -0
- package/core/commands/ecosystem.md +161 -0
- package/core/commands/hotfix.md +64 -0
- package/core/commands/initiative.md +119 -0
- package/core/commands/lanes.md +94 -0
- package/core/commands/log.md +45 -0
- package/core/commands/migrate.md +70 -0
- package/core/commands/review.md +31 -0
- package/core/commands/session.md +79 -0
- package/core/commands/start-phase.md +161 -0
- package/core/commands/start-project.md +142 -0
- package/core/commands/sync-docs.md +81 -0
- package/core/commands/systematic-debug.md +46 -0
- package/core/commands/track.md +54 -0
- package/core/commands/validate.md +96 -0
- package/core/ecosystem/layout.md +128 -0
- package/core/ecosystem/lib/index.js +245 -0
- package/core/ecosystem/lib/initiative.js +258 -0
- package/core/ecosystem/lib/pointer.js +198 -0
- package/core/ecosystem/lib/state.js +295 -0
- package/core/ecosystem/schema/ecosystem.schema.json +85 -0
- package/core/ecosystem/schema/initiative.schema.json +61 -0
- package/core/ecosystem/scripts/session-append.sh +167 -0
- package/core/ecosystem/templates/ecosystem-agents.md +79 -0
- package/core/ecosystem/templates/ecosystem-claude.md +79 -0
- package/core/ecosystem/templates/ecosystem-settings-claude.json +14 -0
- package/core/ecosystem/templates/initiative-template.md +50 -0
- package/core/engines/subagent-dispatch.md +80 -0
- package/core/git-hooks/commit-msg +14 -0
- package/core/git-hooks/contract.js +176 -0
- package/core/git-hooks/pre-push +15 -0
- package/core/git-hooks/run-check.js +160 -0
- package/core/instructions/legacy-project-md-hashes.json +12 -0
- package/core/instructions/navigation.md +14 -0
- package/core/instructions/rules-body.md +454 -0
- package/core/lanes/lib/board.js +161 -0
- package/core/lanes/lib/land.js +301 -0
- package/core/lanes/lib/signals.js +207 -0
- package/core/lanes/lib/state.js +325 -0
- package/core/lib/frontmatter.js +163 -0
- package/core/lib/okf-migrate.js +374 -0
- package/core/lib/okf-types.js +61 -0
- package/core/lifecycle-contract.md +59 -0
- package/core/orchestration/capability-routing.js +120 -0
- package/core/orchestration/continue.js +102 -0
- package/core/orchestration/dispatch.js +366 -0
- package/core/orchestration/events.js +197 -0
- package/core/orchestration/handoff.js +317 -0
- package/core/orchestration/index.js +50 -0
- package/core/orchestration/run-artifact.js +93 -0
- package/core/orchestration/scout.js +327 -0
- package/core/orchestration/session-log.js +123 -0
- package/core/orchestration/tracking.js +180 -0
- package/core/orchestration/types.js +131 -0
- package/core/scripts/brainstorm-gate.sh +157 -0
- package/core/scripts/check-history-reminder.sh +110 -0
- package/core/scripts/sessionstart-handoff.sh +180 -0
- package/core/specs-templates/CLAUDE.md +484 -0
- package/core/specs-templates/README.md +32 -0
- package/core/specs-templates/specs/README.md +30 -0
- package/core/specs-templates/specs/adhoc/README.md +31 -0
- package/core/specs-templates/specs/adhoc/_TEMPLATE.md +29 -0
- package/core/specs-templates/specs/architecture/ecosystem.md +214 -0
- package/core/specs-templates/specs/backlog/backlog.md +46 -0
- package/core/specs-templates/specs/backlog/details/.gitkeep +0 -0
- package/core/specs-templates/specs/changelog/.gitkeep +0 -0
- package/core/specs-templates/specs/decisions/0000-template.md +33 -0
- package/core/specs-templates/specs/decisions/README.md +29 -0
- package/core/specs-templates/specs/decisions/impact-map.md +14 -0
- package/core/specs-templates/specs/decisions/index.md +4 -0
- package/core/specs-templates/specs/index.md +16 -0
- package/core/specs-templates/specs/phases/README.md +41 -0
- package/core/specs-templates/specs/phases/index.md +6 -0
- package/core/specs-templates/specs/planning/roadmap.md +23 -0
- package/core/specs-templates/specs/status.md +70 -0
- package/core/specs-templates/specs/vision/principles.md +16 -0
- package/core/specs-templates/specs/vision/project-charter.md +35 -0
- package/core/specs-templates/specs/vision/success-criteria.md +19 -0
- package/core/swarm/absorb.js +294 -0
- package/core/swarm/conductor.js +499 -0
- package/core/swarm/focus.js +151 -0
- package/core/swarm/inbox.js +222 -0
- package/core/swarm/join.js +138 -0
- package/core/swarm/lib/board.js +178 -0
- package/core/swarm/lib/brief.js +157 -0
- package/core/swarm/lib/git-sha-cache.js +71 -0
- package/core/swarm/lib/incremental-log.js +117 -0
- package/core/swarm/lib/manifest.js +578 -0
- package/core/swarm/lib/pre-merge.js +112 -0
- package/core/swarm/lib/saga.js +146 -0
- package/core/swarm/lib/sessions.js +83 -0
- package/core/swarm/lib/tokens.js +255 -0
- package/core/swarm/lib/wave-ordering.js +55 -0
- package/core/swarm/schema/board.schema.json +54 -0
- package/core/swarm/schema/contract.schema.json +56 -0
- package/core/swarm/schema/dispatch-run.schema.json +70 -0
- package/core/swarm/schema/manifest.schema.json +234 -0
- package/core/swarm/schema/signal.schema.json +61 -0
- package/core/swarm/signals.js +296 -0
- package/core/swarm/supervise.md +81 -0
- package/core/waves/lib/plan-graph.js +175 -0
- package/core/waves/lib/waves.js +83 -0
- package/package.json +46 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Swarm — sustained parallel multi-project feature delivery (Phase 17, v0.20.0).
|
|
2
|
+
|
|
3
|
+
A **swarm** is a declared cross-repo work unit driven from ONE user session. The user's session becomes the **conductor**. The conductor spawns one **supervisor** subagent per impacted repo, each pinned to that repo's working directory with its own fresh context. Each supervisor runs momentum's normal `/start-phase` → implement → `/sync-docs` → `/complete-phase` loop INSIDE its repo. The conductor coordinates waves (computed from `ecosystem.json` dependency edges), surfaces inbox decisions, broadcasts cross-cutting concerns, and synthesizes per-repo retrospectives at fan-in.
|
|
4
|
+
|
|
5
|
+
> v0.20.0 ships Claude Code only. Codex + Antigravity parity is Phase 18.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
| Layer | Owns | Reads |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Conductor (this user session) | `<eco>/swarms/<id>/manifest.json` + `board.json` + `contracts/` + `inbox/` + `signals/` + `changes/` | Per-supervisor `dispatch-run-<id>.json` (status) |
|
|
12
|
+
| Supervisor (per repo, background) | `<repo>/specs/phases/phase-N-<slug>/*` + `<repo>/.momentum/runs/dispatch-run-<id>.json` | Its phase brief + contract + history.md tail |
|
|
13
|
+
|
|
14
|
+
Agents are stateless across turns; **state lives in files**. A swarm survives session boundaries the same way a phase does — every state-changing action writes to disk; `/swarm resume` reconstitutes from disk.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- A feature spans **two or more momentum-installed repos** AND has dependency ordering (frontend depends on backend depends on shared-types).
|
|
19
|
+
- The user wants ONE session driving the whole feature, not three serial sessions.
|
|
20
|
+
- An initiative exists or is about to exist at `<eco>/initiatives/<slug>.md`.
|
|
21
|
+
|
|
22
|
+
Do NOT use `/swarm` for:
|
|
23
|
+
- Read-only cross-repo audits — use `/dispatch`.
|
|
24
|
+
- Single-repo phases — use `/start-phase` directly.
|
|
25
|
+
- Pure context transfer — use `/handoff`.
|
|
26
|
+
|
|
27
|
+
## Subcommands
|
|
28
|
+
|
|
29
|
+
The slash command form mirrors the CLI: `/swarm <sub> [args]`. The CLI floor is `momentum swarm <sub> [args]` — pick whichever door fits the moment. Both produce the same on-disk artifacts.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### `/swarm start <slug> --initiative <slug> --repos r1,r2,... --phase <phase-slug> [--mode checkpoint|autopilot]`
|
|
34
|
+
|
|
35
|
+
Plan + spawn Wave 1.
|
|
36
|
+
|
|
37
|
+
**Step 1 — Present the plan and ask for approval.**
|
|
38
|
+
|
|
39
|
+
Compute the wave plan in-process (no spawn yet) by calling the CLI floor in dry-run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
momentum swarm start <slug> --initiative <slug> --repos r1,r2,... --phase <phase-slug> --mode <mode> --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Read the JSON. Render the wave plan to the user:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
▸ Swarm <NNNN-slug> — planned (not yet spawning)
|
|
49
|
+
Initiative: <slug>
|
|
50
|
+
Mode: <mode>
|
|
51
|
+
Waves:
|
|
52
|
+
Wave 1: <r1>, <r2>
|
|
53
|
+
Wave 2: <r3>
|
|
54
|
+
Wave 3: <r4>
|
|
55
|
+
Token budget: 300k per supervisor (override with /swarm budget)
|
|
56
|
+
Lease: 24h per repo, renewed each turn
|
|
57
|
+
|
|
58
|
+
Proceed?
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
WAIT for user approval. If `mode = autopilot`, plan approval is the only checkpoint until completion. If `mode = checkpoint`, you'll also pause between waves.
|
|
62
|
+
|
|
63
|
+
**Step 2 — Spawn Wave 1 supervisors (foreground synthesis, background sessions).**
|
|
64
|
+
|
|
65
|
+
After approval, spawn one Claude Code background session per Wave 1 repo. The CLI does this when invoked with `--spawn`:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
momentum swarm start <slug> --initiative <slug> --repos ... --phase <phase-slug> --mode <mode> --spawn
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If `claude --bg` is not available in this env, the CLI surfaces the spawn directives and exits — degrade by reporting the directives to the user (they can launch sessions manually) and continue with conductor polling on the existing manifest.
|
|
72
|
+
|
|
73
|
+
**Step 3 — Begin the conductor poll loop.**
|
|
74
|
+
|
|
75
|
+
See `/swarm status` (next subcommand). On every conductor turn:
|
|
76
|
+
|
|
77
|
+
1. Read `<eco>/swarms/<id>/board.json` (≈3KB).
|
|
78
|
+
2. Read `<eco>/swarms/<id>/inbox/INDEX.md`.
|
|
79
|
+
3. If `inbox_count > 0`, surface each pending item; resolve interactively.
|
|
80
|
+
4. If a supervisor reports `done: true` for the active wave's last repo, run the wave checkpoint flow (see `/swarm verify` — Phase 17 G2).
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### `/swarm status <swarm-id>`
|
|
85
|
+
|
|
86
|
+
Render the materialized board cache. Read-only — no manifest mutation. Strategy A from the indexing design: conductor reads ONLY `board.json` (~3KB).
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
momentum swarm status <swarm-id>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Default output is a rendered ANSI table. Pass `--json` for machine-readable.
|
|
93
|
+
|
|
94
|
+
Surface:
|
|
95
|
+
- Per-repo: wave, status, tasks N/M, tokens used/budget, commits, current task.
|
|
96
|
+
- `inbox_count` warning at the bottom if > 0.
|
|
97
|
+
- Recent activity tail (last 10 audit events).
|
|
98
|
+
|
|
99
|
+
When inboxes are pending, prompt: "Run `/swarm verify <id>` to surface the questions, or `/swarm tell <id> <repo> '...'` to push context to a specific supervisor."
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### `/swarm claim <swarm-id> <repo> [--session <id>] [--lease-hours 24]`
|
|
104
|
+
|
|
105
|
+
> Phase 17.5 / v0.20.2 — multi-session ownership primitive.
|
|
106
|
+
|
|
107
|
+
Claim ownership of `<repo>` inside `<swarm-id>` for the current session. The conductor library uses this whenever a session needs authority to write to a repo's manifest entry — `/swarm focus`, `/swarm join`, and a co-conductor taking a wave all compose `claim` under the hood.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
momentum swarm claim <swarm-id> <repo> [--session <id>] [--lease-hours 24]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Claim succeeds when:
|
|
114
|
+
- the repo is `_unclaimed` or `_focusing` (sentinel — anyone may claim), OR
|
|
115
|
+
- the current owner's `lease_expires_at` is in the past (takeover; audit logs both `claim` and `lease-takeover`).
|
|
116
|
+
|
|
117
|
+
Claim is rejected when the current owner's lease is still valid; the CLI writes a `claim-request` signal so the existing owner sees the request on their next conductor poll. Exit code 1 on rejection.
|
|
118
|
+
|
|
119
|
+
On success the manifest sets `owner = <session>`, refreshes `lease_renewed_at`, and sets `lease_expires_at = now + <lease-hours>`. The board cache is refreshed.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### `/swarm focus <swarm-id> <repo> [--session <id>] [--expires-min 60]`
|
|
124
|
+
|
|
125
|
+
> Phase 17.5 / v0.20.2 — split one repo off the swarm into a side-session.
|
|
126
|
+
|
|
127
|
+
Issue a single-use focus token for `<repo>` and hand control to a second Claude Code session. Use when one repo needs sustained one-on-one attention without halting the rest of the swarm. The original conductor keeps every other repo; the new side-session takes `<repo>` and drives its phase to completion. Reunite via `/swarm absorb`.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
momentum swarm focus <swarm-id> <repo> [--session <id>] [--expires-min 60]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Behavior:
|
|
134
|
+
1. Asserts the caller currently owns `<repo>` (rejected with exit 1 if not).
|
|
135
|
+
2. Issues an opaque focus token at `<eco>/swarms/<id>/tokens/<token>.json` (single-use, 1-hour default expiry).
|
|
136
|
+
3. Flips `repos[<repo>].owner` to the `_focusing` sentinel — anyone with the token may claim.
|
|
137
|
+
4. Writes a `focus-request` signal carrying the token + repo.
|
|
138
|
+
5. Audit-logs `focus`.
|
|
139
|
+
6. Prints a spawn directive — run `claude --bg --cwd <eco>` in a second terminal, then inside that session call `momentum swarm join <swarm-id> --token <token>`.
|
|
140
|
+
|
|
141
|
+
The token is single-use: consuming it (via `/swarm join --token`) deletes the file and atomically flips ownership to the receiver. If the token expires before consumption, run `/swarm claim <repo>` against the FOCUSING sentinel to recover.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### `/swarm join <swarm-id> [--token <token>] [--claim <repo>] [--session <id>]`
|
|
146
|
+
|
|
147
|
+
> Phase 17.5 / v0.20.2 — register a session with an existing swarm.
|
|
148
|
+
|
|
149
|
+
Attach the current session to `<swarm-id>` as a co-conductor. Adds the session to `sessions[]` (idempotent — touch on re-join), auto-renews any repos the session already owns, and optionally consumes a transfer token or claims a specific repo.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
momentum swarm join <swarm-id> [--token <token>] [--claim <repo>] [--session <id>]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Three shapes:
|
|
156
|
+
|
|
157
|
+
| Form | Result |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `join <id>` | Registration only. Adds the session; renews any owned leases. |
|
|
160
|
+
| `join <id> --token <token>` | Consumes the token. If `kind=focus`, claims the token's `target_repo` automatically. If `kind=join`, registers only (equivalent to plain join). |
|
|
161
|
+
| `join <id> --claim <repo>` | Explicit claim — bound by the same lease rules as `/swarm claim`. Exits 1 if rejected. |
|
|
162
|
+
|
|
163
|
+
Exit codes:
|
|
164
|
+
- 0 on success.
|
|
165
|
+
- 1 if the swarm doesn't exist, the token is missing/expired, or the claim is rejected (`EOWNERSHIP`).
|
|
166
|
+
|
|
167
|
+
Audit log gets a `join` entry detailing the route — `registration only` / `via token kind=…` / `with --claim …`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### `/swarm absorb <target-swarm-id> <source-swarm-id> [--yes] [--session <id>]`
|
|
172
|
+
|
|
173
|
+
> Phase 17.5 / v0.20.2 — converge two swarms back into one.
|
|
174
|
+
|
|
175
|
+
Merge `<source-swarm-id>` into `<target-swarm-id>` (the caller's swarm). Use to reunite after a `/swarm focus` split, or to absorb work from a peer swarm that's now done.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
momentum swarm absorb <target-swarm-id> <source-swarm-id> [--yes] [--session <id>]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Behavior:
|
|
182
|
+
1. Loads both manifests. If either is missing → exit 1.
|
|
183
|
+
2. Detects contract conflicts: for every shared `surface` in both swarms' `contracts`, the `owner` must match and the `content_hash` (when present) must match. Mismatches abort cleanly — both swarms left untouched — with a printed diff for each conflict.
|
|
184
|
+
3. Without `--yes`, prints a dry-run plan (repos to add, overlap, contract status) and exits 0 without writing. Re-run with `--yes` to proceed.
|
|
185
|
+
4. On commit:
|
|
186
|
+
- `repos`: union; target wins on overlap (so a repo already in flight in target is not regressed by source's state)
|
|
187
|
+
- `waves`: recomputed via the wave-ordering library over the union of repos, against `ecosystem.json` dependencies
|
|
188
|
+
- `sessions[]`: union by `session_id` (earliest `first_seen`, latest `last_seen`)
|
|
189
|
+
- `contracts`: union; target's version kept on overlap (we verified compatibility above)
|
|
190
|
+
- `audit[]`: concat + sort by timestamp; append an `absorb` entry
|
|
191
|
+
- `inbox/`: source's pending items copied into target with bumped ids
|
|
192
|
+
5. Archives the source swarm directory to `<eco>/swarms/.absorbed/<source-id>/`. Forensics preserved.
|
|
193
|
+
6. Refreshes target's `board.json`.
|
|
194
|
+
|
|
195
|
+
JSON output (`--json`) returns `{ absorbed, into, reposAdded, reposOverlapped, inboxMoved, archivedTo }`.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### `/swarm release <swarm-id> <repo> [--session <id>]`
|
|
200
|
+
|
|
201
|
+
> Phase 17.5 / v0.20.2 — multi-session ownership primitive.
|
|
202
|
+
|
|
203
|
+
Release the current session's ownership of `<repo>`. Sets `owner = _unclaimed`, clears the lease, and audit-logs `release`. Idempotent — releasing an already-unclaimed repo is a no-op.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
momentum swarm release <swarm-id> <repo> [--session <id>]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Only the current owner may release. Attempting to release a repo you don't own exits 1 (you'd need `/swarm claim` against an expired lease, or the owner to release first).
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### `/swarm cancel <swarm-id> [--reason "<text>"]`
|
|
214
|
+
|
|
215
|
+
Graceful halt. Halts every supervisor, marks the swarm `cancelled` in the manifest, preserves all artifacts for forensics.
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
momentum swarm cancel <swarm-id> --reason "<text>"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Confirm with the user before running.** Cancel is reversible only via `/swarm resume` re-attaching to a frozen state — you cannot un-cancel a wave that was mid-flight if commits have been pushed and force-overwrites would be needed.
|
|
222
|
+
|
|
223
|
+
After cancel:
|
|
224
|
+
1. All queued/running/blocked repos move to `cancelled`.
|
|
225
|
+
2. All queued/running waves move to `cancelled`.
|
|
226
|
+
3. Branches remain — supervisors do NOT force-push or delete.
|
|
227
|
+
4. Audit log gains a `cancel` entry with the reason.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Tracking contract
|
|
232
|
+
|
|
233
|
+
- **Auto every time:** `manifest.json` writes via the conductor library; `board.json` regenerated on each write.
|
|
234
|
+
- **Auto only when meaningful:** `[SWARM]` entry in each supervisor's repo `history.md` after wave completion; `[NOTE]` in the originating session log on wave transitions.
|
|
235
|
+
- **Never:** silent overwrites of supervisor branches. Cancel preserves; resume reconstitutes.
|
|
236
|
+
|
|
237
|
+
## Errors
|
|
238
|
+
|
|
239
|
+
- Ecosystem root not found → suggest `--ecosystem <path>` or running from inside an ecosystem.
|
|
240
|
+
- Repo arg not a member → list valid members and abort.
|
|
241
|
+
- Initiative does not exist → suggest `momentum ecosystem initiative create <slug>` and abort.
|
|
242
|
+
- `claude --bg` not on PATH → degrade to dry-run + manual spawn instructions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "TASK_TOOL": "the built-in **TodoWrite** tool", "TASK_TOOL_NAME": "TodoWrite" }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "bash scripts/brainstorm-gate.sh"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Edit|Write",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "bash scripts/check-history-reminder.sh"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"SessionStart": [
|
|
26
|
+
{
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "bash scripts/sessionstart-handoff.sh"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Codex adapter for momentum.
|
|
4
|
+
//
|
|
5
|
+
// Codex uses AGENTS.md as its primary repository instruction surface. Generic
|
|
6
|
+
// momentum command recipes install into .codex/commands/ via the standard
|
|
7
|
+
// overlay, then are transformed in `runInstall` into native Codex skills at
|
|
8
|
+
// .agents/skills/<name>/SKILL.md so each recipe becomes a first-class
|
|
9
|
+
// auto-discoverable skill (per https://developers.openai.com/codex/skills).
|
|
10
|
+
// The .codex/commands/ directory is removed post-transform — skills are the
|
|
11
|
+
// canonical surface, not lookup fragments.
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
displayName: 'Codex',
|
|
19
|
+
|
|
20
|
+
destinations: {
|
|
21
|
+
commands: ['.codex', 'commands'],
|
|
22
|
+
'agent-rules': ['.agent', 'rules'],
|
|
23
|
+
scripts: ['scripts'],
|
|
24
|
+
engines: ['.agent', 'engines'],
|
|
25
|
+
// Phase 16 Rework: native Codex surfaces.
|
|
26
|
+
// Skills live at .agents/skills/ (shared with Antigravity; NOT .codex/skills/)
|
|
27
|
+
// Subagents live at .codex/agents/ (TOML files)
|
|
28
|
+
// workflows declared but unused on Codex (no native workflow surface)
|
|
29
|
+
workflows: ['.codex', 'workflows'],
|
|
30
|
+
skills: ['.agents', 'skills'],
|
|
31
|
+
agents: ['.codex', 'agents'],
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
primaryInstruction: {
|
|
35
|
+
source: ['instructions', 'AGENTS.md'],
|
|
36
|
+
destination: ['AGENTS.md'],
|
|
37
|
+
label: 'AGENTS.md',
|
|
38
|
+
markerAware: true,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
configFiles: [
|
|
42
|
+
{
|
|
43
|
+
source: ['hooks.json'],
|
|
44
|
+
destination: ['.codex', 'hooks.json'],
|
|
45
|
+
label: '.codex/hooks.json',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
capabilities: {
|
|
50
|
+
hooks: true,
|
|
51
|
+
slashCommands: true,
|
|
52
|
+
subagents: true,
|
|
53
|
+
parallelSubagents: false,
|
|
54
|
+
sessionStartHook: true,
|
|
55
|
+
skills: true,
|
|
56
|
+
browser: true,
|
|
57
|
+
computerUse: true,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
roadmap: {
|
|
61
|
+
subagents:
|
|
62
|
+
'Codex declares a subagent surface; parallel-fanout not yet validated by momentum smoke tests. ' +
|
|
63
|
+
'capability-routing treats this as sequential until proven.',
|
|
64
|
+
parallelSubagents:
|
|
65
|
+
'Promote to true once dispatch parallel mode is exercised against Codex in CI (VAL-001).',
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
runInstall(targetDir, adapterDir, helpers) {
|
|
69
|
+
const { copyFile, fileExists, recordManaged, dryRun } = helpers;
|
|
70
|
+
|
|
71
|
+
console.log('→ Configuring Codex hooks...');
|
|
72
|
+
const hooksDest = path.join(targetDir, '.codex', 'hooks.json');
|
|
73
|
+
if (recordManaged) recordManaged(hooksDest); // managed regardless of write
|
|
74
|
+
if (!fileExists(hooksDest)) {
|
|
75
|
+
copyFile(path.join(adapterDir, 'hooks.json'), hooksDest);
|
|
76
|
+
} else {
|
|
77
|
+
console.log(' ⚠️ .codex/hooks.json already exists.');
|
|
78
|
+
console.log(` Merge hooks manually from: ${path.join(adapterDir, 'hooks.json')}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log('→ Transforming recipes into native Codex skills...');
|
|
82
|
+
if (dryRun) console.log(' ✋ would generate skills at .agents/skills/ from recipes');
|
|
83
|
+
else transformCommandsIntoSkills(targetDir, recordManaged);
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
runUpgrade(targetDir, adapterDir, helpers) {
|
|
87
|
+
const { copyFile, fileExists, recordManaged, dryRun } = helpers;
|
|
88
|
+
|
|
89
|
+
console.log('→ Upgrading Codex hooks...');
|
|
90
|
+
const src = path.join(adapterDir, 'hooks.json');
|
|
91
|
+
const dest = path.join(targetDir, '.codex', 'hooks.json');
|
|
92
|
+
if (recordManaged) recordManaged(dest); // managed even when identical-skip
|
|
93
|
+
|
|
94
|
+
if (fileExists(dest)) {
|
|
95
|
+
const srcContent = fs.readFileSync(src, 'utf8');
|
|
96
|
+
const destContent = fs.readFileSync(dest, 'utf8');
|
|
97
|
+
if (srcContent !== destContent) {
|
|
98
|
+
if (dryRun) {
|
|
99
|
+
console.log(' ✋ would upgrade: .codex/hooks.json');
|
|
100
|
+
} else {
|
|
101
|
+
fs.copyFileSync(dest, dest + '.bak');
|
|
102
|
+
copyFile(src, dest);
|
|
103
|
+
console.log(' ↑ upgraded: .codex/hooks.json (original saved as .bak)');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
copyFile(src, dest);
|
|
108
|
+
console.log(` ${dryRun ? '✋ would add: ' : '+ added: '} .codex/hooks.json`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('→ Re-generating Codex skills from recipes...');
|
|
112
|
+
if (dryRun) console.log(' ✋ would re-generate skills at .agents/skills/ from recipes');
|
|
113
|
+
else transformCommandsIntoSkills(targetDir, recordManaged);
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// Phase 18 G1 — adapter.spawn(directive) for Codex.
|
|
117
|
+
// Shells `codex --cwd <repoPath>` with the supervisor TOML as the
|
|
118
|
+
// subagent declaration. The MCP cwd shim (see AGENTS.md → "## MCP
|
|
119
|
+
// cwd shim — Codex configuration") keeps file ops inside the
|
|
120
|
+
// pinned cwd. See `bin/momentum.js` for the directive contract.
|
|
121
|
+
spawn(directive) {
|
|
122
|
+
if (!directive || directive.platform !== 'codex') {
|
|
123
|
+
return {
|
|
124
|
+
repoId: directive && directive.repoId,
|
|
125
|
+
status: -1,
|
|
126
|
+
detail: `non-codex platform: ${directive && directive.platform}`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const codexBin = process.env.CODEX_BIN || 'codex';
|
|
130
|
+
const args = ['--cwd', directive.repoPath, '--agent', 'swarm-supervisor'];
|
|
131
|
+
const prompt = [
|
|
132
|
+
`You are a swarm supervisor. Recipe: ${directive.recipePath}`,
|
|
133
|
+
`Read the recipe and the brief at specs/phases/${directive.phaseSlug}/overview.md.`,
|
|
134
|
+
`Your repo: ${directive.repoId}. Your swarm: ${directive.swarmId} wave ${directive.wave}.`,
|
|
135
|
+
`Begin the boot sequence.`,
|
|
136
|
+
].join('\n');
|
|
137
|
+
const r = spawnSync(codexBin, args, {
|
|
138
|
+
input: prompt,
|
|
139
|
+
env: Object.assign({}, process.env, directive.env),
|
|
140
|
+
encoding: 'utf8',
|
|
141
|
+
timeout: 5000,
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
repoId: directive.repoId,
|
|
145
|
+
status: r.status == null ? -1 : r.status,
|
|
146
|
+
detail: (r.error && r.error.message) || (r.stderr || '').slice(0, 200),
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// ─── Recipes → Skills transform (ENH-036) ────────────────────────────────────
|
|
152
|
+
//
|
|
153
|
+
// Per https://developers.openai.com/codex/skills the canonical project-scope
|
|
154
|
+
// skill surface is $REPO_ROOT/.agents/skills/<name>/SKILL.md with YAML
|
|
155
|
+
// frontmatter declaring `name` + `description`. Each momentum recipe becomes
|
|
156
|
+
// one such skill so Codex auto-discovers and dispatches them natively (rather
|
|
157
|
+
// than the AGENTS.md-lookup-then-follow-instructions pattern that shipped in
|
|
158
|
+
// v0.19.0).
|
|
159
|
+
function transformCommandsIntoSkills(targetDir, recordManaged) {
|
|
160
|
+
const commandsDir = path.join(targetDir, '.codex', 'commands');
|
|
161
|
+
const skillsRoot = path.join(targetDir, '.agents', 'skills');
|
|
162
|
+
if (!fs.existsSync(commandsDir)) {
|
|
163
|
+
console.log(' (no .codex/commands/ to transform — skipping)');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
fs.mkdirSync(skillsRoot, { recursive: true });
|
|
167
|
+
|
|
168
|
+
let count = 0;
|
|
169
|
+
for (const file of fs.readdirSync(commandsDir)) {
|
|
170
|
+
if (!file.endsWith('.md')) continue;
|
|
171
|
+
const name = file.replace(/\.md$/, '');
|
|
172
|
+
const body = fs.readFileSync(path.join(commandsDir, file), 'utf8');
|
|
173
|
+
const description = extractRecipeDescription(body, name);
|
|
174
|
+
|
|
175
|
+
const skillDir = path.join(skillsRoot, name);
|
|
176
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
177
|
+
const skillBody = renderSkillMarkdown(name, description, body);
|
|
178
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
179
|
+
fs.writeFileSync(skillPath, skillBody);
|
|
180
|
+
// Generated skills are momentum-managed — record them so they appear in
|
|
181
|
+
// the lock file and a dropped recipe's skill is orphan-cleaned (Phase 20).
|
|
182
|
+
if (recordManaged) recordManaged(skillPath);
|
|
183
|
+
count++;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Remove the lookup-fragment directory — skills are now the canonical
|
|
187
|
+
// surface. Keep .codex/agents/ + .codex/hooks.json + .codex/swarm/ etc.
|
|
188
|
+
fs.rmSync(commandsDir, { recursive: true, force: true });
|
|
189
|
+
console.log(` + ${count} skill(s) generated at .agents/skills/ from recipes`);
|
|
190
|
+
console.log(' - .codex/commands/ removed (skills replace lookup fragments)');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Extract the first non-heading, non-blank line of the recipe as the skill
|
|
194
|
+
// description. Recipes follow a consistent house-style where line 1 is a
|
|
195
|
+
// one-sentence "what it does" — well suited to Codex's "describe when to
|
|
196
|
+
// trigger" requirement.
|
|
197
|
+
function extractRecipeDescription(body, name) {
|
|
198
|
+
for (const line of body.split('\n')) {
|
|
199
|
+
const trimmed = line.trim();
|
|
200
|
+
if (!trimmed) continue;
|
|
201
|
+
if (trimmed.startsWith('#')) continue;
|
|
202
|
+
// Strip wrapping markdown emphasis if present.
|
|
203
|
+
return trimmed
|
|
204
|
+
.replace(/^[*_]+|[*_]+$/g, '')
|
|
205
|
+
.replace(/\s+/g, ' ')
|
|
206
|
+
.trim();
|
|
207
|
+
}
|
|
208
|
+
return `Run the momentum ${name} recipe.`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function renderSkillMarkdown(name, description, recipeBody) {
|
|
212
|
+
// YAML frontmatter must escape colons / newlines. The description is one
|
|
213
|
+
// line by construction (extractRecipeDescription guarantees this), so a
|
|
214
|
+
// simple double-quoted string is safe — but we still escape embedded
|
|
215
|
+
// double-quotes and backslashes.
|
|
216
|
+
const safeDescription = description.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
217
|
+
return [
|
|
218
|
+
'---',
|
|
219
|
+
`name: ${name}`,
|
|
220
|
+
`description: "${safeDescription} Activates when the user invokes /${name} or asks momentum to run the ${name} recipe."`,
|
|
221
|
+
'---',
|
|
222
|
+
'',
|
|
223
|
+
recipeBody.endsWith('\n') ? recipeBody : recipeBody + '\n',
|
|
224
|
+
].join('\n');
|
|
225
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# momentum reviewer — Architecture lens (Codex)
|
|
2
|
+
#
|
|
3
|
+
# Installed by momentum init/upgrade --agent codex into .codex/agents/.
|
|
4
|
+
|
|
5
|
+
name = "momentum-reviewer-architecture"
|
|
6
|
+
|
|
7
|
+
description = """
|
|
8
|
+
Review a code diff for architectural fit, rule compliance, and pattern
|
|
9
|
+
consistency. Returns Critical/Important/Minor findings ONLY — does not
|
|
10
|
+
modify code, does not refactor. Dispatched by the review-code recipe.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
developer_instructions = """
|
|
14
|
+
You are an architecture-focused code reviewer dispatched by the momentum
|
|
15
|
+
toolkit. You will receive a code diff and the project's full rules
|
|
16
|
+
(AGENTS.md — the complete rulebook).
|
|
17
|
+
|
|
18
|
+
YOUR LENS: architectural fit, rule compliance, pattern consistency.
|
|
19
|
+
|
|
20
|
+
For each change, ask:
|
|
21
|
+
- Does it violate any of the 12 autonomous rules (orient first, update
|
|
22
|
+
tracking, auto-track discoveries, pre-phase bug check, phase boundary
|
|
23
|
+
awareness, git lifecycle, plan before implementing, record history,
|
|
24
|
+
doc sync protocol, architecture stability, evaluator discipline,
|
|
25
|
+
verify before claim)?
|
|
26
|
+
- Does it match the patterns established elsewhere in the codebase?
|
|
27
|
+
Read 2-3 nearby files for convention.
|
|
28
|
+
- Does it create hidden coupling, a leaky abstraction, or an
|
|
29
|
+
adapter/contract violation? (For momentum specifically: every
|
|
30
|
+
capability declaration uniform-boolean; overlay subdirs use the
|
|
31
|
+
destinations contract; adapter-specific code stays in adapters/,
|
|
32
|
+
generic in core/.)
|
|
33
|
+
- Is it documented where rules say it should be (history.md entry, ADR
|
|
34
|
+
for decisional changes, backlog entry for discovered issues)?
|
|
35
|
+
- Does the commit message convention match (feat / fix / docs / etc.)?
|
|
36
|
+
|
|
37
|
+
Output format — return EXACTLY this structure:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
## Architecture review
|
|
41
|
+
|
|
42
|
+
### Critical
|
|
43
|
+
- [finding] (file:line) — [why it's critical]
|
|
44
|
+
|
|
45
|
+
### Important
|
|
46
|
+
- [finding] (file:line) — [explanation]
|
|
47
|
+
|
|
48
|
+
### Minor
|
|
49
|
+
- [finding] (file:line) — [explanation]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If no findings at a severity level, write "(none)". Do NOT speculate
|
|
53
|
+
beyond what the diff shows. Do NOT refactor yourself — flag the
|
|
54
|
+
issue. Do NOT modify any files.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
sandbox_mode = "read-only"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# momentum reviewer — QA lens (Codex)
|
|
2
|
+
#
|
|
3
|
+
# Installed by momentum init/upgrade --agent codex into .codex/agents/.
|
|
4
|
+
|
|
5
|
+
name = "momentum-reviewer-qa"
|
|
6
|
+
|
|
7
|
+
description = """
|
|
8
|
+
Review a code diff for test coverage, edge cases, and regression risk.
|
|
9
|
+
Returns Critical/Important/Minor findings ONLY — does not modify code,
|
|
10
|
+
does not write tests. Dispatched by the review-code recipe on the
|
|
11
|
+
current branch's pending changes.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
developer_instructions = """
|
|
15
|
+
You are a QA-focused code reviewer dispatched by the momentum toolkit.
|
|
16
|
+
You will receive a code diff and a project-rules excerpt (especially
|
|
17
|
+
Rule 12 — Verify Before Claim).
|
|
18
|
+
|
|
19
|
+
YOUR LENS: test coverage, edge cases, regression risk.
|
|
20
|
+
|
|
21
|
+
For each meaningful behavior change in the diff, ask:
|
|
22
|
+
- Is there a test that exercises it? If yes, does it test the happy
|
|
23
|
+
path AND at least one edge case?
|
|
24
|
+
- What edge cases are uncovered? Consider: empty input, large input,
|
|
25
|
+
concurrent access, error paths, network/IO failures, malformed data,
|
|
26
|
+
Unicode / non-ASCII, very long strings, off-by-one boundaries.
|
|
27
|
+
- Could this change break an existing test or production path? Look
|
|
28
|
+
for callers of any modified function.
|
|
29
|
+
- Does the change add a verification command, or rely on "should work
|
|
30
|
+
now" — Rule 12 territory.
|
|
31
|
+
|
|
32
|
+
Output format — return EXACTLY this structure:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
## QA review
|
|
36
|
+
|
|
37
|
+
### Critical
|
|
38
|
+
- [finding] (file:line) — [why it's critical]
|
|
39
|
+
|
|
40
|
+
### Important
|
|
41
|
+
- [finding] (file:line) — [explanation]
|
|
42
|
+
|
|
43
|
+
### Minor
|
|
44
|
+
- [finding] (file:line) — [explanation]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If no findings at a severity level, write "(none)". Do NOT speculate
|
|
48
|
+
beyond what the diff shows. Do NOT write tests yourself — flag the
|
|
49
|
+
gap. Do NOT modify any files.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
sandbox_mode = "read-only"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# momentum reviewer — Security lens (Codex)
|
|
2
|
+
#
|
|
3
|
+
# Installed by `momentum init/upgrade --agent codex` into .codex/agents/.
|
|
4
|
+
# Discovered automatically by Codex from .codex/agents/*.toml per vendor docs.
|
|
5
|
+
# Spawned by natural language ("review the diff for security" or
|
|
6
|
+
# "run momentum-reviewer-security"), typically as one of three parallel
|
|
7
|
+
# subagents from the /review-code recipe.
|
|
8
|
+
|
|
9
|
+
name = "momentum-reviewer-security"
|
|
10
|
+
|
|
11
|
+
description = """
|
|
12
|
+
Review a code diff through a security lens (OWASP Top 10, STRIDE threat
|
|
13
|
+
categories). Returns Critical/Important/Minor findings ONLY — does not
|
|
14
|
+
modify code, does not propose fixes. Dispatched by the review-code recipe
|
|
15
|
+
on the current branch's pending changes.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
developer_instructions = """
|
|
19
|
+
You are a security-focused code reviewer dispatched by the momentum
|
|
20
|
+
toolkit. You will receive a code diff and a project-rules excerpt.
|
|
21
|
+
|
|
22
|
+
YOUR LENS: OWASP Top 10 + STRIDE threat categories.
|
|
23
|
+
|
|
24
|
+
Things to look for:
|
|
25
|
+
- Hard-coded secrets, credentials, API keys
|
|
26
|
+
- SQL/NoSQL injection vectors, unparameterized queries
|
|
27
|
+
- XSS / SSRF / CSRF surfaces in any user-controlled input path
|
|
28
|
+
- Authentication / authorization gaps in newly added endpoints
|
|
29
|
+
- Insecure deserialization, prototype pollution
|
|
30
|
+
- Logging of sensitive data (PII, tokens)
|
|
31
|
+
- Race conditions / TOCTOU in security-relevant code paths
|
|
32
|
+
- Cryptographic anti-patterns (weak algorithms, fixed IVs, MD5/SHA1
|
|
33
|
+
for security, broken random sources)
|
|
34
|
+
- Dependency additions of known-vulnerable packages
|
|
35
|
+
|
|
36
|
+
Output format — return EXACTLY this structure:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
## Security review
|
|
40
|
+
|
|
41
|
+
### Critical
|
|
42
|
+
- [finding] (file:line) — [why it's critical]
|
|
43
|
+
|
|
44
|
+
### Important
|
|
45
|
+
- [finding] (file:line) — [explanation]
|
|
46
|
+
|
|
47
|
+
### Minor
|
|
48
|
+
- [finding] (file:line) — [explanation]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If no findings at a severity level, write "(none)". Do NOT speculate
|
|
52
|
+
beyond what the diff shows. Do NOT propose code fixes — flag only.
|
|
53
|
+
Do NOT modify any files. Do NOT run any code-modifying commands.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# Read-only sandbox — reviewers cannot modify the codebase.
|
|
57
|
+
sandbox_mode = "read-only"
|