@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.1
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 +919 -1
- package/README.md +104 -81
- package/README.tr.md +103 -62
- package/docs/FIGMA_PIPELINE.md +35 -35
- package/docs/adr/0006-skills-core-external-split.md +1 -1
- package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
- package/docs/architecture.md +50 -14
- package/docs/best-practices.md +1 -1
- package/docs/ecosystem.md +56 -32
- package/docs/facts.json +10 -10
- package/docs/features.md +97 -5
- package/docs/recovery-guide.md +7 -14
- package/docs/server-readiness.md +31 -24
- package/index.js +1 -1
- package/install/_common.mjs +3 -5
- package/install/_platform-filter.mjs +23 -1
- package/install/_unattended-profile.mjs +321 -75
- package/install/claude.mjs +51 -10
- package/install/codex.mjs +2 -0
- package/install/copilot.mjs +2 -0
- package/install/index.mjs +30 -17
- package/install/templates/claude-hooks.json +16 -5
- package/install/templates/copilot-instructions.md +1 -1
- package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
- package/install/templates/multi-agent-autopilot.plist.template +12 -5
- package/install/unattended-profile-legacy.json +80 -0
- package/manifest.json +617 -483
- package/package.json +8 -3
- package/pipeline/agents/code-reviewer.md +10 -0
- package/pipeline/agents/plan-critic.md +98 -0
- package/pipeline/agents/security-auditor.md +10 -0
- package/pipeline/agents/task-clarifier.md +10 -0
- package/pipeline/commands/multi-agent/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
- package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
- package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
- package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
- package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
- package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
- package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
- package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
- package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
- package/pipeline/contract/CHANGELOG.md +74 -0
- package/pipeline/contract/README.md +126 -0
- package/pipeline/contract/build.mjs +427 -0
- package/pipeline/contract/fixtures/answer-result.json +11 -0
- package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
- package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
- package/pipeline/contract/fixtures/error-unsigned.json +5 -0
- package/pipeline/contract/fixtures/issues-empty.json +18 -0
- package/pipeline/contract/fixtures/launch-plan.json +31 -0
- package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
- package/pipeline/contract/fixtures/runs-empty.json +6 -0
- package/pipeline/contract/fixtures/runs-failed.json +84 -0
- package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
- package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
- package/pipeline/contract/fixtures/runs-running.json +84 -0
- package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
- package/pipeline/contract/frozen/toolbox.json +107 -0
- package/pipeline/contract/manifest.json +263 -0
- package/pipeline/contract/types/index.d.ts +343 -0
- package/pipeline/lib/_jira-auth.sh +6 -2
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/autopilot-state.sh +19 -0
- package/pipeline/lib/context-link-extractor.sh +12 -5
- package/pipeline/lib/credential-inventory.sh +12 -5
- package/pipeline/lib/credential-store.sh +116 -185
- package/pipeline/lib/fetch-confluence.sh +44 -3
- package/pipeline/lib/fetch-document.sh +3 -4
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/figma-mcp-refresh.sh +2 -2
- package/pipeline/lib/figma-token.sh +5 -1
- package/pipeline/lib/issue-fetcher.sh +233 -16
- package/pipeline/lib/json-file-lock.mjs +172 -0
- package/pipeline/lib/model-dispatch.sh +21 -12
- package/pipeline/lib/model-rung.sh +6 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/outbound-gate.mjs +46 -16
- package/pipeline/lib/parse-complaints.sh +14 -7
- package/pipeline/lib/plan-todos.sh +3 -3
- package/pipeline/lib/post-pr-review.sh +9 -9
- package/pipeline/lib/pr-request-location.mjs +85 -0
- package/pipeline/lib/regular-file.mjs +153 -0
- package/pipeline/lib/repo-hygiene.sh +17 -0
- package/pipeline/lib/route-state.sh +5 -1
- package/pipeline/lib/run-paths.sh +3 -2
- package/pipeline/lib/stack-detect.sh +19 -1
- package/pipeline/lib/unattended-profile-check.mjs +178 -0
- package/pipeline/lib/unattended-settings-location.mjs +28 -0
- package/pipeline/lib/unattended.mjs +76 -0
- package/pipeline/lib/unattended.sh +32 -0
- package/pipeline/lib/untrusted.mjs +76 -0
- package/pipeline/lib/usage-endpoint.mjs +33 -0
- package/pipeline/lib/user-facing.mjs +82 -0
- package/pipeline/lib/user-facing.sh +58 -0
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
- package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
- package/pipeline/multi-agent-refs/analysis/render.md +4 -3
- package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
- package/pipeline/multi-agent-refs/analysis-template.md +10 -17
- package/pipeline/multi-agent-refs/channels/jira.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
- package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
- package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
- package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
- package/pipeline/multi-agent-refs/features/constitution.md +196 -0
- package/pipeline/multi-agent-refs/features/doctor.md +6 -3
- package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
- package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
- package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
- package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
- package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
- package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
- package/pipeline/multi-agent-refs/features/research.md +150 -0
- package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
- package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
- package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
- package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
- package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
- package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
- package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
- package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
- package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
- package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
- package/pipeline/multi-agent-refs/keychain.md +6 -11
- package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
- package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
- package/pipeline/multi-agent-refs/phases/modes.md +10 -12
- package/pipeline/multi-agent-refs/phases/operations.md +11 -5
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
- package/pipeline/multi-agent-refs/phases.md +1 -1
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/progress-contract.md +13 -16
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/research/engine.md +91 -0
- package/pipeline/multi-agent-refs/rules.md +6 -4
- package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
- package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
- package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
- package/pipeline/rules/figma-pipeline.md +12 -12
- package/pipeline/schemas/agent-state.schema.json +480 -18
- package/pipeline/schemas/analysis-spec.schema.json +4 -4
- package/pipeline/schemas/answer-request.schema.json +24 -0
- package/pipeline/schemas/answer-result.schema.json +28 -0
- package/pipeline/schemas/autopilot-config.schema.json +111 -13
- package/pipeline/schemas/command-parameters.schema.json +99 -0
- package/pipeline/schemas/constitution.schema.json +56 -0
- package/pipeline/schemas/contract-error.schema.json +52 -0
- package/pipeline/schemas/design-check-config.schema.json +5 -1
- package/pipeline/schemas/issues.schema.json +61 -0
- package/pipeline/schemas/launch-plan.schema.json +46 -0
- package/pipeline/schemas/launch-request.schema.json +45 -0
- package/pipeline/schemas/launch.json +61 -0
- package/pipeline/schemas/launch.schema.json +84 -0
- package/pipeline/schemas/phases.json +2 -2
- package/pipeline/schemas/phases.schema.json +68 -0
- package/pipeline/schemas/phone-devices.schema.json +61 -0
- package/pipeline/schemas/phone-signed-request.schema.json +67 -0
- package/pipeline/schemas/plan-critique.schema.json +99 -0
- package/pipeline/schemas/plan-todos.schema.json +7 -7
- package/pipeline/schemas/planning-output.schema.json +5 -0
- package/pipeline/schemas/pr-request.schema.json +46 -0
- package/pipeline/schemas/prefs.schema.json +79 -8
- package/pipeline/schemas/research-output.schema.json +118 -0
- package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
- package/pipeline/schemas/reviewer-output.schema.json +40 -4
- package/pipeline/schemas/run-questions.json +392 -0
- package/pipeline/schemas/run-questions.schema.json +118 -0
- package/pipeline/schemas/runs-index.schema.json +189 -0
- package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
- package/pipeline/schemas/secret-patterns.schema.json +28 -0
- package/pipeline/schemas/stack-adapters.json +527 -0
- package/pipeline/schemas/stack-adapters.schema.json +184 -0
- package/pipeline/schemas/token-budget.json +1 -1
- package/pipeline/schemas/token-budget.schema.json +26 -0
- package/pipeline/schemas/triage-output.schema.json +64 -3
- package/pipeline/schemas/unattended-policy.json +139 -0
- package/pipeline/schemas/unattended-policy.schema.json +73 -0
- package/pipeline/schemas/unattended-profile.json +248 -0
- package/pipeline/schemas/unattended-profile.schema.json +198 -0
- package/pipeline/schemas/worktrees.schema.json +51 -0
- package/pipeline/scripts/README.md +1 -0
- package/pipeline/scripts/_autopilot-config.mjs +130 -0
- package/pipeline/scripts/_autopilot-ops.mjs +567 -0
- package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
- package/pipeline/scripts/_command-contract.mjs +384 -0
- package/pipeline/scripts/_cost.mjs +40 -0
- package/pipeline/scripts/_notices.mjs +160 -0
- package/pipeline/scripts/_phone-auth.mjs +485 -0
- package/pipeline/scripts/_pre-existing.mjs +294 -0
- package/pipeline/scripts/_redact.mjs +77 -0
- package/pipeline/scripts/_run-paths.mjs +4 -2
- package/pipeline/scripts/_stack-adapter.mjs +678 -0
- package/pipeline/scripts/_stack-routing.mjs +1 -1
- package/pipeline/scripts/agent-guard.py +348 -37
- package/pipeline/scripts/agent-guard.sh +41 -13
- package/pipeline/scripts/analysis-story-tree.mjs +79 -3
- package/pipeline/scripts/answer-question.mjs +181 -0
- package/pipeline/scripts/audit-log-rotate.sh +1 -4
- package/pipeline/scripts/audit-log.sh +4 -4
- package/pipeline/scripts/autopilot-arming.mjs +389 -21
- package/pipeline/scripts/autopilot-awake.mjs +255 -0
- package/pipeline/scripts/autopilot-intake.mjs +137 -36
- package/pipeline/scripts/autopilot-menubar.swift +156 -44
- package/pipeline/scripts/autopilot-publish.mjs +1625 -0
- package/pipeline/scripts/autopilot-runner.mjs +1678 -222
- package/pipeline/scripts/autopilot-status.sh +198 -33
- package/pipeline/scripts/build-lock.sh +120 -0
- package/pipeline/scripts/build-references.mjs +4 -1
- package/pipeline/scripts/build-stack-plugins.mjs +59 -22
- package/pipeline/scripts/capture-flush.sh +1 -1
- package/pipeline/scripts/capture-resume.sh +13 -9
- package/pipeline/scripts/check-derived-drift.mjs +52 -11
- package/pipeline/scripts/commands.mjs +88 -0
- package/pipeline/scripts/constitution.mjs +362 -0
- package/pipeline/scripts/contract-server.mjs +776 -0
- package/pipeline/scripts/cost-analyze.mjs +89 -39
- package/pipeline/scripts/diff-explain.mjs +12 -1
- package/pipeline/scripts/doctor.mjs +77 -28
- package/pipeline/scripts/evidence-gate.mjs +192 -12
- package/pipeline/scripts/feedback-send.mjs +4 -2
- package/pipeline/scripts/gate-ledger.mjs +449 -0
- package/pipeline/scripts/gc-abandoned.sh +132 -13
- package/pipeline/scripts/gen-facts.mjs +31 -15
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/github-ssh-setup.sh +140 -29
- package/pipeline/scripts/graph-mermaid.mjs +4 -1
- package/pipeline/scripts/issues.mjs +236 -0
- package/pipeline/scripts/jira-attach.sh +6 -2
- package/pipeline/scripts/jira-search.sh +4 -3
- package/pipeline/scripts/keychain-save.sh +125 -24
- package/pipeline/scripts/keychain.py +63 -93
- package/pipeline/scripts/launch-request.mjs +747 -0
- package/pipeline/scripts/localize-commands.mjs +4 -10
- package/pipeline/scripts/log-metric.sh +6 -5
- package/pipeline/scripts/maturity-followup.mjs +13 -4
- package/pipeline/scripts/memory-save.sh +25 -0
- package/pipeline/scripts/migrate-prefs.mjs +4 -3
- package/pipeline/scripts/open-questions-gate.mjs +276 -0
- package/pipeline/scripts/phase-tracker.sh +41 -27
- package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
- package/pipeline/scripts/phone-devices.mjs +224 -0
- package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
- package/pipeline/scripts/plan-critique-gate.mjs +591 -0
- package/pipeline/scripts/pr-request.mjs +188 -0
- package/pipeline/scripts/pre-commit-check.sh +115 -4
- package/pipeline/scripts/probe-evidence-capability.sh +44 -5
- package/pipeline/scripts/record-phase.mjs +71 -0
- package/pipeline/scripts/render-agent-log-cost.sh +17 -2
- package/pipeline/scripts/render-cost-summary.sh +1 -1
- package/pipeline/scripts/render-work-summary.sh +1 -1
- package/pipeline/scripts/require-supported-version.sh +4 -1
- package/pipeline/scripts/research-gate.mjs +704 -0
- package/pipeline/scripts/review-decision-gate.mjs +403 -0
- package/pipeline/scripts/routine-registry.mjs +5 -2
- package/pipeline/scripts/runs-index.mjs +135 -27
- package/pipeline/scripts/scaffold-gate.mjs +393 -0
- package/pipeline/scripts/skill-conformance.mjs +25 -8
- package/pipeline/scripts/skill-siblings.mjs +2 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
- package/pipeline/scripts/smoke-schema-validation.sh +6 -2
- package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
- package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
- package/pipeline/scripts/test-gap-scan.mjs +40 -2
- package/pipeline/scripts/test-integrity-gate.mjs +20 -4
- package/pipeline/scripts/test-strength.mjs +484 -0
- package/pipeline/scripts/test-summary.mjs +651 -0
- package/pipeline/scripts/triage-memory.mjs +49 -9
- package/pipeline/scripts/unattended_policy.py +2786 -0
- package/pipeline/scripts/uninstall.mjs +10 -10
- package/pipeline/scripts/update-issue-progress.sh +1 -1
- package/pipeline/scripts/usage-identity.mjs +288 -0
- package/pipeline/scripts/usage-register.mjs +187 -67
- package/pipeline/scripts/usage-report.mjs +232 -67
- package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
- package/pipeline/scripts/validate-planning.mjs +6 -0
- package/pipeline/scripts/verify-citations.mjs +151 -38
- package/pipeline/scripts/verify.mjs +58 -18
- package/pipeline/scripts/worktree-prepare.sh +126 -0
- package/pipeline/scripts/worktrees.mjs +124 -0
- package/pipeline/scripts/write-state.mjs +48 -17
- package/pipeline/skills/.skill-manifest.json +222 -226
- package/pipeline/skills/.skills-index.json +77 -88
- package/pipeline/skills/shared/README.md +44 -45
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
- package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
- package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
- package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
- package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
- package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
- package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
- package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
- package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
- package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
- package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
- package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
- package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
- package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
- package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
- package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
- package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
- package/pipeline/skills/shared/external/council/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
- package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
- package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
- package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
- package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
- package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
- package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
- package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
- package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
- package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
- package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
- package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
- package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
- package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
- package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
- package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
- package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
- package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
- package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
- package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
- package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
- package/pipeline/skills/skills-index.md +40 -41
- package/docs/token-budget-history.md +0 -24
- package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
- package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
- package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
- package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
- package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
- package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
|
@@ -8,12 +8,11 @@
|
|
|
8
8
|
- [5. State](#5-state)
|
|
9
9
|
<!-- /toc -->
|
|
10
10
|
|
|
11
|
-
**Pattern**: the maturity check
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
check was doing its job and producing no effect.
|
|
11
|
+
**Pattern**: the maturity check produces a machine-readable gap list - stable
|
|
12
|
+
codes in `blockers[]` and `warnings[]`. A halt on its own leaves the item as
|
|
13
|
+
immature as it was found and tells nobody, so this feature turns the list into a
|
|
14
|
+
question: asked at the step in an interactive run, posted on the item by an
|
|
15
|
+
autopilot run that is allowed to.
|
|
17
16
|
|
|
18
17
|
Three behaviours, one decision function
|
|
19
18
|
(`$HOME/.claude/scripts/maturity-followup.mjs`, pure - no network, no issue API,
|
|
@@ -30,7 +29,7 @@ content and the CHECK decides. Nothing in this feature infers maturity from the
|
|
|
30
29
|
fact that something moved, and the decision function is handed a freshly scored
|
|
31
30
|
`maturity` on every pass for exactly that reason.
|
|
32
31
|
|
|
33
|
-
The corollary is the second comment. A run that re-comments on every
|
|
32
|
+
The corollary is the second comment. A run that re-comments on every pass turns
|
|
34
33
|
an issue into a wall of identical bot text, so:
|
|
35
34
|
|
|
36
35
|
| Situation | What happens |
|
|
@@ -41,17 +40,17 @@ an issue into a wall of identical bot text, so:
|
|
|
41
40
|
| **Different** gaps | comment - a different question is new information |
|
|
42
41
|
| No gaps | proceed; development starts |
|
|
43
42
|
|
|
44
|
-
**Where "have we already asked" comes from.** The item, not our state file.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
**Where "have we already asked" comes from.** The item, not our state file. A
|
|
44
|
+
new run on the same item - started by hand, or by a client after the parked one
|
|
45
|
+
was abandoned - has a fresh `agent-state.json`, so deriving it from state alone
|
|
46
|
+
would make that run a first ask. So the comment carries its own gap set on a
|
|
47
|
+
last line, `multi-agent gaps: code,code`, and the next pass reads the item's
|
|
49
48
|
comments and takes the newest one of ours (`priorFromComments`). `state.maturityFollowup`
|
|
50
49
|
is a cache of the same answer for the run that wrote it, never the source.
|
|
51
50
|
|
|
52
51
|
A comment of ours carrying no gap line - written before v17.6.0, or edited by
|
|
53
52
|
hand - reads as "asked, about something we can no longer name": an empty gap set,
|
|
54
|
-
which never equals a live one, so the next
|
|
53
|
+
which never equals a live one, so the next pass asks again WITH the codes instead
|
|
55
54
|
of staying silent forever on an unreadable record.
|
|
56
55
|
|
|
57
56
|
"Cannot tell whether it moved" (a tracker whose API omits the timestamp, an
|
|
@@ -60,8 +59,7 @@ unparseable value) resolves to *re-check*, never to *wait*. Folding unknown into
|
|
|
60
59
|
|
|
61
60
|
## 2. Interactive: ask at the step, do not halt at it
|
|
62
61
|
|
|
63
|
-
A blocker
|
|
64
|
-
with the gap as the question. The options are real choices and meet the
|
|
62
|
+
A blocker asks, at the maturity step, with the gap as the question. The options are real choices and meet the
|
|
65
63
|
two-option floor on their own (`picker-contract.md`, "Two options or it is not a
|
|
66
64
|
question"):
|
|
67
65
|
|
|
@@ -71,8 +69,8 @@ question"):
|
|
|
71
69
|
| Continue without it | proceeds, and records WHICH gap was accepted in `state.maturity.accepted[]` |
|
|
72
70
|
| Abort | no worktree, no branch, no state file |
|
|
73
71
|
|
|
74
|
-
`prefs.global.maturityFollowup.askInteractively` (default `true`)
|
|
75
|
-
|
|
72
|
+
`prefs.global.maturityFollowup.askInteractively: false` (default `true`) halts with a
|
|
73
|
+
summary instead.
|
|
76
74
|
|
|
77
75
|
**What an answer here does not do.** An answer typed into a picker improves this
|
|
78
76
|
run and leaves the item as immature as it was for the next person. That is a
|
|
@@ -91,7 +89,7 @@ so it carries the same fence as every other one in this pipeline:
|
|
|
91
89
|
- **A question, never a state change.** No transition, no resolution, no
|
|
92
90
|
assignee, no label, no close - ever. The standing rule that this pipeline
|
|
93
91
|
never auto-closes an issue is not relaxed by a feature that writes comments.
|
|
94
|
-
- **One comment.** The marker line makes the next
|
|
92
|
+
- **One comment.** The marker line makes the next pass able to recognise its own
|
|
95
93
|
prior comment; matching on the marker rather than on authorship is what keeps
|
|
96
94
|
that working when the token belongs to a shared service account.
|
|
97
95
|
- **No square brackets in the marker or the gap line.** `[text]` is a LINK in
|
|
@@ -102,11 +100,21 @@ so it carries the same fence as every other one in this pipeline:
|
|
|
102
100
|
- **Human-facing copy follows `outputLanguage`**, and the gap wording is the
|
|
103
101
|
fetcher's own `maturity.summary` verbatim. Re-deriving those labels here would
|
|
104
102
|
give the project two copies of one table and only one would be maintained.
|
|
103
|
+
- **Research comes first.** Under the autopilot runner a run parked here gets a
|
|
104
|
+
research pass before it is left waiting: tracker comments, links, linked
|
|
105
|
+
documents and the repo, checked source by source by `research-gate.mjs`, and
|
|
106
|
+
the maturity check re-run on the verified result
|
|
107
|
+
(`features/research.md`). A question is asked only for what that leaves open.
|
|
105
108
|
- **Then it stops.** The run halts on the circuit breaker (`features/autopilot-circuit-breaker.md`),
|
|
106
109
|
which is the sanctioned autopilot pause: state recorded, one actionable line
|
|
107
110
|
printed, waiting for `resume`. Posting a question and continuing on a guess is
|
|
108
111
|
worse than not asking - the guess lands in a branch while the question sits
|
|
109
112
|
unanswered.
|
|
113
|
+
- **A later scan does not pick it up again.** The autopilot intake keeps a
|
|
114
|
+
parked item in `awaiting` and never queues it on its own, whatever happens on
|
|
115
|
+
the item meanwhile. It moves only when a
|
|
116
|
+
person answers, through `resume <id> --answer` or a client, and the resumed run
|
|
117
|
+
re-enters this step with the item re-fetched (section 4).
|
|
110
118
|
|
|
111
119
|
**Not a second readiness reviewer.** `/multi-agent:review-jira` and
|
|
112
120
|
`/multi-agent:review-issue` also post a gap list, and they are a different thing: a
|
|
@@ -128,17 +136,29 @@ maturity step has `currentPhase: 0`, so resuming would start at Phase 1 and skip
|
|
|
128
136
|
the check - the halt would be permanent in the one direction that matters.
|
|
129
137
|
|
|
130
138
|
So resume reads `state.waitingFor` first: when it names a step, the run re-enters
|
|
131
|
-
THAT step rather than the next phase.
|
|
132
|
-
|
|
133
|
-
(`phases/phase-5-report.md`), while `resume/SKILL.md` never mentioned the field -
|
|
134
|
-
so that pause had the same gap and this fixes both.
|
|
139
|
+
THAT step rather than the next phase. Phase 5's channels pause resumes through
|
|
140
|
+
the same field (`phases/phase-5-report.md`).
|
|
135
141
|
|
|
136
142
|
| `waitingFor` | Re-entry |
|
|
137
143
|
|---|---|
|
|
138
|
-
| `maturity` | Phase 0, the maturity step, with the item re-fetched |
|
|
144
|
+
| `maturity` | Phase 0, the maturity step, with the item re-fetched. With `state.research.decision: "proceed"` the step re-scores through `research-gate.mjs --recheck` (below) |
|
|
145
|
+
| `question`, `pendingQuestion.stepId: phase-0/maturity` | the same step, reading `lastAnswer`: `fix` re-fetches and re-checks, `continue` records the gaps in `maturity.accepted[]`, `abort` stops |
|
|
139
146
|
| `user-channels-choice` | Phase 5, the channels menu |
|
|
140
147
|
| absent | `currentPhase + 1`, as before |
|
|
141
148
|
|
|
149
|
+
**After research.** `research-gate.mjs` writes `waitingFor: "maturity"` when the
|
|
150
|
+
re-run check passed on the verified findings. The step re-fetches as always, then:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
node "$HOME/.claude/scripts/research-gate.mjs" --state "$STATE_FILE" --recheck --descriptor "$FRESH" --json
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Exit 0: no blocker once the recorded verified findings are applied to the fresh
|
|
157
|
+
item; the printed `description` is the working description and `maturity` the
|
|
158
|
+
maturity. Exit 1: the gaps are back (a comment deleted, a status changed), and
|
|
159
|
+
the step takes the blocker path above. The edit rule holds: research moves
|
|
160
|
+
nothing on the item, and the check still decides.
|
|
161
|
+
|
|
142
162
|
`waitingFor` is cleared by the write that records the answer. A field that
|
|
143
163
|
outlives its question sends every later resume back to the step the user already
|
|
144
164
|
answered.
|
|
@@ -132,6 +132,15 @@ evidence, and there is now one fewer of them. Triage also runs on `opus`, which
|
|
|
132
132
|
makes it the same model as Reviewer 1; the Step 3 anonymisation requirement
|
|
133
133
|
already covers that case and is not optional here.
|
|
134
134
|
|
|
135
|
+
**Commands without Phase 0 resolve it themselves.** `/multi-agent:review`,
|
|
136
|
+
`/multi-agent:review-analysis` and the untracked-branch tail of
|
|
137
|
+
`/multi-agent:resume` dispatch reviewers and triage without a Phase 0 Step 0, so
|
|
138
|
+
each asks `lib/model-dispatch.sh subagent --persona <p> --default fable` for its
|
|
139
|
+
fable slots before any dispatch. The router applies this switch to the caller's
|
|
140
|
+
default on every path, routing on or off, so the answer is `opus` while the rung
|
|
141
|
+
is off. `smoke-model-dispatch.sh` holds both halves: the router's answer, and
|
|
142
|
+
that every command naming a Fable reviewer asks it.
|
|
143
|
+
|
|
135
144
|
**Cost accounting.** `prefs.global.costBudget.pricingModel` defaults to `fable` to
|
|
136
145
|
keep the estimate an upper bound. With the rung off, that default prices every
|
|
137
146
|
call above what it can cost and trips the budget ceiling early, which then
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Feature: Phone API
|
|
2
|
+
|
|
3
|
+
<!-- toc -->
|
|
4
|
+
- [What it is](#what-it-is)
|
|
5
|
+
- [Signing](#signing)
|
|
6
|
+
- [The bearer token and the signature do not mix](#the-bearer-token-and-the-signature-do-not-mix)
|
|
7
|
+
- [Enrolment](#enrolment)
|
|
8
|
+
- [Audit log](#audit-log)
|
|
9
|
+
- [Transport](#transport)
|
|
10
|
+
- [Residual risks](#residual-risks)
|
|
11
|
+
- [Not verified here](#not-verified-here)
|
|
12
|
+
- [Reference](#reference)
|
|
13
|
+
<!-- /toc -->
|
|
14
|
+
|
|
15
|
+
**Pattern**: a phone is the device most likely to be lost, borrowed or reached
|
|
16
|
+
over a network nobody here controls, so it gets the smallest surface that is
|
|
17
|
+
still useful: read the runs, answer the question a run stopped on, and, only
|
|
18
|
+
when the operator switches it on, queue a launch. Everything it sends is signed
|
|
19
|
+
by a key that never leaves it, and everything it reads is the redacted view.
|
|
20
|
+
|
|
21
|
+
The phone app is a separate project. This page is the pipeline side: the routes,
|
|
22
|
+
their security and the enrolment step. Nothing here needs the app to exist, and
|
|
23
|
+
the tests drive the routes with a key pair generated in the test.
|
|
24
|
+
|
|
25
|
+
## What it is
|
|
26
|
+
|
|
27
|
+
Four routes of `contract-server.mjs`, under `/v1/phone/`, served by the same
|
|
28
|
+
handlers as their desktop twins. The listener is the same process, still bound
|
|
29
|
+
to `127.0.0.1` only; the phone reaches it through a forwarder (see "Transport").
|
|
30
|
+
|
|
31
|
+
| Verb | Route | Scope | Backend (existing mechanism) |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| runs | `GET /v1/phone/runs[?group=G]` | `read` | `runs-index.mjs --json --redact` (`envelope`, `selectRuns`) |
|
|
34
|
+
| run | `GET /v1/phone/runs/{id}` | `read` | `runs-index.mjs --json --task-id {id} --redact` |
|
|
35
|
+
| answer | `POST /v1/phone/runs/{id}/answer` | `answer` | `answer-question.mjs` (`answerStateFile`): writes `lastAnswer`, clears `pendingQuestion` and `waitingFor` through `write-state.mjs` with a `rev` compare-and-swap |
|
|
36
|
+
| launch | `POST /v1/phone/launch?repo=P` | `launch` | `launch-request.mjs` (`planLaunch`, `writeRequestFile`), refused with `launch-disabled` until `phone-devices.mjs launch on` |
|
|
37
|
+
|
|
38
|
+
`pipeline/contract/manifest.json` declares all four under `surfaces` (with
|
|
39
|
+
`auth: "device-signature"` and `scope`) and the scheme under `phone`: path
|
|
40
|
+
prefix, header names, signed fields, window, future skew and scopes. A client reads those
|
|
41
|
+
instead of hardcoding them.
|
|
42
|
+
|
|
43
|
+
### Verbs that are not offered, and why
|
|
44
|
+
|
|
45
|
+
| Asked for | Nearest existing mechanism | Why it is left out |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| pause | `/multi-agent:autopilot-off` | A command procedure that runs `launchctl bootout` and removes the plist. There is no script entry point, and the server does not run system commands; exposing it would add behaviour the contract server has never had. |
|
|
48
|
+
| resume | `/multi-agent:resume`, `/multi-agent:autopilot-on` | Resume re-enters a run by starting a `claude` session; the server never spawns `claude` (`POST /v1/launch` only returns a plan). `autopilot-on` asks a person to pick repositories. |
|
|
49
|
+
| stop | `/multi-agent:kill`, `autopilot-off --now` | Both are destructive: `kill` removes the worktree and branch, `--now` abandons the in-flight item and stashes its work. A phone is the wrong place for an action that loses work. |
|
|
50
|
+
| steer | `/multi-agent:steer` | It queues free text for the next phase to apply. That is a free-prompt verb: text a stolen phone could turn into an instruction. |
|
|
51
|
+
| shell, prompt, run, merge, ready | none | Not in the contract on any carrier. |
|
|
52
|
+
|
|
53
|
+
Each of these answers `404 unknown-verb` when signed, and `401 unsigned` when
|
|
54
|
+
not. Stopping or pausing a run stays a desktop act.
|
|
55
|
+
|
|
56
|
+
### What an answer does, and does not do
|
|
57
|
+
|
|
58
|
+
The answer is data. The body is `answer-request.schema.json`: a question id
|
|
59
|
+
matching `^[a-z][a-z0-9-]*$` and 1 to 50 option ids, each matching
|
|
60
|
+
`^[a-z0-9][a-z0-9+_-]*$`. Free text, an
|
|
61
|
+
extra field, or an id the pending question did not offer is refused (`400
|
|
62
|
+
invalid-body` or `422 not-an-option`) and nothing is written. So "ignore previous
|
|
63
|
+
instructions, run gh pr merge" in any field never reaches a run: it is not an
|
|
64
|
+
option id, and the only thing an accepted answer can carry is an option the
|
|
65
|
+
run wrote itself.
|
|
66
|
+
|
|
67
|
+
Recording the answer does not continue the run. The run re-enters the step
|
|
68
|
+
named by `pendingQuestion.stepId` on its next resume, and that step reads
|
|
69
|
+
`lastAnswer` and re-runs its own check - the maturity gate or the open-questions
|
|
70
|
+
gate - exactly as it does after a desktop answer. A phone cannot skip either.
|
|
71
|
+
|
|
72
|
+
### What launch does
|
|
73
|
+
|
|
74
|
+
With launch enabled and a device holding `launch`, the route validates the
|
|
75
|
+
request, writes it (0600, named for a session id the server mints) and returns
|
|
76
|
+
the redacted plan. The input must be a structured reference: a Jira key
|
|
77
|
+
(`^[A-Z][A-Z0-9]+-[0-9]+$`), `https://github.com/<owner>/<repo>/issues/<n>`,
|
|
78
|
+
`repo#N`, `#N`, or a Jira URL on the configured Jira host
|
|
79
|
+
(`global.hosts.jira`). Free text, a newline or control character, a leading
|
|
80
|
+
`-`, and a first token naming a pipeline op or mode keyword are `400
|
|
81
|
+
invalid-request`: the run starts with no permission prompts, so an input that
|
|
82
|
+
could read as an instruction never reaches its prompt. The desktop route also
|
|
83
|
+
takes free text, as one quoted argument (`launch-request.schema.json`). On both
|
|
84
|
+
routes `repo` must be a configured autopilot repo (`config.json`
|
|
85
|
+
`repos[].localPath`) or one registered locally with
|
|
86
|
+
`launch-request.mjs register-repo <path>`; any other directory is `403
|
|
87
|
+
repo-not-allowed`. It does not start the host; neither the server nor the phone
|
|
88
|
+
can. The request waits for a desktop client to start it. Launch is off by
|
|
89
|
+
default because a queued launch is still a decision to spend money and to touch
|
|
90
|
+
a repository.
|
|
91
|
+
|
|
92
|
+
## Signing
|
|
93
|
+
|
|
94
|
+
Every phone request carries four headers:
|
|
95
|
+
|
|
96
|
+
| Header | Value |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `X-MA-Device` | the device id `phone-devices.mjs add` printed (`d-` plus 16 hex) |
|
|
99
|
+
| `X-MA-Timestamp` | Unix seconds |
|
|
100
|
+
| `X-MA-Nonce` | 16 to 64 base64url characters, fresh per request |
|
|
101
|
+
| `X-MA-Signature` | unpadded base64url Ed25519 signature, 86 characters |
|
|
102
|
+
|
|
103
|
+
The signed text is seven fields joined by `\n` (no trailing newline, UTF-8):
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
MA-PHONE-SIG-1
|
|
107
|
+
<method>
|
|
108
|
+
<target: path and query exactly as sent>
|
|
109
|
+
<lowercase hex SHA-256 of the raw body; the empty body too>
|
|
110
|
+
<device id>
|
|
111
|
+
<timestamp>
|
|
112
|
+
<nonce>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
No field may contain a newline, which is what makes the framing unambiguous.
|
|
116
|
+
`phone-signed-request.schema.json` describes it; `signRequest` in
|
|
117
|
+
`scripts/_phone-auth.mjs` is the reference implementation, and the tests build
|
|
118
|
+
the text by hand to pin it.
|
|
119
|
+
|
|
120
|
+
The server checks, in this order, and stops at the first failure:
|
|
121
|
+
|
|
122
|
+
| Check | Refusal |
|
|
123
|
+
|---|---|
|
|
124
|
+
| all four headers present and well formed | `401 unsigned` |
|
|
125
|
+
| the device id is in the registry | `401 unknown-device` |
|
|
126
|
+
| the timestamp is at most 60 seconds behind this machine's clock, at most 5 seconds ahead of it, and not earlier than the server's own start | `401 stale-request` |
|
|
127
|
+
| the signature verifies against the device's public key | `401 bad-signature` |
|
|
128
|
+
| the device is not revoked | `401 revoked-device` |
|
|
129
|
+
| the nonce was not seen inside its window | `401 replayed` |
|
|
130
|
+
| the nonce store has room | `503 replay-store-full` |
|
|
131
|
+
| the verb exists, with this method | `404 unknown-verb`, `405 method-not-allowed` |
|
|
132
|
+
| the device holds the verb's scope | `403 forbidden-scope` |
|
|
133
|
+
| `redact`, if given, is `1` | `400 invalid-query` |
|
|
134
|
+
| the body is JSON and satisfies the route's schema | `415`, `400`, then the route's own refusals |
|
|
135
|
+
|
|
136
|
+
Revocation is checked after the signature so only the key holder learns a
|
|
137
|
+
device was revoked. The nonce is recorded only after the signature verifies, so
|
|
138
|
+
an unsigned flood cannot fill the store. The store holds at most 4096 nonces
|
|
139
|
+
and refuses rather than evicts when full, because eviction is what a replay
|
|
140
|
+
needs. It is kept on disk as well as in memory
|
|
141
|
+
(`<autopilot root>/phone/nonces.json`, 0600, a truncated SHA-256 of each
|
|
142
|
+
device-and-nonce pair, pruned as windows close), so a request one server process
|
|
143
|
+
accepted is `replayed` to the next one after a restart. The start-time floor
|
|
144
|
+
cannot do that alone, because a timestamp ahead of the clock stays later than a
|
|
145
|
+
restart for as long as it is ahead; the 5 second future skew bounds that lead,
|
|
146
|
+
and the floor still covers a nonce file that was lost.
|
|
147
|
+
|
|
148
|
+
The registry is read on every request: a revocation or a launch toggle applies
|
|
149
|
+
to the next request without a restart. A registry other users can write, or
|
|
150
|
+
that another user owns, is treated as empty.
|
|
151
|
+
|
|
152
|
+
## The bearer token and the signature do not mix
|
|
153
|
+
|
|
154
|
+
- A path under `/v1/phone/` is authenticated by signature only. A valid bearer
|
|
155
|
+
token there is ignored, and the request is `401 unsigned` without a
|
|
156
|
+
signature.
|
|
157
|
+
- Every other path is authenticated by the bearer token only. A valid device
|
|
158
|
+
signature there is ignored, and the request is `401 unauthorized`.
|
|
159
|
+
- Route lookup is per family, so a phone path can never resolve to a desktop
|
|
160
|
+
handler or the reverse.
|
|
161
|
+
- The Host and Origin checks run first for both families, unchanged.
|
|
162
|
+
|
|
163
|
+
The desktop client's routes, token file and error bodies are the same; the
|
|
164
|
+
launch input and `repo` rules above apply to `POST /v1/launch` as well. The two
|
|
165
|
+
credentials answer different questions: the token proves
|
|
166
|
+
the caller can read a file on this machine, the signature proves the caller
|
|
167
|
+
holds a key enrolled on it. Neither is accepted in place of the other, so
|
|
168
|
+
leaking one does not widen the other.
|
|
169
|
+
|
|
170
|
+
## Enrolment
|
|
171
|
+
|
|
172
|
+
Local only; there is no route that adds a device.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
node "$HOME/.claude/scripts/phone-devices.mjs" add --name "work phone" \
|
|
176
|
+
--public-key <base64url raw Ed25519 public key> --scopes read,answer
|
|
177
|
+
node "$HOME/.claude/scripts/phone-devices.mjs" add --name "tablet" \
|
|
178
|
+
--public-key-file tablet.pub.pem --scopes read
|
|
179
|
+
node "$HOME/.claude/scripts/phone-devices.mjs" list
|
|
180
|
+
node "$HOME/.claude/scripts/phone-devices.mjs" revoke d-0123456789abcdef
|
|
181
|
+
node "$HOME/.claude/scripts/phone-devices.mjs" launch on # off by default
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The phone generates its key pair and shows the public half; the private key
|
|
185
|
+
never leaves it, and `add` refuses a PEM block holding a private key. `add`
|
|
186
|
+
prints the device id the phone then sends as `X-MA-Device`. Compare the
|
|
187
|
+
fingerprint `list` prints (the first 16 hex digits of the SHA-256 of the raw
|
|
188
|
+
public key) with the one the phone shows before trusting it.
|
|
189
|
+
|
|
190
|
+
The registry is `<autopilot root>/phone/devices.json` (`phone-devices.schema.json`),
|
|
191
|
+
mode 0600 in a 0700 directory: device id, name, public key, scopes, `addedAt`,
|
|
192
|
+
`revokedAt`, and the `launchEnabled` switch. The autopilot root is
|
|
193
|
+
`MA_AUTOPILOT_ROOT`, else `~/.claude/autopilot`, the directory the unattended
|
|
194
|
+
guard already forbids a run to write. `add`, `revoke` and `launch` refuse under
|
|
195
|
+
`MULTI_AGENT_UNATTENDED=1` (exit 3) and the guard blocks the same subcommands by
|
|
196
|
+
name, so an unattended run cannot enrol a device for whoever wrote its ticket.
|
|
197
|
+
|
|
198
|
+
Scopes: `read` (runs, run), `answer`, `launch`. There is no `control` scope,
|
|
199
|
+
because there is no control verb to grant.
|
|
200
|
+
|
|
201
|
+
## Audit log
|
|
202
|
+
|
|
203
|
+
Two files under `<autopilot root>/phone/`, both 0600, one line per request:
|
|
204
|
+
`{at, deviceId, method, verb, status, outcome}`. The device id is logged only
|
|
205
|
+
when it is well formed, the verb only when it is a plain word, and the outcome
|
|
206
|
+
is the error code. The signature, nonce, query string and body are never
|
|
207
|
+
written.
|
|
208
|
+
|
|
209
|
+
- `audit.jsonl` records every request whose signature verified, accepted or
|
|
210
|
+
not: `accepted`, `revoked-device`, `replayed`, `replay-store-full`,
|
|
211
|
+
`unknown-verb`, `method-not-allowed`, `forbidden-scope`, `launch-disabled`,
|
|
212
|
+
`repo-not-allowed` and the route's own refusals. It rotates past 256 KiB and
|
|
213
|
+
keeps five generations (`audit.jsonl.1` to `.5`).
|
|
214
|
+
- `refusals.jsonl` records refusals decided before a signature verified:
|
|
215
|
+
`unsigned`, `unknown-device`, `stale-request`, `bad-signature`, and in place
|
|
216
|
+
of `unknown-device` when the registry itself was the reason,
|
|
217
|
+
`registry-insecure` (writable by others or owned by another user) or
|
|
218
|
+
`registry-unreadable` (missing its device list or not JSON). These cost an
|
|
219
|
+
anonymous sender nothing, so the file takes at most 30 rows a minute per
|
|
220
|
+
server process; the first row after dropped ones carries `suppressed`, their
|
|
221
|
+
count. It rotates past 256 KiB with one generation. A flood of them never
|
|
222
|
+
rotates away a row in `audit.jsonl`. A device id alone does not move a row to
|
|
223
|
+
`audit.jsonl`: it is sent in clear on every request.
|
|
224
|
+
|
|
225
|
+
## Transport
|
|
226
|
+
|
|
227
|
+
The listener stays on `127.0.0.1`; `--host` still refuses anything else.
|
|
228
|
+
Something on this machine forwards to it. Whatever it is must pass the request
|
|
229
|
+
target unchanged (the target is signed) and present `Host: 127.0.0.1:<port>`
|
|
230
|
+
(the Host check is not relaxed for phone routes).
|
|
231
|
+
|
|
232
|
+
**A private network (Tailscale or similar).** The phone and this machine join
|
|
233
|
+
the same tailnet, and a forwarder on this machine publishes the loopback port
|
|
234
|
+
to the tailnet only, for example `tailscale serve` pointed at
|
|
235
|
+
`http://127.0.0.1:<port>`. The tailnet supplies transport encryption and device
|
|
236
|
+
identity at the network layer; the signature supplies it at the request layer,
|
|
237
|
+
so a compromised tailnet node still cannot send a command. Keep the forward
|
|
238
|
+
tailnet-only: never `tailscale funnel`, which publishes to the internet.
|
|
239
|
+
|
|
240
|
+
**A signed relay.** When the phone cannot join a private network, a relay
|
|
241
|
+
outside both ends carries requests. Only the local side is specified here, and
|
|
242
|
+
nothing ships for it:
|
|
243
|
+
|
|
244
|
+
- the local agent opens an outbound TLS connection to the relay and holds it;
|
|
245
|
+
nothing listens on a public interface;
|
|
246
|
+
- it receives `{method, target, headers, body}` frames, forwards each to
|
|
247
|
+
`http://127.0.0.1:<port>` with `Host` rewritten to that address and every
|
|
248
|
+
`X-MA-*` header, the target and the body bytes untouched, and returns
|
|
249
|
+
`{status, headers, body}`;
|
|
250
|
+
- it forwards only paths under `/v1/phone/`, and never adds an `Authorization`
|
|
251
|
+
header: the bearer token stays on this machine;
|
|
252
|
+
- the relay sees ciphertext only if the phone and the local agent add their own
|
|
253
|
+
end-to-end layer; without one, the relay operator can read the redacted
|
|
254
|
+
responses and answers, but cannot forge or replay a command, because it holds
|
|
255
|
+
no device key and the window and nonce checks still apply.
|
|
256
|
+
|
|
257
|
+
## Residual risks
|
|
258
|
+
|
|
259
|
+
- **A stolen, unlocked phone is a valid device** until it is revoked. Scopes
|
|
260
|
+
bound what it can do: read the redacted runs, pick an offered option, and,
|
|
261
|
+
only if enabled, queue a launch. It cannot merge, push, stop, steer or run a
|
|
262
|
+
command. Revoke from this machine; it applies on the next request.
|
|
263
|
+
- **Same-user code can enrol a device.** The registry is protected from an
|
|
264
|
+
unattended run by the guard and by `phone-devices.mjs` itself, but a process
|
|
265
|
+
running as the same user with arbitrary code (the "Bash can write in ways the
|
|
266
|
+
hook cannot see" risk in `features/unattended-security.md`) can write the
|
|
267
|
+
file directly, as it could read the bearer token file today. Run the server
|
|
268
|
+
as the operator, and the runner as the separate user that document
|
|
269
|
+
recommends.
|
|
270
|
+
- **The redacted view is not empty.** Task ids, project names, phase names,
|
|
271
|
+
statuses and scrubbed question text still leave the machine. That is the
|
|
272
|
+
point of the view; it is not a secret-free channel.
|
|
273
|
+
- **Clock skew.** A phone more than 60 seconds behind or 5 seconds ahead of
|
|
274
|
+
this machine's clock is refused until its clock is corrected; for the first
|
|
275
|
+
seconds after a server start, a phone whose clock runs behind is refused by
|
|
276
|
+
the start-time floor. Its refusals land in `refusals.jsonl`, which is
|
|
277
|
+
rate-limited.
|
|
278
|
+
- **Replay inside the window, across a nonce store at capacity.** The store
|
|
279
|
+
refuses new requests when full instead of forgetting live nonces, so the cost
|
|
280
|
+
is availability, not a replay.
|
|
281
|
+
- **An answer can still be the wrong option.** Only offered options are
|
|
282
|
+
accepted, but a person picking "continue" from a phone on a maturity blocker
|
|
283
|
+
is a real decision; the gate re-runs on resume and still refuses what it
|
|
284
|
+
refused before.
|
|
285
|
+
|
|
286
|
+
## Not verified here
|
|
287
|
+
|
|
288
|
+
No real phone, Tailscale forward or relay has exercised these routes. The tests
|
|
289
|
+
cover the server side end to end on an ephemeral `127.0.0.1` port with keys
|
|
290
|
+
generated per test run. Whether a given forwarder preserves the target and sets
|
|
291
|
+
`Host` as required is for the operator to check against the Host and signature
|
|
292
|
+
refusals above.
|
|
293
|
+
|
|
294
|
+
## Reference
|
|
295
|
+
|
|
296
|
+
Scripts: `contract-server.mjs` (phone branch, `isPhonePath`), `_phone-auth.mjs`
|
|
297
|
+
(`canonicalPayload`, `verifyRequest`, `signRequest`, `createNonceStore`,
|
|
298
|
+
`readRegistry`, `appendAudit`), `launch-request.mjs` (`inputErrors`,
|
|
299
|
+
`launchRepoAllowed`, `register-repo`), `phone-devices.mjs`. Schemas:
|
|
300
|
+
`phone-signed-request.schema.json`, `phone-devices.schema.json`,
|
|
301
|
+
`contract-error.schema.json`, `answer-request.schema.json`,
|
|
302
|
+
`launch-request.schema.json`,
|
|
303
|
+
`unattended-policy.json` (`publisherScripts`). Tests:
|
|
304
|
+
`test/phone-api.test.mjs`, `test/contract-server.test.mjs`,
|
|
305
|
+
`test/launch-request.test.mjs`, `test/redact.test.mjs`,
|
|
306
|
+
`test/contract-kit.test.mjs`, `test/unattended-guard.test.mjs`.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Feature: Plan critic, one round
|
|
2
|
+
|
|
3
|
+
<!-- toc -->
|
|
4
|
+
- [When it runs](#when-it-runs)
|
|
5
|
+
- [Why one round, fixed roles](#why-one-round-fixed-roles)
|
|
6
|
+
- [The critic](#the-critic)
|
|
7
|
+
- [The reply](#the-reply)
|
|
8
|
+
- [The judge](#the-judge)
|
|
9
|
+
- [Advisory objections](#advisory-objections)
|
|
10
|
+
- [The ledger, and why it is not mandatory at commit](#the-ledger-and-why-it-is-not-mandatory-at-commit)
|
|
11
|
+
- [Limits](#limits)
|
|
12
|
+
- [Reference](#reference)
|
|
13
|
+
<!-- /toc -->
|
|
14
|
+
|
|
15
|
+
**Pattern**: before a plan is built on, one critic with one task asks why it
|
|
16
|
+
will fail. The planner answers each objection once, and a script decides, by
|
|
17
|
+
constitution rule id, whether any answer leaves a binding rule broken. There is
|
|
18
|
+
no second round and no model scoring the exchange.
|
|
19
|
+
|
|
20
|
+
## When it runs
|
|
21
|
+
|
|
22
|
+
At the end of Phase 1, after Step 12 (the plan validated, spec consistency
|
|
23
|
+
checked) and before Phase 2, only while the quality gates are active
|
|
24
|
+
(`lib/unattended.mjs`, `gatesActive`: `MULTI_AGENT_UNATTENDED=1` or
|
|
25
|
+
`state.autopilot === true`). An attended run is unchanged: no critic is
|
|
26
|
+
dispatched and plan approval stays with the person, who is the critic there. If
|
|
27
|
+
`plan-critique-gate.mjs` is invoked attended anyway, it prints its report marked
|
|
28
|
+
advisory, exits 0 (3 on a usage error) and writes nothing.
|
|
29
|
+
|
|
30
|
+
The pipeline has no separate product mode. The nearest thing, a repo-less
|
|
31
|
+
analysis (`No platform yet`, Locked 34) followed by `/multi-agent:analysis-jira`,
|
|
32
|
+
has no planner to answer an objection: its story tree is derived from the
|
|
33
|
+
document's own ids by `analysis-story-tree.mjs`, deterministically, and a flaw in
|
|
34
|
+
it is fixed in the analysis. The critic runs only on a Phase 1 plan.
|
|
35
|
+
|
|
36
|
+
## Why one round, fixed roles
|
|
37
|
+
|
|
38
|
+
Multi-round debate between agents tends to move them toward each other rather
|
|
39
|
+
than toward the right answer: agreement grows round by round whether or not
|
|
40
|
+
accuracy does ("Debate or Vote", NeurIPS 2025; "Talk Isn't Always Cheap"). So
|
|
41
|
+
the exchange is bounded the way `ai-common-toolkit:council` bounds a decision,
|
|
42
|
+
three voices, one round, one page, and each side keeps one role: the critic
|
|
43
|
+
objects, the planner answers, the gate judges. Nobody replies to a reply.
|
|
44
|
+
|
|
45
|
+
## The critic
|
|
46
|
+
|
|
47
|
+
Persona `agents/plan-critic.md`, dispatched through the model router so it
|
|
48
|
+
follows the fable switch the way review does: fable while the rung is on, opus
|
|
49
|
+
while it is off.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
CRITIC_RUNG=$(bash "$HOME/.claude/lib/model-dispatch.sh" subagent --persona plan-critic --phase 1 --default fable)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
It reads the plan, the analysis document(s), the constitution and the worktree,
|
|
56
|
+
and writes objections under four lenses: `scope`, `feasibility`, `security`,
|
|
57
|
+
`alternative` (a cheaper plan with the same result). Each objection has an id
|
|
58
|
+
(`OBJ-NN`), a lens, a claim, at least one evidence anchor and, when the plan
|
|
59
|
+
breaks one, a constitution rule id. The orchestrator writes the output to
|
|
60
|
+
`$WORKTREE/.pipeline/plan-critique.json` (`schemas/plan-critique.schema.json`)
|
|
61
|
+
with `replies` empty.
|
|
62
|
+
|
|
63
|
+
**Why a persona and not council.** Council fits a decision with several
|
|
64
|
+
credible options: three voices argue, and the caller decides. The critic has no
|
|
65
|
+
options to weigh and must not decide. It is one voice attacking one plan, and
|
|
66
|
+
its output is anchored JSON a script can check, not a tradeoff table. Council's
|
|
67
|
+
own table sends "checking whether output is correct" to a verification pass.
|
|
68
|
+
What the critic takes from council is the bound: one round.
|
|
69
|
+
|
|
70
|
+
| Anchor | `ref` | Checked by the gate |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `file` | `path:line`, optional `quote` | resolved in the working tree the way `verify-citations.mjs` resolves a citation: the file exists, the line is in range, the quote is on the line |
|
|
73
|
+
| `plan` | a task id | the plan has that task |
|
|
74
|
+
| `analysis` | a requirement id, or the whole text of a heading | an analysis document defines the id, or has a heading with exactly that text (its section number optional); a fragment of a heading does not resolve |
|
|
75
|
+
| `inference` | the one-line reasoning | never |
|
|
76
|
+
|
|
77
|
+
An objection none of whose anchors resolves is labelled `inference`. An anchor
|
|
78
|
+
that does not resolve is listed in the report.
|
|
79
|
+
|
|
80
|
+
## The reply
|
|
81
|
+
|
|
82
|
+
The planner answers every objection exactly once, in `replies[]` of the same
|
|
83
|
+
file:
|
|
84
|
+
|
|
85
|
+
- `accept`: revise the plan (overwrite `plan.json` and re-run
|
|
86
|
+
`validate-planning.mjs`), say how in `revision`, and anchor the reply to the
|
|
87
|
+
task that now carries the fix (`plan`).
|
|
88
|
+
- `rebut`: show that the objection does not hold, with at least one anchor.
|
|
89
|
+
|
|
90
|
+
## The judge
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
node "$HOME/.claude/scripts/plan-critique-gate.mjs" --state "$STATE_FILE" \
|
|
94
|
+
--critique "$WORKTREE/.pipeline/plan-critique.json" --plan "$WORKTREE/.pipeline/plan.json"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`--analysis` defaults to `state.analysis.docPath`, `--constitution` to the
|
|
98
|
+
knowledge store (`constitution.mjs`). No model call, and the mapping is by id:
|
|
99
|
+
|
|
100
|
+
| Objection | Reply | Result |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| cites a `binding` rule | accept with a revision and a `plan` anchor that resolves, or rebut with an anchor that resolves; a `file` anchor counts only as `path:line` with a `quote` of that line | advisory |
|
|
103
|
+
| cites a `binding` rule | anything else, including a rebuttal that is inference alone | **blocks** |
|
|
104
|
+
| cites a `proposed` rule, a rule the constitution does not define, or no rule | any | advisory |
|
|
105
|
+
| any, with no constitution file | any | advisory |
|
|
106
|
+
|
|
107
|
+
The protocol is checked in code before any objection is judged: `round` other
|
|
108
|
+
than 1, an objection with no reply, one with two replies, a reply to an
|
|
109
|
+
objection nobody raised, or a second critique of a run already judged (a
|
|
110
|
+
different critique, or different replies, from the one in
|
|
111
|
+
`state.planCritique`) is a protocol failure. Re-running the gate on the same
|
|
112
|
+
file is the same verdict.
|
|
113
|
+
|
|
114
|
+
| Exit | Verdict in the ledger | The run |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| 0 | `pass` | continues to Phase 2 |
|
|
117
|
+
| 1 | `fail`: a blocking objection, or the protocol broken | parked as `verification-failed` by the gate itself (`verificationFailed.gate: plan-critique`); Phase 2 does not start |
|
|
118
|
+
| 2 | `not-applicable`: no plan | continues |
|
|
119
|
+
| 3 | `fail`: the critique, plan, analysis or constitution unreadable, or the critique not in schema shape | parked the same way |
|
|
120
|
+
|
|
121
|
+
A failure is not retried: a second attempt would be the second round this
|
|
122
|
+
design refuses.
|
|
123
|
+
|
|
124
|
+
## Advisory objections
|
|
125
|
+
|
|
126
|
+
Everything that does not block is returned in `advisory[]` and kept in
|
|
127
|
+
`state.planCritique.advisory`, each with its lens, claim, label, rule status and
|
|
128
|
+
the reply's action. Phase 1 carries them into the plan render (the Step 5b
|
|
129
|
+
plan, logged in autopilot); Phase 4 lists them in the PR summary under `## Related`,
|
|
130
|
+
marked advisory, so a reviewer sees what the critic raised and how it was
|
|
131
|
+
answered.
|
|
132
|
+
|
|
133
|
+
## The ledger, and why it is not mandatory at commit
|
|
134
|
+
|
|
135
|
+
With the gates active every verdict is appended to `state.gates[]` as
|
|
136
|
+
`plan-critique`. It is not in `MANDATORY_AT_COMMIT`. A gate joins that list only
|
|
137
|
+
when every gated run has something for it to check, and not every gated run has
|
|
138
|
+
a plan: `/multi-agent:resume autopilot` over work with no run behind it runs the
|
|
139
|
+
pipeline tail, review then commit, with no Plan phase. A mandatory entry would
|
|
140
|
+
block those commits for a phase they never entered. The decision point is the
|
|
141
|
+
start of Phase 2, and a failing verdict parks the run there.
|
|
142
|
+
|
|
143
|
+
## Limits
|
|
144
|
+
|
|
145
|
+
- The gate checks that an anchor resolves, not that it proves the claim. A
|
|
146
|
+
rebuttal citing a real but irrelevant line resolves a binding objection;
|
|
147
|
+
review is where that is caught.
|
|
148
|
+
- The critic is invoked by the agent at the end of Phase 1. An agent that skips
|
|
149
|
+
it leaves no ledger entry, and nothing blocks the commit on that account.
|
|
150
|
+
- While the fable rung is off the critic runs on opus, the planner's model.
|
|
151
|
+
|
|
152
|
+
## Reference
|
|
153
|
+
|
|
154
|
+
Script: `plan-critique-gate.mjs`. Persona: `agents/plan-critic.md`. Schema:
|
|
155
|
+
`plan-critique.schema.json`; state key `planCritique` in
|
|
156
|
+
`agent-state.schema.json`. Tests: `test/plan-critique-gate.test.mjs`, fixtures in
|
|
157
|
+
`test/fixtures/plan-critique/`; smokes `smoke-gates-interactive-noop.sh`,
|
|
158
|
+
`smoke-model-dispatch.sh`. Related: `features/constitution.md`,
|
|
159
|
+
`features/unattended-gates.md`.
|