diff --git a/README.ja.md b/README.ja.md index e7c5192b30..fdf77b7171 100644 --- a/README.ja.md +++ b/README.ja.md @@ -50,6 +50,7 @@ - **[10の標準スコープ](docs/guide/05-scopes-and-depth.ja.md)**(enterprise から workshop まで)+ 自由記述からの自動検出、そしてタスクに合わせた EXECUTE/SKIP 計画を提案し、承認された計画を再利用可能な composed スコープとして登録する **adaptive composer** - **[3段階の depth と 3段階の test strategy](docs/guide/05-scopes-and-depth.ja.md)** — 成果物の詳細度とテスト量を独立に制御 - **[全ステージの承認ゲート](docs/guide/07-interaction-modes.ja.md)** — エンジンが強制。1問ずつからファストトラックまでのインタラクションモード +- **[Intent autonomy](docs/reference/24-intent-autonomy.ja.md)** — 1つの Intent をどこまで自律実行してよいかを `/amadeus --autonomy ` で宣言(Intent を誕生させる起動でも有効)。`full` は人間によるグラント儀式が別途必要で、無人での裁定はすべてレビュー用に記録されます - **[スペースと intent](docs/guide/03-spaces-and-intents.ja.md)** — intent ごとの記録、チームごとのスペース、すべてリポジトリでバージョン管理 - **[ルールと学習ループ](docs/guide/09-rules-and-the-learning-loop.ja.md)** — 人間の是正が層状のメソッドルールとして永続化。矛盾を拒否する admission check 付き - **[2層のナレッジ](docs/guide/08-knowledge.ja.md)** — メソドロジー知識はフレームワークに同梱、チーム・ドメイン知識はワークスペースに蓄積 diff --git a/README.md b/README.md index 0575a35a13..a90c60ebda 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ At every stage the leading agent produces reviewable artifacts under the `amadeu - **[10 stock scopes](docs/guide/05-scopes-and-depth.md)** (enterprise through workshop) with auto-detection from freeform intent, plus the **[adaptive composer](docs/guide/05-scopes-and-depth.md#the-adaptive-composer)** that proposes a tailored EXECUTE/SKIP plan from your task — and registers approved plans as reusable composed scopes - **[3 depth levels](docs/guide/05-scopes-and-depth.md#the-3-depth-levels)** and **[3 test-strategy levels](docs/guide/05-scopes-and-depth.md#the-3-test-strategy-levels)** — artifact detail and test volume, controlled independently - **[Approval gates at every stage](docs/guide/07-interaction-modes.md)** — enforced by the engine, with interaction modes from question-by-question to fast-track +- **[Intent autonomy](docs/reference/24-intent-autonomy.md)** — declare how autonomously one Intent may run with `/amadeus --autonomy ` (it applies on the launch that births the Intent); `full` still requires the human grant ceremony, and every unattended ruling is recorded for review - **[Spaces and intents](docs/guide/03-spaces-and-intents.md)** — per-intent records, per-team spaces, everything version-controlled in your repo - **[Rules and a learning loop](docs/guide/09-rules-and-the-learning-loop.md)** — human corrections persist as layered method rules, guarded by an admission check that rejects contradictions - **[Two-tier knowledge](docs/guide/08-knowledge.md)** — methodology knowledge ships with the framework; team and domain knowledge accumulates in your workspace diff --git a/docs/reference/24-intent-autonomy.ja.md b/docs/reference/24-intent-autonomy.ja.md index 445b22d5f8..74694a6365 100644 --- a/docs/reference/24-intent-autonomy.ja.md +++ b/docs/reference/24-intent-autonomy.ja.md @@ -22,7 +22,7 @@ harness registry です。監査イベントの表と各イベントの emitter | モード | 人間なしで裁定できる範囲 | | --- | --- | | `none` | なし。すべてのゲートと質問が `human-required` です。 | -| `semi` | 内部ステージゲートのみ。phase boundary でないステージゲートに限り、かつモード自体が人間コマンドで設定されている場合だけです。 | +| `semi` | 内部ステージゲートとステージ質問。phase boundary でないステージゲートと、phase boundary で提起されたものでない `question` に限り、かつモード自体が人間コマンドで設定されている場合だけです。 | | `full` | 現在のグラントの scope が許す範囲。 | `none` が既定であり、legacy または読解不能な projection の着地先でもあります。 @@ -39,6 +39,32 @@ bun .claude/tools/amadeus-bolt.ts set-autonomy --mode full \ --confirmed-display-digest sha256:... ``` +### 起動時にモードを宣言する + +`set-autonomy` は正準の記録経路ですが、Intent が既に存在していることを前提とします。 +`--autonomy ` は同じ宣言を起動の一部として記録します。Intent を +誕生させる起動でも有効です。 + +```sh +/amadeus --autonomy semi 公開 API にレート制限を追加する +/amadeus --autonomy none +``` + +このフラグは記録の**手段**を追加するものであり、権限の出所ではありません。受理 +されるのは**最初の**宣言のときだけ — モードの provenance がまだ `system-default` +である間に限られる — ため、人間が既に設定したモードを上書きすることはできません。 +同じモードを再指定した場合は no-op、異なるモードを指定した場合は拒否され +`set-autonomy` を案内します。`none` と `semi` は唯一の正準書込経路を通ります。 +誕生直後の Intent には引用できる自身の監査履歴がないため、宣言は起動時のキー +ストロークの human turn へ束縛されます。実 human turn を伴わない起動は明示的に +拒否され、Intent はモード未設定のまま成立し、最初の宣言は依然として可能なままです。 + +`--autonomy full` は受理されますが適用されることはありません。`full` の付与は上記の +儀式そのものであり、起動フラグがそれを代替することはできません。実行はグラントを +発行する2つのコマンドを表示してそこで停止します。アクティブなグラントがある状態で +`none` を求める起動も同様に拒否されます。グラントの取消はフラグの副作用ではなく +意図的な行為だからです。 + グラントはグローバルなスイッチではありません。Intent uuid、発行時点の scope / norm fingerprint、対象となる対話種別(`stage-gate`・`phase-gate`・ `walking-skeleton`・`question`)、明示的に禁止する effect 分類を持つ scope diff --git a/docs/reference/24-intent-autonomy.md b/docs/reference/24-intent-autonomy.md index 421287060d..40b9c4e40d 100644 --- a/docs/reference/24-intent-autonomy.md +++ b/docs/reference/24-intent-autonomy.md @@ -23,7 +23,7 @@ The mode is one of three values, held on the Intent's autonomy projection | Mode | What may be decided without a human | | --- | --- | | `none` | Nothing. Every gate and question is `human-required`. | -| `semi` | Internal stage gates only — a stage gate that is not a phase boundary, and only when the mode itself was set by a human command. | +| `semi` | Internal stage gates and stage questions — a stage gate that is not a phase boundary, plus a `question` that is not raised at one, and only when the mode itself was set by a human command. | | `full` | Whatever the current grant's scope allows. | `none` is the default, and it is also where a legacy or unreadable projection @@ -41,6 +41,33 @@ bun .claude/tools/amadeus-bolt.ts set-autonomy --mode full \ --confirmed-display-digest sha256:... ``` +### Declaring the mode at launch + +`set-autonomy` is the canonical recording path, but it needs an Intent to already +exist. `--autonomy ` records the same declaration as part of the +invocation, including the invocation that births the Intent: + +```sh +/amadeus --autonomy semi Add rate limiting to the public API +/amadeus --autonomy none +``` + +The flag is an additional recording *means*, never a source of authority. It is +accepted only as the **first** declaration — while the mode's provenance is still +`system-default` — so it can never overwrite a mode a human already set; re-state +the same mode and it is a no-op, name a different one and the run is refused and +points at `set-autonomy`. `none` and `semi` go through the one canonical write +path, and because a freshly born Intent has no audit history of its own to cite, +the declaration is bound to the launching keystroke's human turn: a launch that +carries no real human turn is refused loudly, the Intent stands with its mode +unset, and the first declaration is still available. + +`--autonomy full` is accepted but never applied. Granting `full` is the ceremony +above, and a launch flag may not stand in for it: the run reports the two +commands that issue a grant and stops there. A launch that also revokes — asking +for `none` while an active grant exists — is likewise refused, because revoking a +grant is a deliberate act rather than the side effect of a flag. + A grant is not a global switch. It carries a scope descriptor naming the Intent uuid, the scope and norm fingerprints it was issued against, the interaction kinds it covers (`stage-gate`, `phase-gate`, `walking-skeleton`, `question`), diff --git a/packages/framework/core/amadeus-common/protocols/stage-protocol.md b/packages/framework/core/amadeus-common/protocols/stage-protocol.md index 7b1365673d..c6d0fe9535 100644 --- a/packages/framework/core/amadeus-common/protocols/stage-protocol.md +++ b/packages/framework/core/amadeus-common/protocols/stage-protocol.md @@ -134,6 +134,8 @@ Quality failure is never approval. In `semi` and `full`, the conductor writes th For a question under `full`, the conductor writes the normalized question, stable option IDs, applicable norm/history facts, recommendation, and (when available) the native solo-election result to a machine-local JSON carrier, then runs `amadeus-bolt decide-question --input `. Use the returned `decided.effect.optionId` as the answer and record it in the questions file; `parked` is a hard stop, and any `human-required`, `conflict`, or `aborted` result fails closed. The user is never asked to author JSON. When no election result is available, the Core records loud degradation before using the recommendation. +For a question under `semi`, the conductor runs the **same** `amadeus-bolt decide-question --input ` procedure, unchanged — the carrier shape, the five-rung ladder, the `decided.effect.optionId` answer, the loud degradation when no election result exists, the hard stop on `parked`, and the fail-closed handling of `human-required` / `conflict` / `aborted` are identical. Two things differ, and neither is a step of the procedure: the authorization basis is the semi-scoped one (`semi` holds no Intent grant, so the current grant stays null), and pre-decision policies reach the ladder through `--policies-file` as confirmed-policy material rather than through a grant. Under `semi`, therefore, do **not** put a stage question to the human directly: `decide-question` is the route, and a `human-required` result is what sends the question to a person. Milestones are unaffected — a phase boundary, the walking skeleton, and Intent completion still require a human under `semi`. + **Halt-and-ask on failure** When a Bolt's code-generation returns failure, **always halt regardless of autonomy mode** — the Bolt never proceeds on its own. This is the one case where `autonomous` mode stops to consult. Halting is unconditional; who rules on the halt is decided by the solo auto-election hook below, which names the one branch that does not present the prompt. diff --git a/packages/framework/core/tools/amadeus-utility.ts b/packages/framework/core/tools/amadeus-utility.ts index 77e08005ce..6c36a0a8ac 100644 --- a/packages/framework/core/tools/amadeus-utility.ts +++ b/packages/framework/core/tools/amadeus-utility.ts @@ -262,6 +262,7 @@ Utilities: --scope Set or change scope (standalone or with --stage/--phase) --depth Override depth (minimal, standard, comprehensive) --test-strategy Override test strategy (minimal, standard, comprehensive) + --autonomy Declare the Intent autonomy mode (none, semi, full) — works on the launch that births the intent; full still needs the grant ceremony --version Show the framework version --help Show this help message @@ -279,7 +280,8 @@ Examples: /amadeus --phase construction --scope fix Jump to construction with fix scope /amadeus --scope fix --depth comprehensive Fix with comprehensive depth /amadeus --depth minimal Change depth of active workflow - /amadeus --depth standard --test-strategy minimal Full artifacts, minimal tests`; + /amadeus --depth standard --test-strategy minimal Full artifacts, minimal tests + /amadeus --autonomy semi Add rate limiting Start with semi autonomy declared`; /** Exported for t67 unit tests. */ export function renderHelpText(): string { diff --git a/packages/framework/harness/claude/skills/amadeus/SKILL.md b/packages/framework/harness/claude/skills/amadeus/SKILL.md index 3db68d83e2..26dde12656 100644 --- a/packages/framework/harness/claude/skills/amadeus/SKILL.md +++ b/packages/framework/harness/claude/skills/amadeus/SKILL.md @@ -6,10 +6,10 @@ description: > `.claude/scopes/`; run `bun .claude/tools/amadeus-utility.ts help` for the authoritative list and descriptions. Utilities: --status, --doctor, --migrate [path], --stage, - --phase, --scope, --depth, --test-strategy, --version, + --phase, --scope, --depth, --test-strategy, --autonomy, --version, --help, plus the intent and space verbs. Or describe what you want to build and the scope will be auto-detected. -argument-hint: "[description | --status | --migrate [path] | --stage | --phase | --version | --help]" +argument-hint: "[description | --status | --migrate [path] | --stage | --phase | --autonomy | --version | --help]" user-invocable: true --- @@ -45,7 +45,7 @@ Loop: not `done` alone: `await-completion` is terminal for this turn too. ``` -Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. +Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, `--autonomy`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. Run the engine binary directly via Bash. If a directive looks malformed or names a move you cannot make, that is an engine signal worth surfacing to the user, never a cue to improvise the routing in prose. @@ -245,7 +245,8 @@ The engine reads the compiled `data/stage-graph.json` directly for all routing; - **Adaptive scope**: Scope determines which stages execute and at what depth — from 5-stage chore to 32-stage enterprise. The engine owns the resolution; you run the stages it hands you. - **STAGE RITUAL IS ATOMIC**: Once a stage starts, EVERY step fires: questions → artifact → reviewer (§12a, if declared) → learnings (§13) → gate. No step is skippable. "Skip to stage X" skips INTERMEDIATE stages, NOT the target stage's ritual. Complete the current stage fully (including learnings) before jumping. -- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward autonomy. NEVER self-answer questions without explicit permission for THIS specific stage. +- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward that permission, and NEVER self-answer a question on your own judgement. This forbids *inferring* authority — it does not forbid the authority the engine already holds: when the Intent's recorded autonomy mode (`semi` / `full`) resolves a gate or a question through the engine's own ladder, that is a recorded human declaration being executed, not an inference, and you follow the directive as given. +- **Declaring Intent autonomy at launch**: `--autonomy ` declares the Intent's autonomy mode as part of the invocation, including the invocation that births the intent. Pass it straight through to `next`; the engine owns the decision. `none` / `semi` are recorded through the canonical write path and take effect at once. `full` is never granted by the flag — the run prints the grant ceremony (`bun .claude/tools/amadeus-bolt.ts preview-autonomy`, then `bun .claude/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) and stops there. Never supply the flag on the user's behalf. See `docs/reference/24-intent-autonomy.md`. - **User control**: The user can override any stage decision at any approval gate. - **11 domain experts**: Each stage leverages the appropriate agent persona (product, design, delivery, architect, aws-platform, compliance, devsecops, developer, quality, pipeline-deploy, operations). - **Approval gates**: Every stage except the bootstrap initialization stages presents an approval gate (the engine signals this via `run-stage`'s `gate` field). diff --git a/packages/framework/harness/codex/skills/amadeus/SKILL.md b/packages/framework/harness/codex/skills/amadeus/SKILL.md index 32861ee04f..3a2ab994e5 100644 --- a/packages/framework/harness/codex/skills/amadeus/SKILL.md +++ b/packages/framework/harness/codex/skills/amadeus/SKILL.md @@ -6,7 +6,7 @@ description: > `.codex/scopes/`; run `bun .codex/tools/amadeus-utility.ts help` for the authoritative list and descriptions. Utilities: --status, --doctor, --migrate [path], --stage, - --phase, --scope, --depth, --test-strategy, --version, + --phase, --scope, --depth, --test-strategy, --autonomy, --version, --help, plus the intent and space verbs. Or describe what you want to build and the scope will be auto-detected. --- @@ -43,7 +43,7 @@ Loop: not `done` alone: `await-completion` is terminal for this turn too. ``` -Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass the user's invocation text through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. +Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass the user's invocation text through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, `--autonomy`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. Run the engine binary directly via the shell tool. If a directive looks malformed or names a move you cannot make, that is an engine signal worth surfacing to the user, never a cue to improvise the routing in prose. @@ -243,6 +243,7 @@ The engine reads the compiled `data/stage-graph.json` directly for all routing; ## Key Principles - **Adaptive scope**: Scope determines which stages execute and at what depth — from 5-stage chore to 32-stage enterprise. The engine owns the resolution; you run the stages it hands you. +- **Declaring Intent autonomy at launch**: `--autonomy ` declares the Intent's autonomy mode as part of the invocation, including the invocation that births the intent. Pass it straight through to `next`; the engine owns the decision. `none` / `semi` are recorded through the canonical write path and take effect at once. `full` is never granted by the flag — the run prints the grant ceremony (`bun .codex/tools/amadeus-bolt.ts preview-autonomy`, then `bun .codex/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) and stops there. Never supply the flag on the user's behalf, and never infer autonomy from a previous answer: an autonomous ruling is only ever the engine executing a recorded human declaration. See `docs/reference/24-intent-autonomy.md`. - **User control**: The user can override any stage decision at any approval gate. - **11 domain experts**: Each stage leverages the appropriate agent persona (product, design, delivery, architect, aws-platform, compliance, devsecops, developer, quality, pipeline-deploy, operations). - **Approval gates**: Every stage except the bootstrap initialization stages presents an approval gate (the engine signals this via `run-stage`'s `gate` field). diff --git a/packages/framework/harness/cursor/commands/amadeus.md b/packages/framework/harness/cursor/commands/amadeus.md index 31e1c2757e..4b5677a676 100644 --- a/packages/framework/harness/cursor/commands/amadeus.md +++ b/packages/framework/harness/cursor/commands/amadeus.md @@ -36,7 +36,20 @@ fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them. Pass the user's invocation text through to the first `next` verbatim; the engine parses the flags (`--status`, `--stage`, `--scope`, -`--depth`, freeform text, …) and resolves the scope, so do not pre-parse them. +`--depth`, `--autonomy`, freeform text, …) and resolves the scope, so do not +pre-parse them. + +`--autonomy ` declares the Intent's autonomy mode as part of the +invocation, including the invocation that births the intent. Pass it straight +through to `next`; the engine owns the decision. `none` / `semi` are recorded +through the canonical write path and take effect at once. `full` is never +granted by the flag — the run prints the grant ceremony +(`bun .cursor/tools/amadeus-bolt.ts preview-autonomy`, then +`bun .cursor/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) +and stops there. Never supply the flag on the user's behalf, and never infer +autonomy from a previous answer: an autonomous ruling is only ever the engine +executing a recorded human declaration. See +`docs/reference/24-intent-autonomy.md`. ## Acting on a directive diff --git a/packages/framework/harness/kimi/skills/amadeus/SKILL.md b/packages/framework/harness/kimi/skills/amadeus/SKILL.md index deec01bba5..45e6fc1531 100644 --- a/packages/framework/harness/kimi/skills/amadeus/SKILL.md +++ b/packages/framework/harness/kimi/skills/amadeus/SKILL.md @@ -6,10 +6,10 @@ description: > `.kimi-code/scopes/`; run `bun .kimi-code/tools/amadeus-utility.ts help` for the authoritative list and descriptions. Utilities: --status, --doctor, --migrate [path], --stage, - --phase, --scope, --depth, --test-strategy, --version, + --phase, --scope, --depth, --test-strategy, --autonomy, --version, --help, plus the intent and space verbs. Or describe what you want to build and the scope will be auto-detected. -argument-hint: "[description | --status | --migrate [path] | --stage | --phase | --version | --help]" +argument-hint: "[description | --status | --migrate [path] | --stage | --phase | --autonomy | --version | --help]" user-invocable: true --- @@ -45,7 +45,7 @@ Loop: not `done` alone: `await-completion` is terminal for this turn too. ``` -Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. +Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, `--autonomy`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. Run the engine binary directly via Bash. If a directive looks malformed or names a move you cannot make, that is an engine signal worth surfacing to the user, never a cue to improvise the routing in prose. @@ -254,7 +254,8 @@ The engine reads the compiled `data/stage-graph.json` directly for all routing; - **Adaptive scope**: Scope determines which stages execute and at what depth — from 5-stage chore to 32-stage enterprise. The engine owns the resolution; you run the stages it hands you. - **STAGE RITUAL IS ATOMIC**: Once a stage starts, EVERY step fires: questions → artifact → reviewer (§12a, if declared) → learnings (§13) → gate. No step is skippable. "Skip to stage X" skips INTERMEDIATE stages, NOT the target stage's ritual. Complete the current stage fully (including learnings) before jumping. -- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward autonomy. NEVER self-answer questions without explicit permission for THIS specific stage. +- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward that permission, and NEVER self-answer a question on your own judgement. This forbids *inferring* authority — it does not forbid the authority the engine already holds: when the Intent's recorded autonomy mode (`semi` / `full`) resolves a gate or a question through the engine's own ladder, that is a recorded human declaration being executed, not an inference, and you follow the directive as given. +- **Declaring Intent autonomy at launch**: `--autonomy ` declares the Intent's autonomy mode as part of the invocation, including the invocation that births the intent. Pass it straight through to `next`; the engine owns the decision. `none` / `semi` are recorded through the canonical write path and take effect at once. `full` is never granted by the flag — the run prints the grant ceremony (`bun .kimi-code/tools/amadeus-bolt.ts preview-autonomy`, then `bun .kimi-code/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) and stops there. Never supply the flag on the user's behalf. See `docs/reference/24-intent-autonomy.md`. - **User control**: The user can override any stage decision at any approval gate. - **11 domain experts**: Each stage leverages the appropriate agent persona (product, design, delivery, architect, aws-platform, compliance, devsecops, developer, quality, pipeline-deploy, operations). - **Approval gates**: Every stage except the bootstrap initialization stages presents an approval gate (the engine signals this via `run-stage`'s `gate` field). diff --git a/packages/framework/harness/kiro-ide/skills/amadeus/SKILL.md b/packages/framework/harness/kiro-ide/skills/amadeus/SKILL.md index 4bdee79327..c84738525e 100644 --- a/packages/framework/harness/kiro-ide/skills/amadeus/SKILL.md +++ b/packages/framework/harness/kiro-ide/skills/amadeus/SKILL.md @@ -6,7 +6,7 @@ description: > `.kiro/scopes/`; run `bun .kiro/tools/amadeus-utility.ts help` for the authoritative list and descriptions. Utilities: --status, --doctor, --migrate [path], --stage, - --phase, --scope, --depth, --test-strategy, --version, + --phase, --scope, --depth, --test-strategy, --autonomy, --version, --help, plus the intent and space verbs. Or describe what you want to build and the scope will be auto-detected. --- @@ -41,7 +41,7 @@ Loop: not `done` alone: `await-completion` is terminal for this turn too. ``` -Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. +Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, `--autonomy`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. Run the engine binary directly via the shell tool. If a directive looks malformed or names a move you cannot make, that is an engine signal worth surfacing to the user, never a cue to improvise the routing in prose. @@ -243,7 +243,8 @@ The engine reads the compiled `data/stage-graph.json` directly for all routing; - **Adaptive scope**: Scope determines which stages execute and at what depth. The engine owns the resolution; you run the stages it hands you. - **STAGE RITUAL IS ATOMIC**: Once a stage starts, EVERY step fires: questions → artifact → reviewer (§12a, if declared) → learnings (§13) → gate. No step is skippable. "Skip to stage X" skips INTERMEDIATE stages, NOT the target stage's ritual. Complete the current stage fully (including learnings) before jumping. -- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward autonomy. NEVER self-answer questions without explicit permission for THIS specific stage. +- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward that permission, and NEVER self-answer a question on your own judgement. This forbids *inferring* authority — it does not forbid the authority the engine already holds: when the Intent's recorded autonomy mode (`semi` / `full`) resolves a gate or a question through the engine's own ladder, that is a recorded human declaration being executed, not an inference, and you follow the directive as given. +- **Declaring Intent autonomy at launch**: `--autonomy ` declares the Intent's autonomy mode as part of the invocation, including the invocation that births the intent. Pass it straight through to `next`; the engine owns the decision. `none` / `semi` are recorded through the canonical write path and take effect at once. `full` is never granted by the flag — the run prints the grant ceremony (`bun .kiro/tools/amadeus-bolt.ts preview-autonomy`, then `bun .kiro/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) and stops there. Never supply the flag on the user's behalf. See `docs/reference/24-intent-autonomy.md`. - **User control**: The user can override any stage decision at any approval gate. - **11 domain experts**: Each stage leverages the appropriate agent persona; personas load inline from `.kiro/agents/amadeus--agent.md` for 30 of 32 stages. - **Approval gates**: Every stage except the bootstrap initialization stages presents an approval gate. diff --git a/packages/framework/harness/kiro/skills/amadeus/SKILL.md b/packages/framework/harness/kiro/skills/amadeus/SKILL.md index 9c9b0fceb9..cbb62718c7 100644 --- a/packages/framework/harness/kiro/skills/amadeus/SKILL.md +++ b/packages/framework/harness/kiro/skills/amadeus/SKILL.md @@ -6,7 +6,7 @@ description: > `.kiro/scopes/`; run `bun .kiro/tools/amadeus-utility.ts help` for the authoritative list and descriptions. Utilities: --status, --doctor, --migrate [path], --stage, - --phase, --scope, --depth, --test-strategy, --version, + --phase, --scope, --depth, --test-strategy, --autonomy, --version, --help, plus the intent and space verbs. Or describe what you want to build and the scope will be auto-detected. --- @@ -41,7 +41,7 @@ Loop: not `done` alone: `await-completion` is terminal for this turn too. ``` -Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. +Each `next` reads the workflow state and the compiled stage graph and returns **exactly one** typed directive (JSON) on stdout. It mutates no workflow state (its only write is the machine-local sensor-invocation projection under the gitignored hooks-health runtime). The directive's `kind` names the single move to make; you make that move, then `report` commits the resulting transition so the next `next` reads fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them, and a speculative direct call gets the engine's state-guard error. Pass `$ARGUMENTS` through to the first `next` verbatim — the engine parses flags (`--status`, `--stage`, `--scope`, `--depth`, `--autonomy`, freeform text, …) and resolves the scope, so you do not pre-parse or strip them. Run the engine binary directly via the shell tool. If a directive looks malformed or names a move you cannot make, that is an engine signal worth surfacing to the user, never a cue to improvise the routing in prose. @@ -243,7 +243,8 @@ The engine reads the compiled `data/stage-graph.json` directly for all routing; - **Adaptive scope**: Scope determines which stages execute and at what depth. The engine owns the resolution; you run the stages it hands you. - **STAGE RITUAL IS ATOMIC**: Once a stage starts, EVERY step fires: questions → artifact → reviewer (§12a, if declared) → learnings (§13) → gate. No step is skippable. "Skip to stage X" skips INTERMEDIATE stages, NOT the target stage's ritual. Complete the current stage fully (including learnings) before jumping. -- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward autonomy. NEVER self-answer questions without explicit permission for THIS specific stage. +- **AUTONOMY IS NEVER INFERRED**: A user saying "go with recommended" for one stage is a one-time instruction for THAT stage. The next stage starts fresh. NEVER carry forward that permission, and NEVER self-answer a question on your own judgement. This forbids *inferring* authority — it does not forbid the authority the engine already holds: when the Intent's recorded autonomy mode (`semi` / `full`) resolves a gate or a question through the engine's own ladder, that is a recorded human declaration being executed, not an inference, and you follow the directive as given. +- **Declaring Intent autonomy at launch**: `--autonomy ` declares the Intent's autonomy mode as part of the invocation, including the invocation that births the intent. Pass it straight through to `next`; the engine owns the decision. `none` / `semi` are recorded through the canonical write path and take effect at once. `full` is never granted by the flag — the run prints the grant ceremony (`bun .kiro/tools/amadeus-bolt.ts preview-autonomy`, then `bun .kiro/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) and stops there. Never supply the flag on the user's behalf. See `docs/reference/24-intent-autonomy.md`. - **User control**: The user can override any stage decision at any approval gate. - **11 domain experts**: Each stage leverages the appropriate agent persona; personas load inline from `.kiro/agents/amadeus--agent.md` for 30 of 32 stages. - **Approval gates**: Every stage except the bootstrap initialization stages presents an approval gate. diff --git a/packages/framework/harness/opencode/commands/amadeus.md b/packages/framework/harness/opencode/commands/amadeus.md index 5c24a38116..38aa5620c9 100644 --- a/packages/framework/harness/opencode/commands/amadeus.md +++ b/packages/framework/harness/opencode/commands/amadeus.md @@ -36,7 +36,20 @@ fresh state. **Report once per directive; never call the state tools (`amadeus-state.ts approve/advance/…`) directly** — the engine's `report` dispatches them. Pass the user's invocation text through to the first `next` verbatim; the engine parses the flags (`--status`, `--stage`, `--scope`, -`--depth`, freeform text, …) and resolves the scope, so do not pre-parse them. +`--depth`, `--autonomy`, freeform text, …) and resolves the scope, so do not +pre-parse them. + +`--autonomy ` declares the Intent's autonomy mode as part of the +invocation, including the invocation that births the intent. Pass it straight +through to `next`; the engine owns the decision. `none` / `semi` are recorded +through the canonical write path and take effect at once. `full` is never +granted by the flag — the run prints the grant ceremony +(`bun .opencode/tools/amadeus-bolt.ts preview-autonomy`, then +`bun .opencode/tools/amadeus-bolt.ts set-autonomy --mode full --confirmed-display-digest `) +and stops there. Never supply the flag on the user's behalf, and never infer +autonomy from a previous answer: an autonomous ruling is only ever the engine +executing a recorded human declaration. See +`docs/reference/24-intent-autonomy.md`. ## Acting on a directive diff --git a/packages/framework/harness/pi/skills/amadeus/SKILL.md b/packages/framework/harness/pi/skills/amadeus/SKILL.md index 93cf31a5e0..5eab4777bc 100644 --- a/packages/framework/harness/pi/skills/amadeus/SKILL.md +++ b/packages/framework/harness/pi/skills/amadeus/SKILL.md @@ -40,6 +40,18 @@ the invocation contains flags or free text. In particular: - `--status` → `bun .pi/tools/amadeus-orchestrate.ts next --status` - `--doctor` → `bun .pi/tools/amadeus-orchestrate.ts next --doctor` - `--resume` → `bun .pi/tools/amadeus-orchestrate.ts next --resume` +- `--autonomy ` → `bun .pi/tools/amadeus-orchestrate.ts next --autonomy ` + +`--autonomy` declares the Intent's autonomy mode as part of the invocation, +including the invocation that births the intent. Forward it unchanged; the +engine owns the decision. `none` / `semi` are recorded through the canonical +write path and take effect at once. `full` is never granted by the flag — the +run prints the grant ceremony (`bun .pi/tools/amadeus-bolt.ts +preview-autonomy`, then `bun .pi/tools/amadeus-bolt.ts set-autonomy --mode full +--confirmed-display-digest `) and stops there. Never supply the flag on +the user's behalf, and never infer autonomy from a previous answer: an +autonomous ruling is only ever the engine executing a recorded human +declaration. See `docs/reference/24-intent-autonomy.md`. An active intent does not override a utility flag. A terminal utility directive must be printed and stopped; it never falls through to the current stage. diff --git a/tests/integration/t-coverage-mechanism-ratchet.test.ts b/tests/integration/t-coverage-mechanism-ratchet.test.ts index caa342dad8..51298a3230 100644 --- a/tests/integration/t-coverage-mechanism-ratchet.test.ts +++ b/tests/integration/t-coverage-mechanism-ratchet.test.ts @@ -206,6 +206,7 @@ describe("repository-wide mechanism honesty ratchets", () => { "integration/t458-advisory-auto-resolution.integration.test.ts", "integration/t49.test.ts", "integration/t490-birth-declaration.integration.test.ts", + "integration/t492-autonomy-conduit-parity.integration.test.ts", "integration/t51.test.ts", "integration/t66.test.ts", "integration/t75.test.ts", diff --git a/tests/integration/t492-autonomy-conduit-parity.integration.test.ts b/tests/integration/t492-autonomy-conduit-parity.integration.test.ts new file mode 100644 index 0000000000..3947e6fd1c --- /dev/null +++ b/tests/integration/t492-autonomy-conduit-parity.integration.test.ts @@ -0,0 +1,138 @@ +// t492 — `--autonomy` conduit parity (#2378 FR-5d). +// size: medium +// +// The launch declaration is only reachable if the surfaces a user or a +// conductor actually reads mention it. Before this guard, `--autonomy` was +// implemented in the engine and named on ZERO harness entry points: the flag +// worked and nobody could find it. +// +// The conduit set is DERIVED, never listed: every directory under +// packages/framework/harness/ contributes exactly one canonical entry point — +// skills/amadeus/SKILL.md for the skill harnesses, commands/amadeus.md for the +// command harnesses. A new harness therefore joins the contract by existing, and +// no count lives anywhere in this file (cid:functional-design:c3-adjacent-enum-numerals). +// The derivation is itself asserted: a harness that carries neither entry point, +// or both, reds here rather than silently dropping out of the set. +// +// The help text is observed at the PROCESS boundary (spawn of the shipped +// amadeus-utility.ts `help`), not by grepping the source that renders it — the +// contract is what a user sees, and dist/ is the surface the user runs +// (cid:code-generation:no-canonical-direct-execution). +// +// The English/Japanese reference pair is checked as a pair on purpose: a +// one-sided doc update is the failure this file is meant to catch. + +import { describe, expect, test } from "bun:test"; +import { spawnSync } from "node:child_process"; +import { existsSync, readFileSync, readdirSync } from "node:fs"; +import { join } from "node:path"; + +const REPO_ROOT = join(import.meta.dir, "..", ".."); +const HARNESS_ROOT = join(REPO_ROOT, "packages", "framework", "harness"); +const FLAG = "--autonomy"; + +// The two shapes a harness entry point can take, relative to its harness dir. +const ENTRY_POINT_CANDIDATES = [ + join("skills", "amadeus", "SKILL.md"), + join("commands", "amadeus.md"), +] as const; + +interface Conduit { + readonly label: string; + readonly path: string; +} + +// Every harness directory, read from disk. Non-directory entries (registry.ts, +// projections.ts) are excluded by withFileTypes rather than by name, so a new +// sibling module never has to be added to an ignore list. +function harnessNames(): string[] { + return readdirSync(HARNESS_ROOT, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); +} + +// The entry points a harness carries. Returning ALL matches (not the first) is +// what lets the derivation assert exactly-one below. +function entryPointsOf(harness: string): string[] { + return ENTRY_POINT_CANDIDATES.map((rel) => join(HARNESS_ROOT, harness, rel)).filter( + (path) => existsSync(path), + ); +} + +const HARNESSES = harnessNames(); + +const CONDUITS: Conduit[] = HARNESSES.flatMap((harness) => + entryPointsOf(harness).map((path) => ({ label: `harness:${harness}`, path })), +); + +// The non-harness surfaces the requirement names, kept as an explicit list +// because there is no directory that enumerates them. This list IS the canonical +// definition of the documentation side of the contract. +const DOC_SURFACES: Conduit[] = [ + { label: "README (en)", path: join(REPO_ROOT, "README.md") }, + { label: "README (ja)", path: join(REPO_ROOT, "README.ja.md") }, + { + label: "reference 24 (en)", + path: join(REPO_ROOT, "docs", "reference", "24-intent-autonomy.md"), + }, + { + label: "reference 24 (ja)", + path: join(REPO_ROOT, "docs", "reference", "24-intent-autonomy.ja.md"), + }, +]; + +function readSurface(path: string): string { + return readFileSync(path, "utf-8"); +} + +describe("t492 --autonomy conduit parity", () => { + test("every harness carries exactly one canonical entry point", () => { + // Guards the derivation itself: without this, a harness whose entry point + // moved would leave the conduit set silently short and every parity + // assertion below would still pass. + const malformed = HARNESSES.filter((harness) => entryPointsOf(harness).length !== 1); + expect(malformed).toEqual([]); + expect(HARNESSES.length).toBeGreaterThan(0); + }); + + test("every harness entry point names the launch declaration flag", () => { + const silent = CONDUITS.filter((c) => !readSurface(c.path).includes(FLAG)).map( + (c) => c.label, + ); + expect(silent).toEqual([]); + }); + + test("README and the autonomy reference name the flag, in both languages", () => { + const silent = DOC_SURFACES.filter((c) => !readSurface(c.path).includes(FLAG)).map( + (c) => c.label, + ); + expect(silent).toEqual([]); + }); + + test("the shipped help text names the flag", () => { + const tool = join(REPO_ROOT, "dist", "claude", ".claude", "tools", "amadeus-utility.ts"); + const res = spawnSync(process.execPath, [tool, "help"], { encoding: "utf-8" }); + expect(res.status).toBe(0); + expect(res.stdout ?? "").toContain(FLAG); + }); + + test("stage-protocol gives semi its own decide-question procedure", () => { + // FR-5c: the contract line already said `semi` resolves questions through + // the ladder, but the operational paragraph was written for `full` only, so + // a conductor under `semi` had no named procedure to follow. + const protocol = readSurface( + join( + REPO_ROOT, + "packages", + "framework", + "core", + "amadeus-common", + "protocols", + "stage-protocol.md", + ), + ); + expect(protocol).toContain("For a question under `semi`"); + expect(protocol).toContain("For a question under `full`"); + }); +});