@codedology/code-forge 0.3.1 → 0.4.0
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/CHANGELOG.md +60 -0
- package/README.md +79 -21
- package/bin/code-forge.mjs +6 -1
- package/docs/README.md +5 -4
- package/docs/reference/blocks.json +153 -1
- package/docs/reference/config.md +8 -1
- package/package.json +4 -2
- package/schema/code-forge.schema.json +15 -4
- package/skill/SKILL.md +7 -7
- package/skill/references/adapters/claude-code.md +1 -1
- package/skill/references/adapters/solo.md +1 -1
- package/skill/references/adapters/subprocess.md +1 -1
- package/skill/references/code.md +4 -3
- package/skill/references/continuity.md +4 -0
- package/skill/references/decisions.md +5 -2
- package/skill/references/ledger.md +8 -2
- package/skill/references/plan.md +3 -3
- package/skill/references/review.md +8 -5
- package/skill/references/security.md +3 -1
- package/skill/scripts/forge +1 -1
- package/skill/templates/coder-brief.md +36 -0
- package/skill/templates/plan.md +2 -0
- package/src/cli/block.mjs +51 -8
- package/src/cli/jev.mjs +114 -17
- package/src/cli/ledger.mjs +99 -8
- package/src/cli/logs.mjs +193 -58
- package/src/cli/plan.mjs +27 -11
- package/src/cli/report.mjs +15 -1
- package/src/cli/resolve.mjs +16 -1
- package/src/cli/review-file.mjs +10 -5
- package/src/cli/run.mjs +109 -8
- package/src/config/closed-book.mjs +75 -0
- package/src/config/validate.mjs +128 -7
- package/src/decide/escalation.mjs +112 -11
- package/src/decide/jev-client.mjs +1 -1
- package/src/decide/questions.mjs +39 -3
- package/src/doctor/probes.mjs +48 -6
- package/src/engines/builders/claude.mjs +4 -1
- package/src/engines/builders/codex.mjs +26 -11
- package/src/engines/builders/grok.mjs +3 -3
- package/src/engines/efforts.mjs +109 -0
- package/src/engines/sentinel.mjs +34 -0
- package/src/keys/onepassword.mjs +3 -0
- package/src/ledger/report.mjs +66 -29
- package/src/ledger/spend.mjs +171 -0
- package/src/review/engine.mjs +65 -23
- package/src/review/fixloop.mjs +29 -6
- package/src/review/session-retry.mjs +69 -0
- package/src/review/triage.mjs +26 -1
- package/src/review/validate-review.mjs +21 -6
- package/src/session/author.mjs +6 -2
- package/src/session/plan-check.mjs +71 -6
- package/src/session/plan-sections.mjs +98 -0
- package/src/session/spawn.mjs +217 -8
- package/src/state/block.mjs +13 -4
- package/src/state/config-snapshot.mjs +150 -0
- package/src/state/run.mjs +86 -0
- package/src/util/breadcrumbs.mjs +145 -0
- package/src/util/error-hint.mjs +3 -2
- package/src/util/error-kind.mjs +2 -2
- package/src/util/error-log.mjs +109 -18
- package/src/util/forbidden.mjs +3 -1
- package/src/util/known-fixes.json +1 -0
- package/src/util/known-fixes.mjs +153 -0
- package/src/worker/engine.mjs +13 -8
- package/src/worker/loop.mjs +135 -39
- package/src/worker/queue.mjs +68 -7
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,66 @@ waits on a second real consumer (plan §10.4, Q17).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] — 2026-10-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `budget.usd` per run: every session row carries an estimated `usd`; at 80% one warning, at 100% no new session starts
|
|
14
|
+
(fail closed if the spend cannot be read). `report` shows running totals for open blocks and per run; `run status`
|
|
15
|
+
shows spent and budget; `ledger add coder --usd` records cloud or manual coder spend.
|
|
16
|
+
- `code-forge run reload --run <r>`: re-read `.code-forge.yml` mid-run without stopping blocks. Queued reviews keep the
|
|
17
|
+
old config, new ones use the new one; keys fixed for the run are refused by name; a signed `run.reload` row lists the
|
|
18
|
+
changed key paths (never values). Coders may not run it.
|
|
19
|
+
- `block close --report <file>`: a coder report without a `reviewed <path> ticket <id>` line for every changed file
|
|
20
|
+
counts as FAILED (new `skill/templates/coder-brief.md`).
|
|
21
|
+
- Error reports: `logs report --with-doctor` adds a cleaned setup check; each logged error lists the names of the last 5
|
|
22
|
+
commands (no flags or values); recovered problems are logged as warnings (1Password retry, review retry, System 1
|
|
23
|
+
fallback, budget at 80%), shown by `logs` and `logs summary`, and included in a report only with `--include-warnings`.
|
|
24
|
+
`CODE_FORGE_NO_ERROR_LOG=1` turns all of it off.
|
|
25
|
+
- Known fixes: `logs report` checks a shipped table of fixed errors and, on an older version, tells you to upgrade
|
|
26
|
+
instead of filing (`--force` files anyway). An `error-triage` GitHub Action labels error reports by fingerprint,
|
|
27
|
+
comments once when the error is already fixed, and writes a weekly count. Maintainers record fixes with `npm run
|
|
28
|
+
known-fix -- add`.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Escalation and review cost rules from the first real run: after one review round that leaves 2+ warnings (or any
|
|
33
|
+
critical), the next fix climbs one level (`escalation.*`); docs and contract blocks code at L1 or higher
|
|
34
|
+
(`levels.coder_floor_docs`); risk 0–1 gets a single reviewer (`review.single_reviewer_max_risk`); docs blocks skip
|
|
35
|
+
multimodel review unless `review.multimodel_for_docs` is set.
|
|
36
|
+
- `plan check` refuses a block whose level does not match its recorded lane (`jev ask lane --block <id> [--plan
|
|
37
|
+
<file>]`, or `--rules` without Jev) and prints the lane per block. The plan author gets the exact required headings
|
|
38
|
+
from one shared list; a close heading at the right position is accepted with a WARN. `jev ask` now writes to the
|
|
39
|
+
project's ledger slug (it used to default to `code-forge`).
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- `validate` rejects an effort the level's provider cannot take (for example `xhigh` on an openai level), for levels and
|
|
44
|
+
fallback entries, instead of failing when the session starts. The builders share one list of allowed efforts, and
|
|
45
|
+
messages never repeat an unknown value.
|
|
46
|
+
- Stuck review sessions: a session that times out is retried once before the review is reported unavailable;
|
|
47
|
+
`review.session_timeout_s` now defaults to 300; the ledger note keeps a cleaned stderr tail and the stdout event types
|
|
48
|
+
(never stdout text) so a hang can be diagnosed; a live worker with a fresh heartbeat is never reported as
|
|
49
|
+
`worker_down`.
|
|
50
|
+
- `ledger tail -n <count>` limits the output (only `--n` worked). Jev score criteria keys must be exactly 0..n, with a
|
|
51
|
+
clear error otherwise.
|
|
52
|
+
|
|
53
|
+
### Security
|
|
54
|
+
|
|
55
|
+
- Codex (openai) is refused for closed-book roles — reviewer, judge, S2 and plan author — because it always has a shell
|
|
56
|
+
that can read files. `validate`, `resolve` and `doctor` say so. Set `review.allow_open_book_codex: true` to accept
|
|
57
|
+
that risk and keep using it (with warnings). Codex coders are unchanged.
|
|
58
|
+
|
|
59
|
+
## [0.3.2] — 2026-10-01
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- Jev: `score` questions (such as `risk`) send their criteria as a list indexed by score. Jev refused the keyed object
|
|
64
|
+
with 422, so `doctor`'s Jev check failed and every `risk` call silently fell back to rules.
|
|
65
|
+
- Review: on a small diff (20 added lines or fewer), a clean pass (passed, no findings, every hunk acknowledged) needs
|
|
66
|
+
only 40 output tokens instead of `review.min_tokens_out`, so a correct short review of a tiny file is no longer
|
|
67
|
+
refused as `too_short`. Any finding, or a larger diff, keeps the full floor.
|
|
68
|
+
|
|
9
69
|
## [0.3.1] — 2026-10-01
|
|
10
70
|
|
|
11
71
|
### Fixed
|
package/README.md
CHANGED
|
@@ -3,10 +3,38 @@
|
|
|
3
3
|
A CLI (`code-forge`) plus one Agent Skill that runs the **plan → harden → code → review** pipeline
|
|
4
4
|
for cross-model, parallel, evidence-gated feature delivery — on Claude Code, Codex, Grok, and Solo.
|
|
5
5
|
|
|
6
|
-
> **Status:**
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
6
|
+
> **Status:** published on npm. The CLI, the decision layer, the review engine, the worker, the
|
|
7
|
+
> proof policy, the installer, the Agent Skill under `skill/` and the example repo under
|
|
8
|
+
> `examples/` have all landed (`docs/reference/blocks.json` lists every build block). What changed
|
|
9
|
+
> in each version is in [CHANGELOG.md](CHANGELOG.md).
|
|
10
|
+
|
|
11
|
+
## What's new in 0.4
|
|
12
|
+
|
|
13
|
+
- **Cost control.** Set `budget.usd` per run: one warning at 80%, no new session at 100%. Every
|
|
14
|
+
session row carries an estimated `usd`; `report` and `run status` show the spend, and
|
|
15
|
+
`ledger add coder --usd` records spend code-forge did not see.
|
|
16
|
+
- **Cheaper, faster fixes.** One review round that leaves 2 or more warnings climbs the coder one
|
|
17
|
+
level (`escalation.*`). Docs and contract blocks code at L1 or higher and skip multimodel review;
|
|
18
|
+
a file with risk 0–1 gets one reviewer (`review.single_reviewer_max_risk`).
|
|
19
|
+
- **Change the config mid-run.** `code-forge run reload --run <id>` re-reads `.code-forge.yml`
|
|
20
|
+
without stopping open blocks.
|
|
21
|
+
- **Stricter plans.** `plan check` refuses a block whose level is not the lane recorded with
|
|
22
|
+
`jev ask lane --block <id>` (or `--rules` without Jev), and prints the lane of every block.
|
|
23
|
+
`block close --report <file>` fails a coder report that does not name a review ticket per file.
|
|
24
|
+
- **Codex is refused for closed-book roles** (reviewer, judge, System 2, plan author): it always
|
|
25
|
+
has a shell. See [Security model](#security-model).
|
|
26
|
+
- **Steadier reviews.** A timed-out review session is retried once; `review.session_timeout_s`
|
|
27
|
+
defaults to 300; a live worker with a fresh heartbeat is never reported down.
|
|
28
|
+
- **Better error reports.** `logs report --with-doctor` adds a cleaned setup check; errors list the
|
|
29
|
+
last 5 command names; recovered problems are logged as warnings; an error that a newer version
|
|
30
|
+
fixes tells you to upgrade instead of filing it.
|
|
31
|
+
- **Earlier checks.** `validate` refuses an effort the level's provider cannot take (for example
|
|
32
|
+
`xhigh` on an openai level), so nothing fails when the session starts.
|
|
33
|
+
|
|
34
|
+
Fixed in 0.3.1 and 0.3.2: Claude reviewer sessions no longer fail at once on the `--json-schema`
|
|
35
|
+
flag; Grok answers are read from Grok's own answer envelope; Jev `score` questions (such as `risk`)
|
|
36
|
+
no longer fall back to rules; and a clean review of a tiny diff (20 added lines or fewer) needs only
|
|
37
|
+
40 output tokens, so it is no longer refused as `too_short`.
|
|
10
38
|
|
|
11
39
|
## What ships
|
|
12
40
|
|
|
@@ -88,28 +116,28 @@ usage line.
|
|
|
88
116
|
| `tools` | `code-forge tools [--json]` · `code-forge tools install [<id>…] [--yes] [--dry-run]` — see and install the recommended tools (claude, codex, gemini, grok, op, solo) |
|
|
89
117
|
| `validate` | `code-forge validate [--file <path>]` |
|
|
90
118
|
| `resolve` | `code-forge resolve <L0\|L1\|L2\|L3>` |
|
|
91
|
-
| `run` | `code-forge run start [--cwd <dir>] [--run <id>] [--engine <e>] [--worker-pid <pid>]` · `run start --reattach --run <id
|
|
92
|
-
| `block` | `code-forge block open <id> --run <r> --level L<n> --owned <paths…> --acceptance <file
|
|
119
|
+
| `run` | `code-forge run start [--cwd <dir>] [--run <id>] [--engine <e>] [--worker-pid <pid>]` · `run start --reattach --run <id> [--worker-pid <pid>]` · `run status --run <id>` (with spent and budget USD) · `run reload --run <id>` (re-read `.code-forge.yml` mid-run) · `run end --run <id>` |
|
|
120
|
+
| `block` | `code-forge block open <id> --run <r> --level L<n> --owned <paths…> --acceptance <file> [--brief <file>] [--attempt <n>] [--base <sha>] [--lines <n>] [--kind code\|docs\|contract]` · `block attempt\|rebase <id> --run <r>` · `block close <id> --run <r> [--transcript <file>] [--report <file>] [--no-require-reviews]` · `block claim <id> <path> --run <r>` · `block stop <id> --run <r> --reason <text>` · `block waive <id> <finding-id> --run <r> --file <path> --reason <text>` (human-only) |
|
|
93
121
|
| `worker` | `code-forge worker --run <id> [--cwd <dir>] [--poll-ms <n>] [--once]` — started detached by `run start`, never by a coder |
|
|
94
122
|
| `review` | `code-forge review [--base <ref>] [--files <path…>] [--acceptance <file> \| --intent "<text>"] [--run <id>] [--max <seconds>] [--json] [--keep-run]` — review only: no coder, no proof, never closes a block |
|
|
95
|
-
| `review-file` | `code-forge review-file <path> --block <id> [--run <id>]` (enqueue) · `review-file --wait <ticket> [--max <seconds>s]` (poll) |
|
|
96
|
-
| `spawn` | `code-forge spawn --level
|
|
97
|
-
| `s2` | `code-forge s2 --packet <file.json> [--run <id>] [--block <id>] [--timeout <
|
|
98
|
-
| `author` | `code-forge author --job plan\|harden --brief <file> [--facts <file>] [--draft <file>] [--answers <file>] [--out <file>] [--run <id>] [--timeout <
|
|
99
|
-
| `facts` | `code-forge facts --brief <file> [--sources <path>…] [--out <file>] [--run <id>] [--timeout <
|
|
100
|
-
| `plan` | `code-forge plan check <plan-file> [--facts <sheet>]` |
|
|
101
|
-
| `proof` | `code-forge proof tier --file <path> --risk <0-3> [--security] [--cwd <dir>]` · `proof export
|
|
123
|
+
| `review-file` | `code-forge review-file <path> --block <id> [--run <id>]` (enqueue) · `review-file --wait <ticket> [--max <seconds>s]` (poll, default 90s; still running at `--max` prints `status: pending, reason: wait_timeout`) |
|
|
124
|
+
| `spawn` | `code-forge spawn --level L0\|L1\|L2\|L3 --role <role> --brief <file> [--schema <file>] [--cwd <dir>] [--run <id>] [--block <id>] [--timeout <seconds>] [--background]` |
|
|
125
|
+
| `s2` | `code-forge s2 --packet <file.json> [--run <id>] [--block <id>] [--timeout <seconds>]` |
|
|
126
|
+
| `author` | `code-forge author --job plan\|harden --brief <file> [--facts <file>] [--draft <file>] [--answers <file>] [--out <file>] [--run <id>] [--timeout <seconds>]` |
|
|
127
|
+
| `facts` | `code-forge facts --brief <file> [--sources <path>…] [--out <file>] [--run <id>] [--timeout <seconds>]` |
|
|
128
|
+
| `plan` | `code-forge plan check <plan-file> [--facts <sheet>] [--slug <slug>]` — every block's level must be the lane recorded by `jev ask lane --block <id>`; prints `lanes: B1 L1 (rules) · …` |
|
|
129
|
+
| `proof` | `code-forge proof tier --file <path> --risk <0-3> [--security] [--cwd <dir>]` · `proof export <block> --run <r> [--remove]` · `proof lock\|unlock\|restore <block> --run <r>` · `proof red-green <block> --run <r> --test <file[::case]> [--mechanism revert\|assertion-deletion]` |
|
|
102
130
|
| `gates` | `code-forge gates detect\|run\|secret-scan\|safe-edit\|scope\|acceptance\|transcript-grep --cwd <dir> …` |
|
|
103
|
-
| `jev` | `code-forge jev ask <question-id> --state <file
|
|
104
|
-
| `keys` | `code-forge keys list \| set <name> [--op <ref>] \| test <name> [--ref <ref>] \| remove <name>` |
|
|
105
|
-
| `ledger` | `code-forge ledger calibration
|
|
106
|
-
| `report` | `code-forge report --slug <slug> [--json] [--export <dir>]` |
|
|
131
|
+
| `jev` | `code-forge jev ask <question-id> --state <file> [--cwd <dir>] [--slug <slug>] [--key-ref <ref>] [--block <id>] [--plan <file>] [--rules]` — `--rules` answers `lane`, `risk` or `security_sensitive` without Jev; writes to the project's ledger slug |
|
|
132
|
+
| `keys` | `code-forge keys list \| set <name> [--op <item-id\|link\|op://ref>] \| test <name> [--ref <ref>] \| remove <name>` |
|
|
133
|
+
| `ledger` | `code-forge ledger tail --slug <slug> [--n\|-n <count>]` · `ledger calibration --slug <slug> [--question <id>]` · `ledger outcome --slug <slug> --pr <n> --ci red\|green\|reverted` · `ledger outcome --slug <slug> --scan-git [--cwd <dir>] [--days <n>]` · `ledger add coder --run <r> --block <b> --usd <n> [--note "..."]` |
|
|
134
|
+
| `report` | `code-forge report --slug <slug> [--json] [--export <dir>]` — 13 sections, then the spend per run (open blocks included) and the total |
|
|
107
135
|
| `models` | `code-forge models [--refresh --from-cli-caches]` |
|
|
108
136
|
| `list` | `code-forge list` |
|
|
109
137
|
| `remove` | `code-forge remove [<harness>] [--scope project\|global]` |
|
|
110
138
|
| `upgrade` | `code-forge upgrade [--source <path>]` |
|
|
111
|
-
| `logs` | `code-forge logs [--last N] [--json]` · `logs summary [--days N] [--json]` · `logs clear [--yes]` · `logs path` — the local error log (`~/.code-forge/logs/errors.jsonl`) |
|
|
112
|
-
| `logs report` | `code-forge logs report [--last N] [--kind K] [--verb V] [--note "text"] [--dry-run] [--yes]` — share selected errors as a public GitHub issue; you see the full text first and say yes once |
|
|
139
|
+
| `logs` | `code-forge logs [--last N] [--json]` · `logs summary [--days N] [--json]` · `logs clear [--yes]` · `logs path` — the local error log (`~/.code-forge/logs/errors.jsonl`): errors, warnings, and `[fixed in X.Y.Z]` marks |
|
|
140
|
+
| `logs report` | `code-forge logs report [--last N] [--kind K] [--verb V] [--note "text"] [--include-warnings] [--with-doctor] [--no-ai] [--allow-old] [--force] [--dry-run] [--yes]` — share selected errors as a public GitHub issue; you see the full text first and say yes once. An error a newer version fixes is not filed unless `--force` |
|
|
113
141
|
| `help` / `version` | `code-forge --help` (or no verb) · `code-forge --version` |
|
|
114
142
|
|
|
115
143
|
`run`, `block`, `worker`, `spawn`, `s2`, `author`, `facts` and `review-file` are what the Agent
|
|
@@ -128,6 +156,18 @@ CLI verbs like any other and every one of them is exercised by this package's ow
|
|
|
128
156
|
- **A forbidden-command list** stops a coder from starting its own worker, waiving a review, or
|
|
129
157
|
running other orchestrator-only actions — rendered into each provider's own deny-list mechanism
|
|
130
158
|
(`--disallowedTools` for Claude, an execpolicy rules file plus prose for Codex).
|
|
159
|
+
- **Closed-book reviews.** Reviewers, judges, System 2 and the plan author see the packet and
|
|
160
|
+
nothing else: Claude runs them with no tools, Grok with every tool denied. Codex (provider
|
|
161
|
+
`openai`) has no mode without a shell, so code-forge refuses it for those roles: `validate`
|
|
162
|
+
warns, `resolve` marks the level `closed_book: "refused"`, `doctor` fails its isolation row, and
|
|
163
|
+
the session is never started. Codex coders are unchanged. `review.allow_open_book_codex: true`
|
|
164
|
+
accepts the risk and keeps Codex in those roles, with a warning on every surface.
|
|
165
|
+
- **The error log stays on your machine.** A failed verb is logged to
|
|
166
|
+
`~/.code-forge/logs/errors.jsonl` with flag names but never flag values, and with home folder,
|
|
167
|
+
project, emails, `op://` references and 1Password item IDs replaced. `logs report` cleans the
|
|
168
|
+
text twice (built-in rules, then an AI check), stops on anything that looks like a key, shows
|
|
169
|
+
you the full issue and sends nothing without your yes. `CODE_FORGE_NO_ERROR_LOG=1` turns the log,
|
|
170
|
+
the warnings and the command list off. Every field is listed in [docs/privacy.md](docs/privacy.md).
|
|
131
171
|
- **No mutation testing.** Neither this package's own tests nor the product it ships run mutation
|
|
132
172
|
testing (Ricardo's ruling R14/Q16, 2026-09-25). Proof is plain unit and feature tests with exact
|
|
133
173
|
assertions, plus a red→green runner that proves a new test fails before the fix and passes after.
|
|
@@ -135,7 +175,22 @@ CLI verbs like any other and every one of them is exercised by this package's ow
|
|
|
135
175
|
## Configuration reference
|
|
136
176
|
|
|
137
177
|
`schema/code-forge.schema.json` is the source of truth for `.code-forge.yml`.
|
|
138
|
-
|
|
178
|
+
[docs/reference/config.md](docs/reference/config.md) lists every key with its type and default.
|
|
179
|
+
Keys added for 0.4:
|
|
180
|
+
|
|
181
|
+
| Key | Default | What it does |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `budget.usd` | none | per-run spend stop in USD: one warning at 80%, no new session at 100% |
|
|
184
|
+
| `escalation.after_rounds_with_warnings` | `1` | rounds with many warnings at one level before the coder climbs (`0` turns it off) |
|
|
185
|
+
| `escalation.warning_threshold` | `2` | how many open warnings make a round "heavy" (any critical counts too) |
|
|
186
|
+
| `levels.coder_floor_docs` | `L1` | the lowest level that codes a docs or contract block |
|
|
187
|
+
| `review.single_reviewer_max_risk` | `1` | at or below this risk a file gets one reviewer and no judge |
|
|
188
|
+
| `review.multimodel_for_docs` | `false` | let docs and contract blocks use multimodel review too |
|
|
189
|
+
| `review.allow_open_book_codex` | `false` | let Codex run reviewer, judge, System 2 and plan author anyway |
|
|
190
|
+
| `review.session_timeout_s` | `300` | a review session that runs longer is killed and retried once |
|
|
191
|
+
|
|
192
|
+
`code-forge block open … --kind code|docs|contract` sets a block's kind when its file endings do
|
|
193
|
+
not say it. The reference page is generated:
|
|
139
194
|
|
|
140
195
|
```bash
|
|
141
196
|
node scripts/gen-config-doc.mjs # regenerate docs/reference/config.md
|
|
@@ -154,4 +209,7 @@ Node >= 22 required (ruling R7). No build step — the package ships plain ESM `
|
|
|
154
209
|
by Node. `docs/reference/blocks.json` maps each build block to the files it owns and what it
|
|
155
210
|
depends on, kept in sync with the maintainer's design plan.
|
|
156
211
|
|
|
157
|
-
Releasing: record changes with `npm run changelog -- <type> "<text>"
|
|
212
|
+
Releasing: record changes with `npm run changelog -- <type> "<text>"` and fixed error reports with
|
|
213
|
+
`npm run known-fix -- add <fp> <version> "<summary>"`, then `npm run release -- <patch|minor|major|x.y.z> [--dry-run]`
|
|
214
|
+
bumps, commits and tags (it never pushes or publishes). Publish with `npm publish` from your
|
|
215
|
+
machine, then push the tag: CI only creates the GitHub release. See [docs/releasing.md](docs/releasing.md).
|
package/bin/code-forge.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import path from 'node:path';
|
|
|
14
14
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
15
|
import { clearErrorKind, reportErrorKind, takeErrorKind } from '../src/util/error-kind.mjs';
|
|
16
16
|
import { maybeHint } from '../src/util/error-hint.mjs';
|
|
17
|
-
import { captureStderr, writeVerbFailure } from '../src/util/error-log.mjs';
|
|
17
|
+
import { captureStderr, noteVerb, writeVerbFailure } from '../src/util/error-log.mjs';
|
|
18
18
|
import { redact } from '../src/util/redact.mjs';
|
|
19
19
|
|
|
20
20
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -98,6 +98,11 @@ export async function run(argv) {
|
|
|
98
98
|
|
|
99
99
|
const modulePath = path.join(CLI_DIR, `${verb}.mjs`);
|
|
100
100
|
|
|
101
|
+
// B37: the verb and its known subcommand word (never a flag or a value) join the last-5 list in
|
|
102
|
+
// `~/.code-forge/logs/breadcrumbs.json`; an error logged below names the commands before it.
|
|
103
|
+
// Best effort, never throws (CODE_FORGE_NO_ERROR_LOG=1 turns it off).
|
|
104
|
+
await noteVerb(verb, rest).catch(() => false);
|
|
105
|
+
|
|
101
106
|
// B27: a verb that exits non-zero or throws is logged to `~/.code-forge/logs/errors.jsonl`
|
|
102
107
|
// (scrubbed; never throws; never changes the exit code). The kind a verb reports is cleared
|
|
103
108
|
// first, and stderr is recorded only while the verb runs (the message is its last text).
|
package/docs/README.md
CHANGED
|
@@ -9,9 +9,9 @@ disagree, the verb is right: each verb prints its own usage line when its argume
|
|
|
9
9
|
| # | Page | Read it when you want to… |
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| 1 | [overview.md](overview.md) | know what code-forge is, the problem it solves, who it is for, and what it is not |
|
|
12
|
-
| 2 | [concepts.md](concepts.md) | look up a word: block, level, lane, tier, S1/S2, waiver, ledger… |
|
|
12
|
+
| 2 | [concepts.md](concepts.md) | look up a word: block, level, lane, tier, S1/S2, waiver, ledger, budget, block kind, closed book, known fix… |
|
|
13
13
|
| 3 | [how-it-works.md](how-it-works.md) | follow the full workflow from a brief to a closed block, and see who does what and where state lives |
|
|
14
|
-
| 4 | [getting-started.md](getting-started.md) | install it, answer `init`, run `doctor`,
|
|
14
|
+
| 4 | [getting-started.md](getting-started.md) | install it, answer `init`, run `doctor`, try the first commands, and read or report errors (`code-forge logs`) |
|
|
15
15
|
| 5 | [tutorial-first-test.md](tutorial-first-test.md) | run one real end-to-end test: build the code-forge marketing site in a new repo |
|
|
16
16
|
| 5a | [review-only.md](review-only.md) | only review code you already wrote: a branch, uncommitted work or some files, with CI exit codes |
|
|
17
17
|
| 6 | [examples/marketing-site/brief.md](examples/marketing-site/brief.md) | copy the brief the tutorial uses |
|
|
@@ -24,11 +24,12 @@ then 5a.
|
|
|
24
24
|
|
|
25
25
|
| Page | What it is |
|
|
26
26
|
|---|---|
|
|
27
|
+
| [../CHANGELOG.md](../CHANGELOG.md) | what changed in each version; `## [Unreleased]` is the next one |
|
|
27
28
|
| [reference/config.md](reference/config.md) | every `.code-forge.yml` key, its type and default. Generated from `schema/code-forge.schema.json` |
|
|
28
29
|
| [reference/blocks.json](reference/blocks.json) | the build blocks of this package and what each one owns |
|
|
29
30
|
| [marketing/code-forge-story.md](marketing/code-forge-story.md) | the marketing content bank (copy, lessons, what not to claim) |
|
|
30
|
-
| [privacy.md](privacy.md) | what the local error log holds, every cleaning rule, the AI check, and how to turn the log off or delete it |
|
|
31
|
-
| [releasing.md](releasing.md) | for maintainers: record changes (`npm run changelog`), cut a release with one command (`npm run release`), GitHub Releases,
|
|
31
|
+
| [privacy.md](privacy.md) | what the local error log holds (errors, warnings, the last command names), every cleaning rule, the AI check, the setup check (`--with-doctor`), known fixes, and how to turn the log off or delete it |
|
|
32
|
+
| [releasing.md](releasing.md) | for maintainers: record changes (`npm run changelog`) and known fixes (`npm run known-fix`), cut a release with one command (`npm run release`), publish by hand, GitHub Releases, the error-triage Action |
|
|
32
33
|
| [`skill/SKILL.md`](../skill/SKILL.md) and [`skill/references/`](../skill/references/) | the Agent Skill the orchestrator follows. The deepest and most exact description of the rules |
|
|
33
34
|
|
|
34
35
|
## Conventions in these pages
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"plans/code-forge-plan-v1.3.md §10.4",
|
|
5
5
|
"plans/NIGHT-LOG.md"
|
|
6
6
|
],
|
|
7
|
-
"block_count":
|
|
7
|
+
"block_count": 40,
|
|
8
8
|
"baseline_ids": ["B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8"],
|
|
9
9
|
"baseline_note": "Wave 0-1 blocks, landed before v1.3; depends_on may name them, but they have no entry under blocks.",
|
|
10
10
|
"blocks": {
|
|
@@ -371,6 +371,158 @@
|
|
|
371
371
|
],
|
|
372
372
|
"depends_on": ["B27"],
|
|
373
373
|
"note": "root-added 2026-10-01; not in the v1.3 §10.4 table"
|
|
374
|
+
},
|
|
375
|
+
"B29": {
|
|
376
|
+
"title": "Effort checked per provider: one shared PROVIDER_EFFORTS list for builders and validate (rule 15); messages never echo an unknown value",
|
|
377
|
+
"wave": 7,
|
|
378
|
+
"level": "L2",
|
|
379
|
+
"status": "landed",
|
|
380
|
+
"owned": [
|
|
381
|
+
"src/engines/efforts.mjs",
|
|
382
|
+
"test/engines/efforts.test.mjs"
|
|
383
|
+
],
|
|
384
|
+
"depends_on": [
|
|
385
|
+
"B4.1"
|
|
386
|
+
],
|
|
387
|
+
"note": "root-added 2026-10-02 from issue #2 field notes"
|
|
388
|
+
},
|
|
389
|
+
"B30": {
|
|
390
|
+
"title": "Review session hangs: one automatic retry on timeout, default timeout 300 s, cleaned stderr tail and stdout event types in a ledger note, worker heartbeat so --wait never reports worker_down for a live worker",
|
|
391
|
+
"wave": 7,
|
|
392
|
+
"level": "L2",
|
|
393
|
+
"status": "landed",
|
|
394
|
+
"owned": [
|
|
395
|
+
"src/review/session-retry.mjs",
|
|
396
|
+
"test/review/session-retry.test.mjs",
|
|
397
|
+
"test/worker/heartbeat.test.mjs"
|
|
398
|
+
],
|
|
399
|
+
"depends_on": [
|
|
400
|
+
"B12c"
|
|
401
|
+
],
|
|
402
|
+
"note": "root-added 2026-10-02 from issue #2 field notes; review cap reached, rulings in the local plan"
|
|
403
|
+
},
|
|
404
|
+
"B31": {
|
|
405
|
+
"title": "ledger tail -n, Jev score criteria keys must be 0..n, test hardening for PRs #3 and #4",
|
|
406
|
+
"wave": 7,
|
|
407
|
+
"level": "L2",
|
|
408
|
+
"status": "landed",
|
|
409
|
+
"owned": [
|
|
410
|
+
"src/decide/questions.mjs",
|
|
411
|
+
"test/decide/questions.test.mjs",
|
|
412
|
+
"test/review/validate-review.test.mjs"
|
|
413
|
+
],
|
|
414
|
+
"depends_on": [
|
|
415
|
+
"B12a"
|
|
416
|
+
],
|
|
417
|
+
"note": "root-added 2026-10-02"
|
|
418
|
+
},
|
|
419
|
+
"B32": {
|
|
420
|
+
"title": "Codex is refused for closed-book roles (reviewer, judge, S2, plan author): no proven no-tools mode; opt-in review.allow_open_book_codex with warnings",
|
|
421
|
+
"wave": 8,
|
|
422
|
+
"level": "L2",
|
|
423
|
+
"status": "landed",
|
|
424
|
+
"owned": [
|
|
425
|
+
"src/config/closed-book.mjs",
|
|
426
|
+
"test/config/closed-book.test.mjs"
|
|
427
|
+
],
|
|
428
|
+
"depends_on": [
|
|
429
|
+
"B4.1"
|
|
430
|
+
],
|
|
431
|
+
"note": "root-added 2026-10-02 from issue #2"
|
|
432
|
+
},
|
|
433
|
+
"B33": {
|
|
434
|
+
"title": "Session USD on every row, report running totals, budget.usd stop per run (80% warning, fail closed), ledger add coder --usd, run status spend",
|
|
435
|
+
"wave": 8,
|
|
436
|
+
"level": "L2",
|
|
437
|
+
"status": "landed",
|
|
438
|
+
"owned": [
|
|
439
|
+
"src/ledger/spend.mjs",
|
|
440
|
+
"test/ledger/spend.test.mjs",
|
|
441
|
+
"test/session/budget.test.mjs",
|
|
442
|
+
"test/state/budget.test.mjs"
|
|
443
|
+
],
|
|
444
|
+
"depends_on": [
|
|
445
|
+
"B6"
|
|
446
|
+
],
|
|
447
|
+
"note": "root-added 2026-10-02 from issue #2"
|
|
448
|
+
},
|
|
449
|
+
"B34": {
|
|
450
|
+
"title": "Escalation after a heavy review round, docs/contract coder floor L1, single reviewer for low risk, no multimodel for docs",
|
|
451
|
+
"wave": 8,
|
|
452
|
+
"level": "L2",
|
|
453
|
+
"status": "landed",
|
|
454
|
+
"owned": [
|
|
455
|
+
"src/decide/escalation.mjs",
|
|
456
|
+
"test/decide/escalation.test.mjs"
|
|
457
|
+
],
|
|
458
|
+
"depends_on": [
|
|
459
|
+
"B12c"
|
|
460
|
+
],
|
|
461
|
+
"note": "root-added 2026-10-02 from the owner rules in issue #2"
|
|
462
|
+
},
|
|
463
|
+
"B35": {
|
|
464
|
+
"title": "run reload: re-read config mid-run, pin queued tickets to the old snapshot, refuse fixed keys, signed run.reload row",
|
|
465
|
+
"wave": 8,
|
|
466
|
+
"level": "L2",
|
|
467
|
+
"status": "landed",
|
|
468
|
+
"owned": [
|
|
469
|
+
"src/state/config-snapshot.mjs",
|
|
470
|
+
"test/state/reload.test.mjs",
|
|
471
|
+
"test/worker/config-reload.test.mjs"
|
|
472
|
+
],
|
|
473
|
+
"depends_on": [
|
|
474
|
+
"B11"
|
|
475
|
+
],
|
|
476
|
+
"note": "root-added 2026-10-02 from issue #2"
|
|
477
|
+
},
|
|
478
|
+
"B36": {
|
|
479
|
+
"title": "plan check: levels must match a recorded lane (jev or rules, per block and plan); one shared source for required headings with a strict near-miss WARN; coder reports fail closed without review-file ticket ids (block close --report)",
|
|
480
|
+
"wave": 8,
|
|
481
|
+
"level": "L2",
|
|
482
|
+
"status": "landed",
|
|
483
|
+
"owned": [
|
|
484
|
+
"src/session/plan-sections.mjs",
|
|
485
|
+
"test/session/plan-sections.test.mjs",
|
|
486
|
+
"skill/templates/coder-brief.md"
|
|
487
|
+
],
|
|
488
|
+
"depends_on": [
|
|
489
|
+
"B12c"
|
|
490
|
+
],
|
|
491
|
+
"note": "root-added 2026-10-02 from issue #2 notes 12-14"
|
|
492
|
+
},
|
|
493
|
+
"B37": {
|
|
494
|
+
"title": "Error reports: --with-doctor setup check, breadcrumbs of the last 5 commands, warning lines for recovered problems (1Password retry, review retry, S1 fallback, budget 80%)",
|
|
495
|
+
"wave": 9,
|
|
496
|
+
"level": "L2",
|
|
497
|
+
"status": "landed",
|
|
498
|
+
"owned": [
|
|
499
|
+
"src/util/breadcrumbs.mjs",
|
|
500
|
+
"test/util/breadcrumbs.test.mjs",
|
|
501
|
+
"test/util/warnings.test.mjs"
|
|
502
|
+
],
|
|
503
|
+
"depends_on": [
|
|
504
|
+
"B28"
|
|
505
|
+
],
|
|
506
|
+
"note": "root-added 2026-10-02"
|
|
507
|
+
},
|
|
508
|
+
"B38": {
|
|
509
|
+
"title": "Known fixes table (logs report says upgrade instead of filing; regression note), known-fix maintainer script, error-triage GitHub Action (fp labels, one known-fix comment, weekly counts)",
|
|
510
|
+
"wave": 9,
|
|
511
|
+
"level": "L2",
|
|
512
|
+
"status": "landed",
|
|
513
|
+
"owned": [
|
|
514
|
+
"src/util/known-fixes.mjs",
|
|
515
|
+
"src/util/known-fixes.json",
|
|
516
|
+
"scripts/known-fix.mjs",
|
|
517
|
+
".github/workflows/error-triage.yml",
|
|
518
|
+
"test/util/known-fixes.test.mjs",
|
|
519
|
+
"test/known-fix.test.mjs",
|
|
520
|
+
"test/error-triage.test.mjs"
|
|
521
|
+
],
|
|
522
|
+
"depends_on": [
|
|
523
|
+
"B37"
|
|
524
|
+
],
|
|
525
|
+
"note": "root-added 2026-10-02"
|
|
374
526
|
}
|
|
375
527
|
}
|
|
376
528
|
}
|
package/docs/reference/config.md
CHANGED
|
@@ -53,6 +53,7 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
53
53
|
| `levels.L3.fallback[].provider` | enum: `anthropic`, `openai`, `xai` | yes | — | |
|
|
54
54
|
| `levels.L3.fallback[].model` | string | yes | — | minLength 1 |
|
|
55
55
|
| `levels.L3.fallback[].effort` | string | | — | |
|
|
56
|
+
| `levels.coder_floor_docs` | enum: `L0`, `L1`, `L2` | | `"L1"` | |
|
|
56
57
|
| `orchestrator` | enum: `L0`, `L1`, `L2`, `L3` | | — | |
|
|
57
58
|
| `system1` | object | | — | |
|
|
58
59
|
| `system1.provider` | enum: `anthropic`, `openai`, `xai` | | — | |
|
|
@@ -83,8 +84,12 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
83
84
|
| `escalation.review_rounds_per_level` | integer | | `2` | min 0 |
|
|
84
85
|
| `escalation.stop_at` | const `"L3"` | | `"L3"` | |
|
|
85
86
|
| `escalation.l3_mode` | enum: `patch`, `code` | | `"patch"` | |
|
|
87
|
+
| `escalation.after_rounds_with_warnings` | integer | | `1` | min 0 |
|
|
88
|
+
| `escalation.warning_threshold` | integer | | `2` | min 1 |
|
|
86
89
|
| `review` | object | | — | |
|
|
87
90
|
| `review.multimodel` | boolean | | `false` | |
|
|
91
|
+
| `review.multimodel_for_docs` | boolean | | `false` | |
|
|
92
|
+
| `review.single_reviewer_max_risk` | number | | `1` | min 0; max 3 |
|
|
88
93
|
| `review.second_provider` | enum: `anthropic`, `openai`, `xai` \| null | | `null` | |
|
|
89
94
|
| `review.second_levels` | null \| object | | `null` | |
|
|
90
95
|
| `review.closed_book` | const `true` | | `true` | |
|
|
@@ -102,10 +107,11 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
102
107
|
| `review.block_budget_usd` | number \| null | | `null` | |
|
|
103
108
|
| `review.min_tokens_out` | integer | | `120` | min 1 |
|
|
104
109
|
| `review.batch_small_files` | boolean | | `true` | |
|
|
105
|
-
| `review.session_timeout_s` | integer | | `
|
|
110
|
+
| `review.session_timeout_s` | integer | | `300` | min 1 |
|
|
106
111
|
| `review.max_rounds_per_file` | integer | | `4` | min 2; max 6 |
|
|
107
112
|
| `review.recheck_scope` | enum: `fix_hunks`, `file` | | `"fix_hunks"` | |
|
|
108
113
|
| `review.late_findings` | enum: `sweep`, `block` | | `"sweep"` | |
|
|
114
|
+
| `review.allow_open_book_codex` | boolean | | `false` | B32: let openai (Codex) run reviewer/judge/S2/author with its read-only sandbox, which can read files on this machine. Off: those sessions are refused. |
|
|
109
115
|
| `engine` | enum: `auto`, `solo`, `harness`, `subprocess` | | `"auto"` | |
|
|
110
116
|
| `harnesses` | array<string> | | — | |
|
|
111
117
|
| `harness` | object | | — | |
|
|
@@ -140,6 +146,7 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
140
146
|
| `budget.block_tokens_soft` | integer | | — | min 1 |
|
|
141
147
|
| `budget.block_tokens_hard` | integer | | — | min 1 |
|
|
142
148
|
| `budget.run_usd_soft` | number | | — | min 0 |
|
|
149
|
+
| `budget.usd` | number | | — | > 0; Per-run spend stop in USD (R6). Before every session spawn the run's estimated spend is checked: one warning at 80%, new sessions refused at 100%. |
|
|
143
150
|
| `budget.block_cases` | integer | | `80` | min 10 |
|
|
144
151
|
| `autonomy` | object | | — | |
|
|
145
152
|
| `autonomy.coder_may_open_draft_pr` | boolean | | `true` | |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codedology/code-forge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Plan/harden/code/review orchestration CLI and Agent Skill for cross-model, parallel, evidence-gated feature delivery.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"scripts",
|
|
32
32
|
"!scripts/release.mjs",
|
|
33
33
|
"!scripts/changelog.mjs",
|
|
34
|
+
"!scripts/known-fix.mjs",
|
|
34
35
|
"README.md",
|
|
35
36
|
"CHANGELOG.md",
|
|
36
37
|
"LICENSE"
|
|
@@ -39,7 +40,8 @@
|
|
|
39
40
|
"test": "CODE_FORGE_NO_LEAK=snapshot node --import ./test/helpers/isolate.mjs --test test/no-leak.test.mjs && node --import ./test/helpers/isolate.mjs --experimental-test-module-mocks --test 'test/**/*.test.mjs' && CODE_FORGE_NO_LEAK=final node --import ./test/helpers/isolate.mjs --test test/no-leak.test.mjs",
|
|
40
41
|
"typecheck": "tsc --checkJs --noEmit",
|
|
41
42
|
"release": "node scripts/release.mjs",
|
|
42
|
-
"changelog": "node scripts/changelog.mjs"
|
|
43
|
+
"changelog": "node scripts/changelog.mjs",
|
|
44
|
+
"known-fix": "node scripts/known-fix.mjs"
|
|
43
45
|
},
|
|
44
46
|
"dependencies": {
|
|
45
47
|
"@clack/prompts": "1.8.1",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"L0": { "$ref": "#/$defs/level" },
|
|
37
37
|
"L1": { "$ref": "#/$defs/level" },
|
|
38
38
|
"L2": { "$ref": "#/$defs/level" },
|
|
39
|
-
"L3": { "$ref": "#/$defs/level" }
|
|
39
|
+
"L3": { "$ref": "#/$defs/level" },
|
|
40
|
+
"coder_floor_docs": { "type": "string", "enum": ["L0", "L1", "L2"], "default": "L1" }
|
|
40
41
|
}
|
|
41
42
|
},
|
|
42
43
|
"orchestrator": { "$ref": "#/$defs/levelName" },
|
|
@@ -85,7 +86,9 @@
|
|
|
85
86
|
"retries_per_level": { "type": "integer", "minimum": 0, "default": 2 },
|
|
86
87
|
"review_rounds_per_level": { "type": "integer", "minimum": 0, "default": 2 },
|
|
87
88
|
"stop_at": { "type": "string", "const": "L3", "default": "L3" },
|
|
88
|
-
"l3_mode": { "type": "string", "enum": ["patch", "code"], "default": "patch" }
|
|
89
|
+
"l3_mode": { "type": "string", "enum": ["patch", "code"], "default": "patch" },
|
|
90
|
+
"after_rounds_with_warnings": { "type": "integer", "minimum": 0, "default": 1 },
|
|
91
|
+
"warning_threshold": { "type": "integer", "minimum": 1, "default": 2 }
|
|
89
92
|
}
|
|
90
93
|
},
|
|
91
94
|
"review": {
|
|
@@ -93,6 +96,8 @@
|
|
|
93
96
|
"additionalProperties": false,
|
|
94
97
|
"properties": {
|
|
95
98
|
"multimodel": { "type": "boolean", "default": false },
|
|
99
|
+
"multimodel_for_docs": { "type": "boolean", "default": false },
|
|
100
|
+
"single_reviewer_max_risk": { "type": "number", "minimum": 0, "maximum": 3, "default": 1 },
|
|
96
101
|
"second_provider": { "anyOf": [{ "$ref": "#/$defs/provider" }, { "type": "null" }], "default": null },
|
|
97
102
|
"second_levels": {
|
|
98
103
|
"anyOf": [
|
|
@@ -133,10 +138,11 @@
|
|
|
133
138
|
},
|
|
134
139
|
"min_tokens_out": { "type": "integer", "minimum": 1, "default": 120 },
|
|
135
140
|
"batch_small_files": { "type": "boolean", "default": true },
|
|
136
|
-
"session_timeout_s": { "type": "integer", "minimum": 1, "default":
|
|
141
|
+
"session_timeout_s": { "type": "integer", "minimum": 1, "default": 300 },
|
|
137
142
|
"max_rounds_per_file": { "type": "integer", "minimum": 2, "maximum": 6, "default": 4 },
|
|
138
143
|
"recheck_scope": { "type": "string", "enum": ["fix_hunks", "file"], "default": "fix_hunks" },
|
|
139
|
-
"late_findings": { "type": "string", "enum": ["sweep", "block"], "default": "sweep" }
|
|
144
|
+
"late_findings": { "type": "string", "enum": ["sweep", "block"], "default": "sweep" },
|
|
145
|
+
"allow_open_book_codex": { "type": "boolean", "default": false, "description": "B32: let openai (Codex) run reviewer/judge/S2/author with its read-only sandbox, which can read files on this machine. Off: those sessions are refused." }
|
|
140
146
|
}
|
|
141
147
|
},
|
|
142
148
|
"engine": { "type": "string", "enum": ["auto", "solo", "harness", "subprocess"], "default": "auto" },
|
|
@@ -228,6 +234,11 @@
|
|
|
228
234
|
"block_tokens_soft": { "type": "integer", "minimum": 1 },
|
|
229
235
|
"block_tokens_hard": { "type": "integer", "minimum": 1 },
|
|
230
236
|
"run_usd_soft": { "type": "number", "minimum": 0 },
|
|
237
|
+
"usd": {
|
|
238
|
+
"type": "number",
|
|
239
|
+
"exclusiveMinimum": 0,
|
|
240
|
+
"description": "Per-run spend stop in USD (R6). Before every session spawn the run's estimated spend is checked: one warning at 80%, new sessions refused at 100%."
|
|
241
|
+
},
|
|
231
242
|
"block_cases": { "type": "integer", "minimum": 10, "default": 80 }
|
|
232
243
|
}
|
|
233
244
|
},
|
package/skill/SKILL.md
CHANGED
|
@@ -18,7 +18,7 @@ You are the **orchestrator**: the session that invoked this skill. You dispatch,
|
|
|
18
18
|
|
|
19
19
|
`/code-forge plan|harden|code|full [brief file | plan file]`. No job given ⇒ infer it: a brief ⇒ `plan`; a plan whose header says `status: planned` ⇒ `harden`; `status: hardened` ⇒ `code`. `full` runs the three in order with one human checkpoint after `harden`.
|
|
20
20
|
|
|
21
|
-
State lives in the plan file's header — `facts → planned → hardened → coding → done` — and in the run record: `forge run status --run <id>` prints the active blocks, `forge ledger tail --slug <slug>` the last rows. Takeover after a lost session: `references/continuity.md`.
|
|
21
|
+
State lives in the plan file's header — `facts → planned → hardened → coding → done` — and in the run record: `forge run status --run <id>` prints the active blocks, `forge ledger tail --slug <slug>` the last rows. Takeover after a lost session: `references/continuity.md`. A config change mid-run (a model swap, the review topology) is `forge run reload --run <id>` — never `block stop` + `run end` + `run start` (`references/continuity.md` §4).
|
|
22
22
|
|
|
23
23
|
## §2 Roles by level (never by model name)
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ State lives in the plan file's header — `facts → planned → hardened → co
|
|
|
27
27
|
| facts delegate | L0 | read-only tools, empty cwd | `forge facts` |
|
|
28
28
|
| coder | the lane S1 picks (L0–L2); climbs one rung per escalation | the project tree | the engine adapter |
|
|
29
29
|
| reviewer, recheck | L2 | closed-book, empty cwd, packet on stdin | the worker |
|
|
30
|
-
| judge, S2, author | L3 | closed-book, one turn | the worker, `forge s2`, `forge author` |
|
|
30
|
+
| judge, S2, author | L3 | closed-book, one turn (never Codex: `references/security.md` §4) | the worker, `forge s2`, `forge author` |
|
|
31
31
|
| L3 rung | L3 | a patch ≤ 80 lines, once per block | `forge spawn --level L3 --role coder` |
|
|
32
32
|
|
|
33
33
|
`forge resolve L<n>` prints what a level resolves to (provider, model, effort, fallback); `forge models` lists the catalog. With `review.multimodel` on, the second reviewer is another provider's L2 and the judge comes from a third provider.
|
|
@@ -36,12 +36,12 @@ State lives in the plan file's header — `facts → planned → hardened → co
|
|
|
36
36
|
|
|
37
37
|
1. `forge facts --brief <brief> --out <plans_dir>/<slug>.facts.md` — an L0 delegate checks every claim with a read-only command. You read the sheet; you never read the sources yourself (`references/plan.md` §0).
|
|
38
38
|
2. `forge author --job plan --brief <brief> --facts <sheet> --out <plan>` — refuses without `--facts` (exit 2) and refuses a sheet older than the brief. The draft's §0 is the sheet, verbatim.
|
|
39
|
-
3. Harden: `forge author --job harden --brief <brief> --facts <sheet> --draft <plan> --answers <file>` until `questions[]` is empty. The human answers; you relay, never answer for them (`references/harden.md`). Exit gate: `forge plan check <plan>` green.
|
|
40
|
-
4. Per block, in dispatch order, never more than `caps.coders` alive: `forge block open <id> --run <r> --level L<n> --owned <paths…> --acceptance <file> --brief <file> --lines <n
|
|
39
|
+
3. Harden: `forge author --job harden --brief <brief> --facts <sheet> --draft <plan> --answers <file>` until `questions[]` is empty. The human answers; you relay, never answer for them (`references/harden.md`). Before the exit gate, record each block's lane: `forge jev ask lane --block <id> --plan <plan> --state <file>` (`--rules` without Jev); the plan's level must equal it. Exit gate: `forge plan check <plan>` green, with a lane for every block on its `lanes:` line (`references/plan.md`).
|
|
40
|
+
4. Per block, in dispatch order, never more than `caps.coders` alive: `forge block open <id> --run <r> --level L<n> --owned <paths…> --acceptance <file> --brief <file> --lines <n> [--kind code|docs|contract]` prints the pointer `BRIEF <path> lines=<n> sha=<sha8> <<<EOM>>>`. Send the pointer per the engine's adapter — `solo` → `references/adapters/solo.md`, `harness` → `references/adapters/claude-code.md`, `subprocess` → `references/adapters/subprocess.md` — and wait for `ACK <sha8> lines=<n>`.
|
|
41
41
|
5. The coder's first message is its **facts diff**, then its forecast (cases and lines, `templates/block-record.md`), then code, file by file: after each file `forge review-file <path> --block <id> --run <r>`, then `forge review-file --wait <ticket>` before the next file. Rounds ≥ 2 re-check only the fix hunks (`references/review.md`).
|
|
42
42
|
6. `===BLOCK <id> COMPLETE===` or `===BLOCK <id> FAILED: <reason>===` ends the coder's turn. Its report is a claim sheet: re-measure it (`references/code.md` §5).
|
|
43
|
-
7. `forge block close <id> --run <r>` is the gate: a signed `review.approved` row per changed file, gates green, every clause covered, forecast vs actual, no `rule_break`. Red ⇒ `references/decisions.md` (S1 `next`, escalation). Green ⇒ one commit for the block in the project's house style; `forge block rebase <id> --run <r>` first when HEAD moved.
|
|
44
|
-
8. `forge run end --run <r>` when every block is `done`; `forge report --slug <slug>` prints cost per block, escalations and
|
|
43
|
+
7. `forge block close <id> --run <r> --report <coder report>` is the gate: a report without a `reviewed <path> ticket <id>` line per changed file is FAILED; a signed `review.approved` row per changed file, gates green, every clause covered, forecast vs actual, no `rule_break`. Red ⇒ `references/decisions.md` (S1 `next`, escalation). Green ⇒ one commit for the block in the project's house style; `forge block rebase <id> --run <r>` first when HEAD moved.
|
|
44
|
+
8. `forge run end --run <r>` when every block is `done`; `forge report --slug <slug>` prints cost per block, escalations, review rounds and the spend per run (`budget.usd`, `references/ledger.md` §3.1).
|
|
45
45
|
|
|
46
46
|
## §4 Hard rules (the headings of `references/rules-core.md`)
|
|
47
47
|
|
|
@@ -68,7 +68,7 @@ State lives in the plan file's header — `facts → planned → hardened → co
|
|
|
68
68
|
|---|---|
|
|
69
69
|
| decomposing, forecasting, `plan check` | `references/plan.md`, `templates/plan.md`, `templates/facts-sheet.md` |
|
|
70
70
|
| the author loop and the tranche gate | `references/harden.md` |
|
|
71
|
-
| briefing a coder, the block gate, the PR contract, Definition of Done | `references/code.md`, `templates/block-record.md` |
|
|
71
|
+
| briefing a coder, the block gate, the PR contract, Definition of Done | `references/code.md`, `templates/coder-brief.md`, `templates/block-record.md` |
|
|
72
72
|
| review depth, packets, the convergence rule, `block waive` | `references/review.md` |
|
|
73
73
|
| System 1 / System 2, thresholds, escalation, the L3 rung | `references/decisions.md` |
|
|
74
74
|
| proof tiers, red→green, the measurement export | `references/proof.md` |
|
|
@@ -12,7 +12,7 @@ The harness's `Agent` tool runs the coder as a subagent; everything else — the
|
|
|
12
12
|
|
|
13
13
|
The tool return is the completion signal; the report must begin with `ACK <sha8>` and end with `===BLOCK <id> COMPLETE===` (+ test summary + `git diff --stat`) or `===BLOCK <id> FAILED: <reason>===`. A report without the sentinel is a failed block, never a partial success.
|
|
14
14
|
|
|
15
|
-
**Between completion and close come the review rounds.** The subagent ran `forge review-file <path> --block <id> --run <r>` per file and `--wait`ed on each ticket inside its turn, so most rounds happen before the sentinel; when the tool returns, first drain every `pending` ticket with `forge review-file --wait <ticket>` yourself — a pending ticket is a review in flight, not an open finding, and waiting on it costs no round. Then only an open `fix_now` finding, or a file the coder never submitted, starts a fix round (each one counts toward the file's cap): dispatch a new `Agent` call at the level the ladder says (`review.md` §5 — the coder is gone with its tool return, so the fix brief carries the open findings and the fix history) and it runs `review-file` again on the fixed file. Rounds are bounded: four rounds per file, then the L3 rung once, then `stopped: review_cap` for the human. Only when every changed file has a signed `review.approved` row do you run the re-measurement of `code.md` §5 and `forge block close <id> --run <r>` — the transcript grep reads `.code-forge/runs/<run>/<block>.log`; pass `--transcript <file>` when the harness saved the subagent's transcript elsewhere. Closing with a file still unreviewed is a human decision: `forge block waive <id> <finding> --run <r> --file <path> --reason "<why>"` per finding, or `forge block close … --no-require-reviews`, both audited as their own rows.
|
|
15
|
+
**Between completion and close come the review rounds.** The subagent ran `forge review-file <path> --block <id> --run <r>` per file and `--wait`ed on each ticket inside its turn, so most rounds happen before the sentinel; when the tool returns, first drain every `pending` ticket with `forge review-file --wait <ticket>` yourself — a pending ticket is a review in flight, not an open finding, and waiting on it costs no round. Then only an open `fix_now` finding, or a file the coder never submitted, starts a fix round (each one counts toward the file's cap): dispatch a new `Agent` call at the level the ladder says (`review.md` §5 — the coder is gone with its tool return, so the fix brief carries the open findings and the fix history) and it runs `review-file` again on the fixed file. Rounds are bounded: four rounds per file, then the L3 rung once, then `stopped: review_cap` for the human. Only when every changed file has a signed `review.approved` row do you run the re-measurement of `code.md` §5 and `forge block close <id> --run <r> --report <file>` (the subagent's final report, saved to a file) — the transcript grep reads `.code-forge/runs/<run>/<block>.log`; pass `--transcript <file>` when the harness saved the subagent's transcript elsewhere. Closing with a file still unreviewed is a human decision: `forge block waive <id> <finding> --run <r> --file <path> --reason "<why>"` per finding, or `forge block close … --no-require-reviews`, both audited as their own rows.
|
|
16
16
|
|
|
17
17
|
## §3 What is lost and what is not
|
|
18
18
|
|