@codedology/code-forge 0.5.1 → 0.6.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 +37 -0
- package/README.md +13 -0
- package/docs/README.md +1 -0
- package/docs/reference/blocks.json +96 -1
- package/docs/reference/config.md +2 -0
- package/package.json +1 -1
- package/schema/code-forge.schema.json +7 -0
- package/skill/SKILL.md +1 -0
- package/skill/references/adapters/claude-code.md +14 -0
- package/skill/references/autopilot.md +48 -0
- package/skill/references/code.md +1 -1
- package/skill/references/decisions.md +2 -0
- package/skill/references/harden.md +1 -1
- package/skill/references/plan.md +2 -0
- package/skill/references/review.md +2 -2
- package/skill/scripts/forge +1 -1
- package/src/autopilot/actions.mjs +491 -0
- package/src/autopilot/binnacle.mjs +494 -0
- package/src/autopilot/delegate.mjs +422 -0
- package/src/autopilot/grant.mjs +354 -0
- package/src/autopilot/limits.mjs +847 -0
- package/src/autopilot/scopes.mjs +95 -0
- package/src/cli/author.mjs +1 -2
- package/src/cli/autopilot.mjs +500 -0
- package/src/cli/block.mjs +40 -8
- package/src/cli/facts.mjs +1 -2
- package/src/cli/jev.mjs +1 -2
- package/src/cli/logs.mjs +4 -142
- package/src/cli/plan.mjs +1 -2
- package/src/cli/run.mjs +18 -60
- package/src/cli/s2.mjs +1 -2
- package/src/cli/spawn.mjs +1 -2
- package/src/config/closed-book.mjs +20 -3
- package/src/config/load.mjs +15 -0
- package/src/doctor/probes.mjs +34 -11
- package/src/engines/builders/claude.mjs +3 -3
- package/src/engines/builders/codex.mjs +6 -5
- package/src/engines/builders/grok.mjs +3 -3
- package/src/engines/builders/validate-params.mjs +3 -3
- package/src/ledger/report.mjs +2 -0
- package/src/review/fixloop.mjs +69 -5
- package/src/review/gate-check.mjs +156 -6
- package/src/session/spawn.mjs +68 -8
- package/src/state/run.mjs +8 -1
- package/src/util/breadcrumbs.mjs +1 -0
- package/src/util/forbidden.mjs +10 -0
- package/src/util/gh.mjs +175 -0
- package/src/worker/engine.mjs +8 -4
- package/src/worker/loop.mjs +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,43 @@ waits on a second real consumer (plan §10.4, Q17).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.6.0] — 2026-10-06
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `code-forge autopilot start|status|stop` (issue #5): a time-boxed grant (at most 24 h) of owner decisions — allow
|
|
14
|
+
`waive:warning`, `waive:nit`, `round:extra`, `model:choose` — with a fixed deny list in code (critical or proof
|
|
15
|
+
waivers, skipping reviews, any limit or rule change incl. parent keys, plan/design approval, merges, destructive
|
|
16
|
+
actions, budget raises). Signed grant, stop and expire rows; expiry is checked at every command. Coders may not run
|
|
17
|
+
it.
|
|
18
|
+
- `code-forge autopilot ask`: a closed-book delegate (never Codex) answers one owner question inside the grant; every
|
|
19
|
+
answer is one signed `autopilot.decision` row. It acts only when the question offers at least 2 options, the answer is
|
|
20
|
+
one of them, it is within scope, does not ask to escalate, and its confidence is at least `autopilot.min_confidence`
|
|
21
|
+
(default 0.7); otherwise the question goes to the owner (exit 3). `autopilot.*` counts as a limit key.
|
|
22
|
+
- `code-forge autopilot waive|round|level`: actions that need the delegate's acted decision (`--decision <id>`, same
|
|
23
|
+
grant, scope and block/file/finding, at most 30 minutes old, with the matching word: `waive`, `allow` or the level).
|
|
24
|
+
Waivers cover warnings and nits only (severity read from the signed review rows) and are written `by: autopilot`; each
|
|
25
|
+
opens one tracked GitHub issue in the project's repo. The block gate accepts an autopilot waiver only under a grant
|
|
26
|
+
and decision that covered it. One extra fix round per file per grant; the coder level comes from the Jev lane, capped
|
|
27
|
+
at the plan level + 1 and L2.
|
|
28
|
+
- Autopilot budget stop per category: with `--budget review=<usd>,coding=<usd>`, new sessions in a category are refused
|
|
29
|
+
once its spend since the grant started plus running reservations reaches `--stop-at` x cap ("autopilot paused: ...
|
|
30
|
+
waiting for the owner"), with one signed `autopilot.pause` row; `autopilot status` shows spend per category.
|
|
31
|
+
`code-forge autopilot approve --key --value --until` (owner only, in a terminal, no `--yes`) changes one setting until
|
|
32
|
+
a time and restores it automatically, crash-safe, with signed rows; a value changed by hand meanwhile is left alone.
|
|
33
|
+
While a grant is active, `run reload` refuses any limit key.
|
|
34
|
+
- `code-forge autopilot binnacle` and `autopilot log`: the logbook of an autopilot run, in the shape of an overnight-run
|
|
35
|
+
page (status at a glance, decisions with why and what would reverse them, blocks, open questions, actions only you can
|
|
36
|
+
take, incidents, timeline newest first) plus a full log of every autopilot event. As JSON or as
|
|
37
|
+
`autopilot-binnacle.md` / `autopilot-log.md` in the run dir, rewritten after each delegate decision and scrubbed.
|
|
38
|
+
`--link <https url>` stores the live page's link.
|
|
39
|
+
- Autopilot log page for your return: the skill (`skill/references/autopilot.md`) creates one Claude Docs doc per run
|
|
40
|
+
with a Binnacle tab (the title and byline, then 7 sections) and a Full log tab, stores its link first, updates only
|
|
41
|
+
the changed sections after each decision, block close or incident, and at stop adds the final rows and asks you to
|
|
42
|
+
review the open questions and your actions. `autopilot status` and `stop` print the link (or the Markdown file paths
|
|
43
|
+
without the Docs connector). Every owner stop in the skill says what autopilot may do there or that it is never
|
|
44
|
+
delegated. New `docs/autopilot.md`.
|
|
45
|
+
|
|
9
46
|
## [0.5.1] — 2026-10-04
|
|
10
47
|
|
|
11
48
|
### Changed
|
package/README.md
CHANGED
|
@@ -8,6 +8,18 @@ for cross-model, parallel, evidence-gated feature delivery — on Claude Code, C
|
|
|
8
8
|
> `examples/` have all landed (`docs/reference/blocks.json` lists every build block). What changed
|
|
9
9
|
> in each version is in [CHANGELOG.md](CHANGELOG.md).
|
|
10
10
|
|
|
11
|
+
## What's new (next release)
|
|
12
|
+
|
|
13
|
+
- **Autopilot.** Step away for up to 24 hours. `code-forge autopilot start` grants a delegate (a
|
|
14
|
+
fresh L2 or L3 session) a few of your decisions: waive a warning or a nit, one extra fix round,
|
|
15
|
+
the coder level. A fixed deny list keeps the rest yours: critical waivers, plan and design
|
|
16
|
+
approval, limits, budget raises, merges, destructive actions. Each category can pause at a
|
|
17
|
+
budget stop, and every answer is a signed ledger row.
|
|
18
|
+
- **A live log for your return.** In Claude Code the orchestrator keeps one Claude Docs page per
|
|
19
|
+
run with two tabs: Binnacle (the summary) and Full log (every event, newest first).
|
|
20
|
+
`autopilot status` and `autopilot stop` print its link; without the connector they print the two
|
|
21
|
+
Markdown files. See [docs/autopilot.md](docs/autopilot.md).
|
|
22
|
+
|
|
11
23
|
## What's new in 0.5
|
|
12
24
|
|
|
13
25
|
- **Parallel review.** The worker reviews `review.parallel_tickets` files at once (default 3), with
|
|
@@ -152,6 +164,7 @@ usage line.
|
|
|
152
164
|
| `upgrade` | `code-forge upgrade [--source <path>]` |
|
|
153
165
|
| `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 |
|
|
154
166
|
| `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` |
|
|
167
|
+
| `autopilot` | `code-forge autopilot start --run <id> --until <ISO-8601 with offset> --delegate <L2\|L3> --allow <scope,…> [--deny <scope,…>] [--budget <category>=<usd>,…] [--stop-at <0..1>] [--yes]` · `autopilot status\|stop --run <id>` (print the live log's link, or the two Markdown files) · `autopilot ask --run <id> --scope <scope> --question <text> [--options a,b,…] [--block <id>] [--file <path>] [--finding <id>] [--json]` · `autopilot waive\|round\|level … --decision <id>` · `autopilot approve --run <id> --key <dot.path> --value <json> --until <time>` (owner only, at a terminal) · `autopilot binnacle --run <id> [--json\|--markdown] [--link <https url>]` · `autopilot log --run <id> [--json\|--markdown]` — the owner's time-boxed grant to a delegate; see [docs/autopilot.md](docs/autopilot.md) |
|
|
155
168
|
| `help` / `version` | `code-forge --help` (or no verb) · `code-forge --version` |
|
|
156
169
|
|
|
157
170
|
`run`, `block`, `worker`, `spawn`, `s2`, `author`, `facts` and `review-file` are what the Agent
|
package/docs/README.md
CHANGED
|
@@ -14,6 +14,7 @@ disagree, the verb is right: each verb prints its own usage line when its argume
|
|
|
14
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
|
+
| 5b | [autopilot.md](autopilot.md) | step away while a run goes on: grant a delegate a few decisions for a set time, and review the live log (Binnacle and Full log) when you return |
|
|
17
18
|
| 6 | [examples/marketing-site/brief.md](examples/marketing-site/brief.md) | copy the brief the tutorial uses |
|
|
18
19
|
| 7 | [marketing.md](marketing.md) | read the product story: the problem, the promise, the honest limits |
|
|
19
20
|
|
|
@@ -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": 52,
|
|
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": {
|
|
@@ -606,6 +606,101 @@
|
|
|
606
606
|
"B43"
|
|
607
607
|
],
|
|
608
608
|
"note": "root-added 2026-10-03; plan plans/parallel-review (approved in plan mode)"
|
|
609
|
+
},
|
|
610
|
+
"B45": {
|
|
611
|
+
"title": "Autopilot grants: autopilot start/status/stop, scopes with a fixed deny list (incl. parents of limit keys), lazy expiry with signed grant/stop/expire rows; coders may not run autopilot",
|
|
612
|
+
"wave": 11,
|
|
613
|
+
"level": "L2",
|
|
614
|
+
"status": "landed",
|
|
615
|
+
"owned": [
|
|
616
|
+
"src/autopilot/scopes.mjs",
|
|
617
|
+
"src/autopilot/grant.mjs",
|
|
618
|
+
"src/cli/autopilot.mjs",
|
|
619
|
+
"test/cli/autopilot.test.mjs",
|
|
620
|
+
"test/autopilot/grant.test.mjs"
|
|
621
|
+
],
|
|
622
|
+
"depends_on": [
|
|
623
|
+
"B44"
|
|
624
|
+
],
|
|
625
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5), approved in plan mode"
|
|
626
|
+
},
|
|
627
|
+
"B46": {
|
|
628
|
+
"title": "Autopilot delegate: closed-book delegate role (never Codex, opt-in or not), askDelegate (grant first, one session, one signed autopilot.decision row; acts only with options, in scope, no escalation, confidence >= autopilot.min_confidence), autopilot ask, doctor delegate pings; autopilot.* is a limit key",
|
|
629
|
+
"wave": 11,
|
|
630
|
+
"level": "L2",
|
|
631
|
+
"status": "landed",
|
|
632
|
+
"owned": [
|
|
633
|
+
"src/autopilot/delegate.mjs",
|
|
634
|
+
"src/doctor/probes.mjs",
|
|
635
|
+
"test/autopilot/delegate.test.mjs"
|
|
636
|
+
],
|
|
637
|
+
"depends_on": [
|
|
638
|
+
"B45"
|
|
639
|
+
],
|
|
640
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5)"
|
|
641
|
+
},
|
|
642
|
+
"B47": {
|
|
643
|
+
"title": "Autopilot delegated actions, each on the delegate's acted decision with the matching word (waive / allow / the level): autopilot waive (warning or nit read from signed review rows, never critical or proof; tracked gh issue in the project repo, exact-marker dedupe; no gh => waiver stands + autopilot.issue_failed), gate accepts by:autopilot waivers only under a covering grant and decision, autopilot round (one extra fix round per file per grant), autopilot level (lane capped at plan + 1, max L2; block open uses it); re-checked under the run lock before writing",
|
|
644
|
+
"wave": 11,
|
|
645
|
+
"level": "L2",
|
|
646
|
+
"status": "landed",
|
|
647
|
+
"owned": [
|
|
648
|
+
"src/autopilot/actions.mjs",
|
|
649
|
+
"src/review/gate-check.mjs",
|
|
650
|
+
"src/util/gh.mjs",
|
|
651
|
+
"test/autopilot/actions.test.mjs"
|
|
652
|
+
],
|
|
653
|
+
"depends_on": [
|
|
654
|
+
"B46"
|
|
655
|
+
],
|
|
656
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5); also amends src/autopilot/delegate.mjs, src/cli/autopilot.mjs, src/cli/block.mjs, src/cli/logs.mjs, src/review/fixloop.mjs, src/worker/engine.mjs"
|
|
657
|
+
},
|
|
658
|
+
"B48": {
|
|
659
|
+
"title": "Autopilot budget stop per category (review/coding caps at --stop-at, refused at the spawn budget gate under the B41 lock, one signed autopilot.pause row per category per grant, grantFor paused, status spend) and expiring owner approvals (autopilot approve: terminal only, no --yes, fixed keys and __proto__/constructor/prototype refused, applied through the run reload path, signed approve/restore/restore_skipped rows, crash-safe lazy restore at autopilot, block and worker drain); run reload refuses limit keys while a grant is active",
|
|
660
|
+
"wave": 11,
|
|
661
|
+
"level": "L2",
|
|
662
|
+
"status": "landed",
|
|
663
|
+
"owned": [
|
|
664
|
+
"src/autopilot/limits.mjs",
|
|
665
|
+
"src/session/spawn.mjs",
|
|
666
|
+
"src/worker/loop.mjs",
|
|
667
|
+
"src/cli/block.mjs",
|
|
668
|
+
"src/cli/run.mjs",
|
|
669
|
+
"test/autopilot/expiry.test.mjs"
|
|
670
|
+
],
|
|
671
|
+
"depends_on": [
|
|
672
|
+
"B47"
|
|
673
|
+
],
|
|
674
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5); also amends src/autopilot/grant.mjs, src/autopilot/scopes.mjs, src/cli/autopilot.mjs, src/state/run.mjs (reloadRun guard), src/config/load.mjs (slugFor moved from cli/run.mjs), src/cli/{author,facts,jev,plan,s2,spawn}.mjs (slugFor import), test/cli/autopilot.test.mjs"
|
|
675
|
+
},
|
|
676
|
+
"B49a": {
|
|
677
|
+
"title": "Autopilot binnacle and full log: autopilot binnacle builds the owner's 8-section logbook (status at a glance, decisions with why and reversal, blocks, open questions, actions only the owner can take, incidents, timeline) and autopilot log lists every autopilot row, as JSON or Markdown files in the run dir (rewritten after each decision, scrubbed with the workspace as <project>); --link stores the live page link with a signed row",
|
|
678
|
+
"wave": 11,
|
|
679
|
+
"level": "L1",
|
|
680
|
+
"status": "landed",
|
|
681
|
+
"owned": [
|
|
682
|
+
"src/autopilot/binnacle.mjs",
|
|
683
|
+
"test/autopilot/binnacle.test.mjs"
|
|
684
|
+
],
|
|
685
|
+
"depends_on": [
|
|
686
|
+
"B48"
|
|
687
|
+
],
|
|
688
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5); also amends src/autopilot/delegate.mjs (refresh hook), src/cli/autopilot.mjs"
|
|
689
|
+
},
|
|
690
|
+
"B49b": {
|
|
691
|
+
"title": "Autopilot live log artifact and skill text: skill/references/autopilot.md (one Claude Docs doc per run with a Binnacle tab - title and byline, then 7 sections - and a Full log tab; link stored first; only changed sections updated; stop adds the final rows and asks the owner to review), Autopilot notes at every owner stop, the never-delegated list, autopilot status/stop print the link or the Markdown paths, docs/autopilot.md, README, concepts",
|
|
692
|
+
"wave": 11,
|
|
693
|
+
"level": "L2",
|
|
694
|
+
"status": "landed",
|
|
695
|
+
"owned": [
|
|
696
|
+
"skill/references/autopilot.md",
|
|
697
|
+
"docs/autopilot.md",
|
|
698
|
+
"test/skill/structure.test.mjs"
|
|
699
|
+
],
|
|
700
|
+
"depends_on": [
|
|
701
|
+
"B49a"
|
|
702
|
+
],
|
|
703
|
+
"note": "root-added 2026-10-06; plan plans/autopilot (issue #5); also amends src/cli/autopilot.mjs, skill/SKILL.md, skill/references/{decisions,review,harden,plan,code}.md, skill/references/adapters/claude-code.md, README.md, docs/README.md, docs/concepts.md, docs/getting-started.md"
|
|
609
704
|
}
|
|
610
705
|
}
|
|
611
706
|
}
|
package/docs/reference/config.md
CHANGED
|
@@ -171,4 +171,6 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
171
171
|
| `keys.<key>` | string | | — | user-defined key |
|
|
172
172
|
| `tmp` | object | | — | |
|
|
173
173
|
| `tmp.root` | string \| null | | `null` | |
|
|
174
|
+
| `autopilot` | object | | — | |
|
|
175
|
+
| `autopilot.min_confidence` | number | | `0.7` | min 0; max 1; B46: the lowest confidence at which the autopilot delegate's answer is acted on; below it the question goes to the owner. |
|
|
174
176
|
| `telemetry` | const `"off"` | | `"off"` | |
|
package/package.json
CHANGED
|
@@ -306,6 +306,13 @@
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
},
|
|
309
|
+
"autopilot": {
|
|
310
|
+
"type": "object",
|
|
311
|
+
"additionalProperties": false,
|
|
312
|
+
"properties": {
|
|
313
|
+
"min_confidence": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.7, "description": "B46: the lowest confidence at which the autopilot delegate's answer is acted on; below it the question goes to the owner." }
|
|
314
|
+
}
|
|
315
|
+
},
|
|
309
316
|
"telemetry": { "type": "string", "const": "off", "default": "off" }
|
|
310
317
|
},
|
|
311
318
|
"$defs": {
|
package/skill/SKILL.md
CHANGED
|
@@ -77,4 +77,5 @@ State lives in the plan file's header — `facts → planned → hardened → co
|
|
|
77
77
|
| takeover, base moves | `references/continuity.md` |
|
|
78
78
|
| no Solo, no subagent tool, a level unavailable | `references/degraded.md` |
|
|
79
79
|
| keys, the forbidden list, signed rows and their limit | `references/security.md` |
|
|
80
|
+
| the owner is away: an autopilot grant, the delegate, the live log doc | `references/autopilot.md` |
|
|
80
81
|
| spawning coders per engine | `references/adapters/solo.md`, `references/adapters/claude-code.md`, `references/adapters/subprocess.md` |
|
|
@@ -21,3 +21,17 @@ The plan goes to the owner through plan mode (`plan.md` §4.1): `EnterPlanMode`
|
|
|
21
21
|
## §3 What is lost and what is not
|
|
22
22
|
|
|
23
23
|
Lost: live observation of the coder (only the progress log and the final report), a resumable transcript (a lost subagent is re-dispatched with the fix history in a new brief — `continuity.md` §2). Not lost: session isolation, signed rows, the gate, the ladder, the facts rule, the convergence rule (`degraded.md` §2).
|
|
24
|
+
|
|
25
|
+
## §4 Autopilot — the live log doc (Claude Docs connector)
|
|
26
|
+
|
|
27
|
+
At `forge autopilot start` (`autopilot.md` §1) the run gets ONE doc through the Claude Docs connector. Follow the connector's own guide (`guide` → `topic.index`, `topic.tabs`). The steps:
|
|
28
|
+
|
|
29
|
+
0. **One doc per run:** `forge autopilot status --run <r>` first. A link there ⇒ the doc exists (a lost session left it): continue in it from step 5, never birth a second one.
|
|
30
|
+
1. **Birth, one `batch`:** a new doc named `<project> autopilot run — <date>`. The main tab **Binnacle** follows `forge autopilot binnacle --run <r> --json`: the title and byline, then 7 sections: Status at a glance, Decisions, Blocks, Open questions, Actions only you can take, Incidents, Timeline — one `pending` block per section. A second tab **Full log** is born in the same batch with one `pending` block for its table. The last member places both: Binnacle `order "a0"`, Full log `order "a1"`.
|
|
31
|
+
2. **Store the link at once,** from the birth ack: `forge autopilot binnacle --run <r> --link <url>`.
|
|
32
|
+
3. **Open it** with the Artifact tool's `open` action and that link (no `open` action: give the link in your next message, once).
|
|
33
|
+
4. **Fill one section per `update`**, in reading order: replace each Binnacle pending block with `## <heading>` and its table or list from the JSON; then the Full log tab's pending block with one pipe table from `forge autopilot log --run <r> --json`, newest first.
|
|
34
|
+
5. **During the window:** after each decision, block close or incident, one `update` per changed section — insert the new Decisions row, insert the new Timeline row at the top, replace only the Status cells that changed — and insert the new rows at the top of the Full log table. Never resend the whole doc. A refused edit (`guard_mismatch`, `find_none`) means the owner edited it: re-read that section, keep their edit, apply only the new row(s); never `force`.
|
|
35
|
+
6. **At stop:** after `forge autopilot stop --run <r>`, insert the stop event as the newest Timeline row and the newest Full log row, then replace the Status at a glance section with the final values. The doc stays as the run's record. Tell the owner in chat: the link, and "review Open questions and Actions only you can take before work resumes".
|
|
36
|
+
|
|
37
|
+
No Claude Docs connector: skip the doc. The Markdown files in the run dir are the record, and `status` and `stop` print their paths (`autopilot.md` §4).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Autopilot — the owner steps away; a delegate decides inside a grant; one live doc records it all
|
|
2
|
+
|
|
3
|
+
Autopilot lets the owner leave for a set time. A delegate (a fresh L2 or L3 session) answers some owner questions inside a time-boxed grant. Everything it does is a signed ledger row, and one live doc shows it. You start nothing on your own: autopilot exists only when the owner asks for it.
|
|
4
|
+
|
|
5
|
+
## §1 Start — only after the owner asks
|
|
6
|
+
|
|
7
|
+
1. The owner asks for autopilot and names the window, the delegate level and the scopes. Run `forge autopilot start --run <r> --until <ISO-8601 with offset> --delegate <L2|L3> --allow <scope,…> [--deny <scope,…>] [--budget <category>=<usd>,…] [--stop-at <0..1>]`. The owner confirms it at the prompt. Never pass `--yes` unless the owner said so in chat.
|
|
8
|
+
2. **One doc per run.** First run `forge autopilot status --run <r>`: a link there means the doc exists (a lost session left it) — continue in it, never create a second doc for the same run. No link: create ONE Claude Docs doc titled `<project> autopilot run — <date>` with two tabs, born in one call (the exact steps: `adapters/claude-code.md` §4).
|
|
9
|
+
- **Binnacle** (the main tab): its outline is `forge autopilot binnacle --run <r> --json` — the title and byline, then 7 sections: Status at a glance, Decisions, Blocks, Open questions, Actions only you can take, Incidents, Timeline. One pending block per section.
|
|
10
|
+
- **Full log**: one table from `forge autopilot log --run <r> --json` — Time, Event, Block, File, Detail, Link — newest first. One pending block for it.
|
|
11
|
+
3. **Store the link first**, right after the birth (its ack gives the link): `forge autopilot binnacle --run <r> --link <url>`. From now on `forge autopilot status` and `forge autopilot stop` print it.
|
|
12
|
+
4. Open the doc for the owner, then fill one section per call, in reading order: the 7 Binnacle sections, then the Full log table. Never write the whole doc in one call.
|
|
13
|
+
|
|
14
|
+
## §2 During the window
|
|
15
|
+
|
|
16
|
+
- **Every owner-level question goes to the delegate first**: `forge autopilot ask --run <r> --scope <scope> --question <text> --options <words> [--block <id>] [--file <path>] [--finding <id>]`. Use the fixed option words, or the action will refuse the answer: a waiver `waive,fix` · an extra round `allow,deny` · a coder level the candidate levels, e.g. `L1,L2`.
|
|
17
|
+
- **Act only when it acted** (exit 0): run the action with `--decision <id>` from the answer — `forge autopilot waive|round|level … --decision <id>`. Exit 3 means the question goes to the owner: leave it open, it shows under Open questions. Exit 1 means the grant refused it: also the owner's.
|
|
18
|
+
- **A paused category** (`autopilot paused: … waiting for the owner`): wait. Never raise the cap, never route around it.
|
|
19
|
+
- **Keep the doc current — only what changed.** After every decision, block close or incident: re-read `forge autopilot binnacle --run <r> --json` and `forge autopilot log --run <r> --json`, then
|
|
20
|
+
- append the new row to the Binnacle's Decisions table;
|
|
21
|
+
- put the new row at the top of the Timeline (newest first);
|
|
22
|
+
- update the Status at a glance cells that changed (and Blocks, Open questions, Actions or Incidents when they changed);
|
|
23
|
+
- add the new rows to the Full log tab's table, at the top (it is newest first too).
|
|
24
|
+
Never rewrite the whole doc and never replace a section that did not change.
|
|
25
|
+
- **A refused edit** (`guard_mismatch`, `find_none`) means the owner edited that section: re-read it, keep the owner's edit, and apply only the new row(s). Never force. Answer an owner's comment in its own thread.
|
|
26
|
+
- **A lost session:** the next one reads the link from `forge autopilot status --run <r>` and continues in the same doc.
|
|
27
|
+
|
|
28
|
+
## §3 Stop — at the owner's return or `until`
|
|
29
|
+
|
|
30
|
+
1. `forge autopilot stop --run <r>` when the owner is back (at `until` the grant expires by itself; `forge autopilot status --run <r>` then says so).
|
|
31
|
+
2. Add the stop (or expiry) event as the newest Timeline row and the newest Full log row, then write the final Status at a glance (the window's end, the result, the spend). Leave the doc as the record of the run; do not delete or move it.
|
|
32
|
+
3. Tell the owner in chat: the link, and "review Open questions and Actions only you can take before work resumes".
|
|
33
|
+
|
|
34
|
+
## §4 Without the Docs connector
|
|
35
|
+
|
|
36
|
+
Another harness, or the connector is missing: the two Markdown files in the run dir are the record. At start, run `forge autopilot binnacle --run <r> --markdown` once: it creates `autopilot-binnacle.md` and `autopilot-log.md`; print both paths for the owner. After that the CLI rewrites both files by itself, after every delegate decision and at every `forge autopilot status` and `forge autopilot stop`, and those two commands print both paths. At stop, tell the owner the two paths and the same review line as §3.
|
|
37
|
+
|
|
38
|
+
## §5 Never delegated — always the owner
|
|
39
|
+
|
|
40
|
+
These never go to the delegate, whatever the grant says (the CLI's fixed deny list refuses them too):
|
|
41
|
+
|
|
42
|
+
- plan approval (`plan.md` §4.1) and design approval;
|
|
43
|
+
- a budget raise (`code.md` §6, `review.md` §7);
|
|
44
|
+
- a threshold edit or any other limit or rule change — only the owner's own `forge autopilot approve` at a terminal;
|
|
45
|
+
- a critical waiver, a proof waiver, or closing a block without its reviews;
|
|
46
|
+
- merges and destructive actions.
|
|
47
|
+
|
|
48
|
+
When one of these comes up during the window: stop that line of work, add it to Actions only you can take, and wait.
|
package/skill/references/code.md
CHANGED
|
@@ -45,7 +45,7 @@ The coder's report is a claim sheet. The gate reproduces each number in the meas
|
|
|
45
45
|
|
|
46
46
|
## §6 Budget — the stop is the feature (R6)
|
|
47
47
|
|
|
48
|
-
`budget.block_lines` and `budget.block_cases` bind the plan; the gate's 1.25 × stop binds the block. A coder that overruns and stops before expanding did the right thing: never compress or defer coverage to fit. One raise per run, by the human, logged; a second overrun in the same run re-decomposes at the architect level. A post-acceptance ruling that adds required lines re-baselines the cap at ruling time, priced from the assertions it orders; a STOP defined mid-turn binds from the coder's next reported boundary. A coder never trims to fit; landing exactly on a cap is a tell that is checked. Review tokens count toward `budget.block_tokens_soft` / `budget.block_tokens_hard` (`review.md` §7).
|
|
48
|
+
`budget.block_lines` and `budget.block_cases` bind the plan; the gate's 1.25 × stop binds the block. A coder that overruns and stops before expanding did the right thing: never compress or defer coverage to fit. One raise per run, by the human, logged; a second overrun in the same run re-decomposes at the architect level. **Autopilot:** a budget raise is never delegated, and neither is `--no-require-reviews` or a merge (`autopilot.md` §5). A post-acceptance ruling that adds required lines re-baselines the cap at ruling time, priced from the assertions it orders; a STOP defined mid-turn binds from the coder's next reported boundary. A coder never trims to fit; landing exactly on a cap is a tell that is checked. Review tokens count toward `budget.block_tokens_soft` / `budget.block_tokens_hard` (`review.md` §7).
|
|
49
49
|
|
|
50
50
|
## §7 The PR contract — a draft PR only after independent review
|
|
51
51
|
|
|
@@ -51,3 +51,5 @@ A fresh L3 session receives the failure evidence — the last attempt's diff, th
|
|
|
51
51
|
## §7 What reaches the human
|
|
52
52
|
|
|
53
53
|
`next = stop`, `review.over_budget`, an orphan file, `worker_down`, `review_cap`, `redecompose`, `ask_human`, a security question, consensus unavailable, and one budget raise per run. Everything else is decided by S1, S2 or the rules above and recorded.
|
|
54
|
+
|
|
55
|
+
**Autopilot:** while a grant is active, a warning or nit waiver, one extra round at `review_cap` and a coder level go first to the delegate (`forge autopilot ask`, then `forge autopilot waive|round|level --decision <id>` only when it acted, `autopilot.md` §2). Never delegated: `next = stop`, `ask_human`, a security question, a critical finding, a budget raise, `redecompose` — they wait for the owner (`autopilot.md` §5).
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
`forge author --job harden --brief <brief> --facts <sheet> --draft <plan> [--answers <file>] --out <plan>` runs a fresh L3 closed-book session over the brief, the facts sheet, the current draft and the answers so far. It returns `{draft, questions: [{id, question, options[], why, blocking}], cost}`.
|
|
6
6
|
|
|
7
|
-
Loop: write the draft to the plan file → print `questions[]` to the human in chat (and to the Solo scratchpad when present) → collect answers into `<answers file>` → re-run with `--draft` and `--answers`. Stop when **no blocking question is left**: `questions[]` is empty, or every remaining item is non-blocking and the human chose to skip it — a skipped question is written into the plan's Q&A as `skipped` with the human's word, never silently dropped. Each round prints its cost. **The human answers; the orchestrator never answers for them.** Under Solo the human may run harden as an interactive L3 session (`harness.solo.interactive_harden`).
|
|
7
|
+
Loop: write the draft to the plan file → print `questions[]` to the human in chat (and to the Solo scratchpad when present) → collect answers into `<answers file>` → re-run with `--draft` and `--answers`. Stop when **no blocking question is left**: `questions[]` is empty, or every remaining item is non-blocking and the human chose to skip it — a skipped question is written into the plan's Q&A as `skipped` with the human's word, never silently dropped. Each round prints its cost. **The human answers; the orchestrator never answers for them.** **Autopilot:** never delegated — harden questions wait for the owner, grant or not (`autopilot.md` §5). Under Solo the human may run harden as an interactive L3 session (`harness.solo.interactive_harden`).
|
|
8
8
|
|
|
9
9
|
## §2 What the L3 session interrogates (so you can judge its questions)
|
|
10
10
|
|
package/skill/references/plan.md
CHANGED
|
@@ -47,6 +47,8 @@ A plan that passed `forge plan check` still needs the owner's yes before any blo
|
|
|
47
47
|
|
|
48
48
|
Never treat a chat summary of the plan as the approval step, and never start `forge block open` before it.
|
|
49
49
|
|
|
50
|
+
**Autopilot:** plan approval is never delegated. Under a grant the plan waits for the owner (`autopilot.md` §5).
|
|
51
|
+
|
|
50
52
|
## §5 Cost
|
|
51
53
|
|
|
52
54
|
One L0 session per plan for the facts (typically a claim list of 40–80 items) and one L3 session per author round; `forge report --slug <slug>` shows both as `facts $` and coder/review splits.
|
|
@@ -30,7 +30,7 @@ Per file, per block:
|
|
|
30
30
|
3. **Strictly shrinking**: the open `fix_now` set after round n is smaller than after round n−1, counting closures minus new in-hunk findings. Equal or larger ⇒ `review_stall` (rule 2b), a trigger at once.
|
|
31
31
|
3a. **Heavy rounds climb at once** (`review_warnings`, `decisions.md` §5 rule 3a): below L2, a round — round 1 included — that leaves ≥ `escalation.warning_threshold` (2) warnings or any `critical` open, `escalation.after_rounds_with_warnings` (1) times at the current level, climbs one level for the next fix. One round with a stronger model is faster and cheaper than three with a cheap one. The per-file cap (step 5) stays the outer limit.
|
|
32
32
|
4. **Ladder**: the running ceiling is `min(L2, escalation.stop_at)` — L3 is never a *running* level. A trigger — rule 1 (`retries`), rule 2 (`escalation.review_rounds_per_level` exhausted with an open `fix_now`), rule 2b (`review_stall`) or step 3a (`review_warnings`) — below the ceiling climbs one level, coded by a fresh session with the open findings and the fix history in its brief (an L1 block's rounds 3–4 run at L2). At the ceiling — an L2 block, or an L1 block that has climbed to L2 — it takes the **L3 rung**: a patch ≤ 80 lines, owned files only, reviewed as a `patch_check` round outside the cap. Under `escalation.l3_mode: code` (opt-in) the rung is instead one L3 coding turn. Either way the rung fires **once per block** and the same post-patch order follows it. After it, in order: `patch_check` clean ⇒ complete; open set not smaller than before the patch ⇒ `stopped: l3_patch_exhausted` (`review_stall`); round ≥ `review.max_rounds_per_file` ⇒ `stopped: review_cap`; otherwise the fixes continue at L2 with `rounds_at_level` reset and the patch in the brief. Any later trigger in that block stops with its named reason (`l3_patch_exhausted`, `review_cap`) and never patches again.
|
|
33
|
-
5. **Cap — four rounds per file** (`review.max_rounds_per_file`, default 4, range 2–6). Round 4 still open ⇒ the L3 rung if the block has not used it (same post-patch order as step 4), else `stopped: review_cap`. A stop means the block cannot close, the ledger lists the open findings, and the human decides — fix by hand, `forge block waive <id> <finding-id> --run <r> --file <path> --reason <text>` (a signed `review.waived` row, `by: human`), or re-decompose. The coder never sees a `waive` verb; it is on the forbidden list.
|
|
33
|
+
5. **Cap — four rounds per file** (`review.max_rounds_per_file`, default 4, range 2–6). Round 4 still open ⇒ the L3 rung if the block has not used it (same post-patch order as step 4), else `stopped: review_cap`. A stop means the block cannot close, the ledger lists the open findings, and the human decides — fix by hand, `forge block waive <id> <finding-id> --run <r> --file <path> --reason <text>` (a signed `review.waived` row, `by: human`), or re-decompose. The coder never sees a `waive` verb; it is on the forbidden list. **Autopilot:** under a grant, a warning or nit finding may be waived by the delegate (`forge autopilot waive … --decision <id>`, written `by: autopilot`) and a file at the cap may get one extra round (`forge autopilot round`); a critical or proof waiver is never delegated (`autopilot.md`).
|
|
34
34
|
6. **Block-close sweep**: `forge block close` batches the `late_findings` per file to one L3 judge ruling (`fix_now | nit`); a `fix_now` opens a round on that file at the block's current level and counts toward its cap.
|
|
35
35
|
7. Ledger: one `review.round` row per round with `open_before`, `closed`, `new_in_hunks`, `late`, `open_after`; `forge report` prints rounds per file and rounds that stalled.
|
|
36
36
|
|
|
@@ -42,7 +42,7 @@ Two L2 reviewers, one per effective provider (`resolve(L2)` and `review.second_l
|
|
|
42
42
|
|
|
43
43
|
## §7 The review budget per block
|
|
44
44
|
|
|
45
|
-
`review.block_budget_tokens` (and optionally `review.block_budget_usd`) bounds every review, recheck, judge and S2 session made for the block. When the forecast exceeds it the worker degrades one step at a time, cheapest first: batch small files of one tier into one packet (`review.batch_small_files`) → one judge per block instead of per file → standard band `full` → `quick` → high tier `A + B + judge` → one `full` L2 + judge, the floor. Tools-only is never a review; a light `quick` stays `quick`. Still over ⇒ `review.over_budget`: raise the budget once per run (a config edit by the human, on record) or split the block — never silently, never below the floors. The ledger keeps `depth_unconstrained` and `depth_chosen` per file so `forge report` can show `missed_after_degrade`.
|
|
45
|
+
`review.block_budget_tokens` (and optionally `review.block_budget_usd`) bounds every review, recheck, judge and S2 session made for the block. When the forecast exceeds it the worker degrades one step at a time, cheapest first: batch small files of one tier into one packet (`review.batch_small_files`) → one judge per block instead of per file → standard band `full` → `quick` → high tier `A + B + judge` → one `full` L2 + judge, the floor. Tools-only is never a review; a light `quick` stays `quick`. Still over ⇒ `review.over_budget`: raise the budget once per run (a config edit by the human, on record) or split the block — never silently, never below the floors. **Autopilot:** a budget raise is never delegated; a paused category waits for the owner (`autopilot.md` §5). The ledger keeps `depth_unconstrained` and `depth_chosen` per file so `forge report` can show `missed_after_degrade`.
|
|
46
46
|
|
|
47
47
|
## §7a Parallel tickets
|
|
48
48
|
|
package/skill/scripts/forge
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# copied install with no package next to it); `test/skill/shim.test.mjs` asserts the pin
|
|
11
11
|
# equals package.json's version.
|
|
12
12
|
# The shim holds no logic of its own: every verb, flag and message is the CLI's.
|
|
13
|
-
PINNED_VERSION="0.
|
|
13
|
+
PINNED_VERSION="0.6.0"
|
|
14
14
|
set -eu
|
|
15
15
|
|
|
16
16
|
self="$0"
|