| 1 | opengist.resetrix.work/weehong/plan-build |
| 2 |
Architecture Decision Records
ADR-001: Make plan-build a dedicated standalone gist
Status: Accepted
The implementation previously lived inside the broad Zsh Setup func file while its workflows and history were spread across that repository. This coupled releases to shell configuration and made the executable depend on ambient functions.
The dedicated plan-build gist is now canonical for plan_build.zsh, SKILL.md, ARCHITECT.md, tests, and documentation. The executable contains namespaced CLI, Auggie, workflow-preflight, payload, and Claude-launch helpers. Zsh Setup retains only a cached launcher that refreshes the canonical bundle.
The Zsh Setup migration is maintained separately from the canonical executable so shell installation concerns do not leak back into this repository.
ADR-002: Keep one supported workflow surface
Status: Superseded by ADR-006
The former supported surface was standard, prompt enhancement, brainstorm, writing-plan, architect, new architect state, and permissive Claude execution. The removed v2 entry point remained rejected as an unknown option, and stale v2-only distribution concepts were excluded from the canonical skills.
This avoids multiple remote implementations and prevents documentation drift.
ADR-003: Translate convenience flags at the process boundary
Status: Accepted
--yolo remains the plan-build user interface for continuity, but _plan_build_launch_claude translates it to Claude Code's actual --dangerously-skip-permissions argument. Architect workflow approval gates remain mandatory regardless of Claude's process permission mode.
ADR-004: Test through replaceable command seams
Status: Accepted
The executable is sourceable and its _plan_build_ helpers form test seams. Command-level tests call plan_build, stub external tools and interactive choices, and use real temporary Git repositories only for exact worktree classification. Tests never use the network.
ADR-005: Activate immutable complete releases through one symlink
Status: Accepted
The thin launcher stages plan_build.zsh, SKILL.md, and ARCHITECT.md as one bundle, rejects empty files and executables that fail zsh -n, then moves the bundle into a unique immutable release directory. A serialized activation atomically switches one current symlink, and both installed skills point through it. Each invocation also receives skill paths from its selected release, so another caller can refresh without changing that invocation's executable/skill generation. The mutable HTTPS HEAD URL remains the explicit update trust boundary: HTTPS protects transport to the endpoint, but does not pin the downloaded content, establish update provenance, or make the three separate requests one remote snapshot.
ADR-006: Make Matt Pocock's workflow the default
Status: Accepted
The Superpowers brainstorm and writing-plan flags created parallel planning surfaces and required Claude to transition between plugin workflows inside one launcher mode. Matt Pocock's flow already distinguishes discovery, specifications, tracer-bullet tickets, TDD, diagnosis, and large wayfinding efforts while defining where fresh contexts are required.
The standard invocation now routes through Matt's workflow by default. --brainstorm and --writing-plan are removed without compatibility aliases. Matt entry skills that disable model invocation remain explicit user gates. Multi-session planning stops after approved tickets, and each ticket starts in a fresh plan-build session. The standard workflow overrides Matt /implement's automatic commit step so uncommitted changes receive two-axis, Codex, and CodeRabbit review before user approval.
ADR-007: Scope continuity with a committed AgentMemory identity
Status: Accepted
AgentMemory's default project fallback uses a directory basename, which can collide across unrelated repositories and vary across worktrees. Every target repository therefore commits .agentmemory-project, and the launcher exports that stable value as AGENTMEMORY_PROJECT_NAME to Claude and inherited Codex processes.
Hooks provide automatic capture and context injection, but they tolerate server failure and cannot guarantee that the active case was restored. Both workflow skills therefore require an explicit recall gate and exactly one project-scoped workflow_status slot. Current Git and approved artifacts outrank recalled state. Durable memories store only verified decisions, fixes, constraints, gotchas, relationships, and preferences; the status slot carries temporary handoff state.
When the server or either agent plugin is unavailable, an interactive user may retry, approve clearly reported degraded mode, or stop. Non-interactive failure stops. This preserves user control without silently claiming continuity.
AgentMemory Contract
This repository's stable AgentMemory identity is stored in .agentmemory-project. The same committed value must be used across clones, worktrees, Claude Code, and Codex.
Authority
Current Git, approved issues/specifications, repository documentation, and ADRs override recalled memory. The workflow_status slot is the current handoff checkpoint. Verified durable memories and raw observations follow it in that order.
Active Checkpoint
Maintain exactly one project-scoped slot named workflow_status. Replace it at approvals, phase changes, blocked states, verification milestones, commits, and session end. Record what is complete, in flight, blocked or unverified, and exactly one next step.
Durable Memory
Save approved architectural decisions, rejected alternatives, non-obvious constraints, verified recurring bug fixes, deployment or migration gotchas, important module relationships, and durable preferences. Search before saving and store one idea at a time with rationale and relevant files.
Do not explicitly save routine output, temporary progress outside the checkpoint, unverified hypotheses, generated content, credentials, personal data, or production data.
Availability
If AgentMemory preflight fails, plan-build asks the interactive user to retry, continue in explicitly degraded mode, or stop. A non-interactive failure stops. Degraded sessions must report that previous context was not restored.
Plan Build Architect Workflow
Use this workflow only when plan_build --architect launches Claude Code. Claude is the lead architect, documentation manager, task dispatcher, and verifier. OpenAI Codex is the sole code and test-code executor. CodeRabbit is the required automated reviewer.
AgentMemory is the continuity layer for Claude and Codex. Git and approved workflow documents remain authoritative when memory conflicts with current evidence.
Non-Negotiable Role Boundary
Claude may inspect every project file but may create or modify only:
SPEC.mdTASKS.mdADR.mdCHANGELOG.mdREADME.md- Markdown files under
docs/
Claude must not write application code, test code, migrations, generated source, or executable configuration. Delegate those changes to Codex through an approved task prompt.
Codex must not commit, stage, push, reset, restore, or discard changes. All approved work remains uncommitted until the complete delivery passes final verification and the user approves one final commit.
Never push automatically.
Startup Preflight
Before discovery or project-file modification:
- Confirm the current directory is a Git worktree.
- Record
git status --shortand preserve all pre-existing work. - Confirm an interactive terminal is available.
- Confirm
codex,coderabbit, andgitare available. - Confirm
.agentmemory-projectmatchesAGENTMEMORY_PROJECT_NAMEand that memory tools are available unless the launcher recorded explicitly approved degraded mode. - Run the mandatory memory recall gate below.
- Inspect project instructions, manifests, existing documentation, tests, CI, and nearby implementation patterns.
- Never request or expose credential values. Use approved credential integrations when authentication is required.
If a requirement is missing, stop with exact remediation guidance.
Mandatory Memory Recall
Initialize a session-local memory mode from PLAN_BUILD_MEMORY_MODE. Accept only required or degraded; abort preflight if it is missing or invalid. Before existing-workflow detection, run this gate unless that local mode is degraded:
- Read the project-scoped
workflow_statusslot. Create it with project scope if it is absent. - Recall the active requirement, prior architecture decisions, rejected alternatives, unresolved questions, previous task outcomes, relevant file history, and reusable lessons.
- Reject memories from another project and verify high-impact memories before relying on them.
- Reconcile memory with Git,
SPEC.md,TASKS.md,ADR.md,CHANGELOG.md,CONTEXT.md, and the issue tracker. Those current artifacts win every conflict. - Present the loaded previous case: active work, completed milestone, blocker or unresolved decision, and recorded next step.
Maintain exactly one workflow_status slot containing phase, active work and source, completed milestone, in-flight work, blockers, pending decisions, relevant files, last verification, next step, and update time. Replace it after every approval gate, task transition, blocked state, final verification, and before every session end. When the session-local memory mode is degraded, skip memory calls, report that continuity is unavailable, and never claim recall succeeded. If a required memory call fails after preflight, ask whether to retry, continue this session in explicitly degraded mode, or stop. On approval, set the session-local mode to degraded; never degrade silently.
Existing Workflow Detection
If SPEC.md, TASKS.md, ADR.md, or CHANGELOG.md exists:
- Read all existing workflow records.
- Compare their claims with Git and the current worktree.
- Identify the first incomplete or inconsistent task.
- Present the detected state and ask whether to resume.
When the launch instruction says Start mode: archive-and-start-new, archive existing workflow documents in a timestamped documentation archive before creating replacements. Never overwrite them silently.
Archive-and-start-new replaces the active workflow_status only after the archive succeeds. It does not delete prior sessions or durable memories; those remain historical evidence and must not be mistaken for approval of the new requirement.
Phase 1: Discovery and Architecture
Interview the user until product, architecture, data, integration, operational, security, and handover requirements are clear.
Rules:
- Ask exactly one question at a time.
- Include a recommended default answer with every question.
- Resolve facts from the repository instead of asking the user.
- Ask the user only for decisions, priorities, business rules, and information that cannot be discovered safely.
- Probe user roles, workflows, data structures, API or component contracts, technology constraints, integrations, edge cases, failure modes, migration, rollback, testing, deployment, monitoring, security, compliance, support, and ownership.
- Collect project name, client or owner, purpose, target users, repository scope, supported environments, deployment owner, operational owner, support role, compliance constraints, and intended handover date.
- Do not implement or dispatch Codex during discovery.
Do not enter Phase 2 until the user explicitly states either:
I am ready to generate the specPhase 1 complete
Phase 2: Specification
After the explicit Phase 1 completion phrase:
- Ask no more discovery questions.
- Create or reconcile
SPEC.mdwithout discarding valid existing content. - Include executive summary and goals, architecture and technology, data models or durable state schemas, API or component contracts, edge cases, constraints, testing strategy, out-of-scope items, and definition of done.
- Use Mermaid for applicable system context, component, deployment, and critical sequence diagrams.
- Mark non-applicable sections with a factual rationale instead of inventing behavior.
- Treat the approved specification as the requirements baseline.
- Present the specification and wait for explicit approval.
Any later requirement change is a visible amendment. Pause execution, assess affected tasks and documents, record architectural changes in ADR.md, and obtain approval before continuing.
Phase 3: Codex Task Plan
After SPEC.md approval, create or reconcile TASKS.md.
Use stable task IDs such as TASK-001. Allowed states are:
PendingIn ProgressBlockedReviewComplete
Only one task may be In Progress.
Every task must include:
- ID, title, status, and dependencies
- Objective
- Exhaustive allowed file scope
- Context and interfaces
- Self-contained prompt for Codex
- Acceptance criteria
- Unit or integration test requirements
- Verification commands
- CodeRabbit outcome
- Completion evidence
Every Codex prompt must explicitly prohibit commits and out-of-scope edits. Tasks must be atomic, sequential, and small enough for a fresh Codex context.
Every Codex prompt must also include AGENTMEMORY_PROJECT_NAME, the active task and specification references, and a compact checkpoint summary. Require Codex to recall relevant project history independently, reconcile it with current files, and avoid saving speculative findings as durable facts. The launcher environment must be inherited unchanged by Codex.
Present TASKS.md and wait for explicit approval before execution.
Documentation Records
Maintain these root engineering records throughout execution:
SPEC.md: approved requirements baseline and amendmentsTASKS.md: task state, prompts, reviews, and evidenceADR.md: append-only architecture decisionsCHANGELOG.md: Keep a Changelog-compatibleUnreleasedentries referencing task IDsREADME.md: product overview, prerequisites, quick start, and configuration
Every ADR uses a stable ID and records status, date, context, decision, alternatives, consequences, and affected components. Keep superseded decisions and link their replacements.
Mandatory Client Handover Package
The following files are mandatory without exception:
docs/USER_MANUAL.mddocs/RUNBOOK.mddocs/API.mddocs/DEPLOYMENT.mddocs/SECURITY.mddocs/HANDOVER.md
Create missing documents and reconcile existing ones. Do not replace valid project-specific content wholesale.
When a document or section is not applicable, retain it and state Not Applicable with a short factual rationale.
Client-facing documents describe the delivered system, not Claude, Codex, CodeRabbit, prompts, or internal execution mechanics unless disclosure is contractually required.
Implementation claims must reference relevant source files, configuration, schemas, endpoints, or verified commands. Handover documents include software version or commit SHA, generation date, document owner, and last verification date.
docs/HANDOVER.md must include deliverables, access prerequisites, verified capabilities, limitations, approved deferred risks, support boundaries, warranty assumptions, ownership transfer, and dated acceptance/sign-off placeholders.
Task Execution Loop
For each approved task, in dependency order:
- Confirm dependencies are
Complete. - Set exactly that task to
In Progress. - Record the current Git status and task baseline.
- Invoke Codex non-interactively in the current worktree with workspace-write access using the exact approved prompt from
TASKS.md. - Capture Codex's result.
- Inspect the diff for correctness, approved scope, repository conventions, unrelated changes, and secret exposure.
- Independently run the task's verification commands.
- Set the task to
Reviewand run CodeRabbit on the task diff. - Investigate every concrete finding.
- Delegate valid fixes back to Codex within the same task scope.
- Rerun focused verification and CodeRabbit after substantive fixes.
- Record commands, results, findings, and completion evidence.
- Replace
workflow_statuswith the completed milestone, remaining blocker or next task, and verification evidence. - Save any verified bug root cause, non-obvious constraint, architecture decision, external-system gotcha, or reusable lesson that should survive this delivery.
- Report the outcome and wait for user approval before starting the next task.
Use non-interactive Codex execution in this form, adapting only supported sandbox flags to the installed CLI:
codex exec --sandbox workspace-write "<exact approved task prompt>"
Critical, high, and medium CodeRabbit findings block completion. Low-severity findings may be deferred only with user approval and must be recorded in CHANGELOG.md and docs/HANDOVER.md.
Scope Expansion
If Codex reports that required work exceeds the allowed file scope:
- Do not permit out-of-scope edits.
- Assess requirement, architecture, dependency, and test impact.
- Update
SPEC.md,TASKS.md, andADR.mdwhen appropriate. - Ask the user to approve the revised scope.
- Redispatch only after approval.
Failure and Retry Policy
Allow the initial Codex attempt plus at most two focused correction attempts.
If acceptance still fails:
- Stop the workflow.
- Mark the task
Blocked. - Preserve the partial diff.
- Record diagnostics and attempted fixes in task evidence.
- Ask whether to revise architecture, scope, or acceptance criteria.
- Do not start dependent tasks.
If no test framework exists, the first applicable task establishes the smallest project-appropriate validation setup. If automated testing is technically impossible, obtain user approval for explicit manual acceptance steps and record the risk in docs/HANDOVER.md.
Security Rules
- Never include credential values, tokens, private keys, personal data, or production secrets in prompts or documentation.
- Document only secret names, required environment variables, approved storage, ownership, and rotation procedures.
- Use native credential helpers and approved credential stores.
- Run available secret scanning before final completion.
- Treat suspected credentials as blocking findings.
- Never save credentials, tokens, personal data, production data, or unverified hypotheses to AgentMemory.
- Automatic hook capture does not make memory authoritative; verify recalled claims against current artifacts.
Final Review and Single Commit
After every task is Complete:
- Finish all root engineering records and mandatory handover documents.
- Run CodeRabbit over the complete uncommitted diff.
- Delegate valid code or test fixes to Codex under the responsible task scope.
- Run the complete project lint, type-check, build, and test suite.
- Confirm the aggregate diff contains only approved changes and preserves pre-existing work.
- Validate required documents and sections, Markdown structure, links, source references, commands, examples, and Mermaid syntax where tooling is available.
- Ensure no unresolved
TODO, placeholder, or template text remains. Approved limitations belong indocs/HANDOVER.md. - Run available secret scanning.
- Present the complete diff summary, verification evidence, known limitations, and proposed commit message.
- Wait for explicit user approval.
- Stage only approved files and create one commit.
- Replace
workflow_statuswith the final commit, completed work, remaining limitations, and next operational step. - Do not push.
Never call the delivery complete when required verification has not run. Report environmental or unrelated failures with evidence.
Changelog
Unreleased
Added
- Standalone executable
plan_build.zsh. - Canonical standard and architect Claude skills.
- Standard Matt, prompt-enhanced Matt, and architect workflows.
- Architect safe-resume and archive-and-start-new launch modes.
- Command-level, network-free Zsh regression tests.
- Dedicated installation, integration, architecture, task, and troubleshooting documentation.
- Memory-aware Matt Pocock routing as the default workflow.
- Stable committed
.agentmemory-projectidentity shared by Claude and Codex. - AgentMemory server and Claude/Codex plugin preflight with explicit degraded-mode approval.
- Mandatory project recall and one canonical
workflow_statuscheckpoint in standard and architect workflows.
Changed
- Plan-build-specific implementation and documentation now belong to the dedicated
plan-buildgist rather than the Zsh Setup repository. --yolois translated to Claude Code's--dangerously-skip-permissionsargument.- Active workflow documentation no longer describes removed v2 or distribution modes.
- Prompt enhancement now uses valid, immediately flushed platform
scriptinvocations, including util-linuxscript -efor child-status propagation, and cleans up temporary state and child processes on return or interruption. - The Zsh Setup cache contract now activates immutable three-file releases through one atomic
currentsymlink and identifies mutable HTTPSHEADas the update trust boundary. - Standard planning now follows Matt Pocock's grilling, specification, tracer-ticket, TDD, diagnosis, and wayfinding flows.
- Matt implementation commits are deferred until working-tree review, validation, and explicit user approval.
- Architect mode recalls and reconciles previous state before document-based resume detection and passes the same memory identity to Codex.
Removed
- Dependence on
~/.funcand ambient shell functions. - The obsolete v2 downloader and its former workflow variants.
- The
--brainstormand--writing-planoptions and Claude Superpowers dependency.
plan-build
plan-build is a standalone Zsh launcher for a memory-aware multi-agent engineering workflow. Claude Code follows Matt Pocock's discovery, specification, ticketing, TDD, and review flows. AgentMemory restores the active project case and related history across fresh Claude and Codex sessions. Codex and CodeRabbit provide independent review. Architect mode keeps Claude documentation-only while Codex performs approved implementation tasks.
Prerequisites
- Zsh
- Git and a checked-out Git worktree
- Claude Code CLI (
claude) - OpenAI Codex CLI (
codex) - CodeRabbit CLI (
coderabbit) - AgentMemory CLI and a running AgentMemory server
- Enabled Claude Code plugins
mattpocock-skills@mattpocockandagentmemory@agentmemory - Enabled Codex plugin
agentmemory@agentmemory - The installed plan-build skills described below
Claude Code safe mode must be disabled because it disables both required plugins. All modes require an interactive terminal. --prompt additionally requires Auggie (auggie), an authenticated ~/.augment/session.json, Perl, and the platform script utility.
Agent Setup
Start and connect AgentMemory according to its current installation guide. The core wiring is:
agentmemory
agentmemory connect claude-code
codex plugin marketplace add rohitg00/agentmemory
codex plugin add agentmemory@agentmemory
Install and enable the AgentMemory and Matt Pocock plugins in Claude Code. Verify the shared server before using plan-build:
agentmemory status
claude plugin list
codex plugin list
No LLM provider is required for continuity. AgentMemory's local embeddings, keyword retrieval, automatic hooks, explicit recall gate, and project-scoped status slot work without LLM compression.
Plan-Build Installation
Install the executable somewhere on PATH:
mkdir -p "$HOME/.local/bin"
curl -fsSL \
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/plan_build.zsh \
-o "$HOME/.local/bin/plan_build"
chmod +x "$HOME/.local/bin/plan_build"
Install both plan-build skills:
mkdir -p \
"$HOME/.claude/skills/plan-build" \
"$HOME/.claude/skills/plan-build-architect"
curl -fsSL \
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/SKILL.md \
-o "$HOME/.claude/skills/plan-build/SKILL.md"
curl -fsSL \
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/ARCHITECT.md \
-o "$HOME/.claude/skills/plan-build-architect/SKILL.md"
For production automation, download to a temporary file in the destination directory and rename it atomically after successful validation.
Project Identity
Every target repository must commit a .agentmemory-project file containing one stable identifier. The exact grammar is [A-Za-z0-9][A-Za-z0-9._:/-]{1,127}: 2-128 characters with no whitespace. Use the normalized remote repository identity when possible:
github.com/owner/repository
For a repository without a durable remote, use a stable UUID-based value such as local/550e8400-e29b-41d4-a716-446655440000.
On the first interactive run, plan-build proposes the normalized origin URL and creates .agentmemory-project after approval. That setup run then stops: commit the file and rerun plan-build. Directory names are deliberately not used because unrelated repositories can share the same basename. A working-tree identity that differs from HEAD is rejected.
The launcher exports the ID as AGENTMEMORY_PROJECT_NAME and enables context injection for Claude except in explicitly degraded mode. Codex inherits the same environment, so both agents use one memory scope across clones and worktrees.
Usage
Run the command in the project to change, enter the payload, then put EOF alone on a line:
plan_build
Implement pagination for the audit log.
Preserve existing API compatibility.
EOF
Available modes:
plan_build Memory-aware Matt workflow
plan_build --prompt Auggie enhancement, approval, then Matt workflow
plan_build --yolo Permissive Claude process mode; gates remain active
plan_build --architect Memory-aware architect safe resume
plan_build --architect --new Archive active documents and start new state
plan_build --architect --yolo Architect with permissive Claude process mode
--architect may combine only with --new and --yolo; --new is invalid without --architect. Duplicate and unknown flags fail. Removed --brainstorm, --writing-plan, and --v2 options are intentionally unknown.
The user-facing --yolo option translates to Claude Code's --dangerously-skip-permissions. It never bypasses memory, planning, review, or commit approval gates.
Workflow
Except in explicitly degraded mode, every session starts by loading the project-scoped workflow_status slot and retrieving related decisions, bugs, lessons, and file history. Claude reconciles this memory with Git, the current issue or specification, CONTEXT.md, and ADRs before acting.
The default Matt route is:
- Ordinary ideas enter
/mattpocock-skills:grill-with-docs. - Small approved work continues through
/mattpocock-skills:implementand TDD in the same context. - Multi-session work uses
/mattpocock-skills:to-spec, then/mattpocock-skills:to-tickets. - Each unblocked ticket starts in a fresh
plan_buildsession and recovers its case through AgentMemory. - Hard bugs use
/mattpocock-skills:diagnosing-bugs; huge foggy efforts use/mattpocock-skills:wayfinder. - Matt two-axis review, Codex review, CodeRabbit, and complete validation run before an approval-gated commit.
Matt's workflow entry skills require explicit invocation. Claude tells the user the exact namespaced command and waits rather than silently approximating it. The standard workflow overrides Matt /implement's automatic commit instruction: plan-build commits only after explicit approval and never pushes automatically.
Memory Availability
AgentMemory captures prompts, tool activity, session boundaries, subagents, compaction, and commits automatically. Plan-build adds an explicit recall and checkpoint protocol because hooks alone fail silently when the server is unavailable.
If AgentMemory, its Claude plugin, or its Codex plugin fails preflight, plan-build asks whether to retry, continue in explicitly degraded memoryless mode, or stop. A non-interactive failure stops. Degraded mode is always reported and must never claim previous context was restored.
Memory supplements the repository; it does not replace specs, tickets, CONTEXT.md, ADRs, tests, or Git. Current approved artifacts win conflicts with old memory. Secrets, personal data, production data, and unverified hypotheses must not be explicitly saved.
Architect Mode
Architect mode recalls the previous case before detecting SPEC.md, TASKS.md, ADRs, or changelog state. Claude remains documentation-only and passes the same AgentMemory project ID and checkpoint summary to every Codex task.
--architect --new archives the active workflow documents and replaces the active status slot only after successful archival. Historical sessions and durable memories remain available but do not count as approval for the new requirement.
Zsh Setup Cache Launcher
The Zsh Setup integration downloads this complete release bundle:
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/plan_build.zsh
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/SKILL.md
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/ARCHITECT.md
It stages all three non-empty files, requires plan_build.zsh to pass zsh -n, moves them into one immutable release directory, and atomically switches a serialized current symlink. Failed refreshes leave the previous validated release active. Both internal skill paths are bound to the selected release, so concurrent refreshes cannot mix generations.
The mutable HTTPS HEAD URL is the explicit update trust boundary. HTTPS protects transport but does not pin content, establish provenance, or guarantee that separate requests observed one remote revision.
Testing
The suite is self-contained and never accesses the network or launches real agent CLIs:
zsh -n plan_build.zsh test_plan_build.zsh
zsh test_plan_build.zsh
git diff --check
Troubleshooting
- AgentMemory unavailable: run
agentmemory status, start the server, and retry. - AgentMemory tools missing: confirm the Claude and Codex plugins are enabled and connected to the same server.
- Matt skills missing: install or enable
mattpocock-skills@mattpocockin Claude Code. - Safe mode blocks plugins: unset
CLAUDE_CODE_SAFE_MODE. - Project ID rejected: keep
.agentmemory-projectto one valid 2-128 character identifier with no whitespace. - Auggie cannot authenticate: run
auggie loginand confirm~/.augment/session.jsonis non-empty. - Prompt enhancement does not continue:
--promptrequires approval for optional indexing and the enhanced prompt. - Git preflight fails: run from a checked-out worktree, not a bare repository or
.gitdirectory. - Workflow skill missing: install
SKILL.mdandARCHITECT.mdat the exact paths above.
Plan-Build Memory-Aware Matt Workflow
Use this workflow when plan_build hands Claude Code a project request. Matt Pocock's skills provide discovery, specification, ticketing, TDD, and review. AgentMemory restores prior project context across Claude and Codex sessions. Codex and CodeRabbit remain independent reviewers.
Non-Negotiable Rules
- Run from the project root and preserve all pre-existing work.
- Treat Git, the approved issue or specification,
CONTEXT.md, and ADRs as authoritative. Memory supplements them and never overrides contradictory current evidence. - Use the
AGENTMEMORY_PROJECT_NAMEsupplied by the launcher for every memory operation and child Codex process. - Do not expose or save credentials, tokens, personal data, or production secrets.
- Matt entry skills marked
disable-model-invocationrequire explicit user invocation. Tell the user the exact namespaced slash command and wait for it instead of simulating the skill. - Override
/implement's automatic commit instruction. Keep changes uncommitted until review and validation pass and the user explicitly approves the commit. Never push automatically.
Memory Precedence
Resolve conflicts in this order:
- Current Git state and the approved issue or specification.
- Current repository documentation,
CONTEXT.md, and ADRs. - The project-scoped
workflow_statusslot. - Verified durable memories and lessons.
- Raw historical observations.
Report conflicts and correct stale memory. Never bend current implementation or requirements to match an old observation.
Mandatory Recall Gate
Run this gate before routing the request, asking discovery questions, or modifying files. Initialize a session-local memory mode from PLAN_BUILD_MEMORY_MODE, accepting only required or degraded. Treat an unset or invalid value as required and fail closed if mandatory recall cannot run. Only a launcher-supplied degraded value or an explicit user approval after a later memory failure may set the local mode to degraded and permit skipping memory calls.
- Confirm the current project matches
AGENTMEMORY_PROJECT_NAMEand read.agentmemory-project. - Read the project-scoped
workflow_statusslot withmemory_slot_get. If it does not exist, create it with project scope, a 4,000-character limit, and the template below. - Redact the request before search. Query only sanitized issue or ticket identifiers and non-sensitive domain terms; remove or reject credentials, tokens, personal data, production data, and other sensitive payload values. Search for related prior bugs, decisions, and lessons, and reject results belonging to another project.
- After likely files are known, use file history to recover prior changes and gotchas for those files.
- Verify high-impact memories before relying on them. Never invent context when retrieval is empty.
- Reconcile recalled state with Git, the tracker,
CONTEXT.md, ADRs, and current documentation. - Tell the user what previous case was loaded: active work, last completed milestone, unresolved decision or blocker, and recorded next step.
Use this slot shape and replace it at milestones rather than appending an unlimited log:
Phase: <discovery|specification|ticketing|implementation|review|blocked|complete>
Active work: <title and stable issue/spec reference>
Completed: <latest completed milestone>
In flight: <current operation>
Blocked: <blocker or None>
Pending decisions: <decisions or None>
Relevant files: <paths or Unknown>
Last verified: <commands and result or Not run>
Next step: <one concrete action>
Updated: <ISO-8601 timestamp>
When AgentMemory is healthy but no prior state exists, say so and initialize the slot. If any required memory call fails after launcher preflight, ask the user whether to retry, continue this session in explicitly degraded mode, or stop. On approval, record the session-local mode as degraded, skip remaining memory calls, and report the loss of continuity. Do not continue memoryless without that approval and never claim previous context was loaded.
Route Through Matt
After recall, route the request using Matt's /ask-matt model:
| Request | Entry skill |
|---|---|
| Ordinary feature or idea | /mattpocock-skills:grill-with-docs |
| Approved specification or ready ticket | /mattpocock-skills:implement |
| Difficult, intermittent, or unclear bug | /mattpocock-skills:diagnosing-bugs |
| Huge and foggy multi-session effort | /mattpocock-skills:wayfinder |
| Unrefined incoming external issue | /mattpocock-skills:triage |
| Codebase-health exploration | /mattpocock-skills:improve-codebase-architecture |
Do not triage tickets produced by /mattpocock-skills:to-tickets; they are already agent-ready.
Feature Flow
For an ordinary idea:
- Ask the user to invoke
/mattpocock-skills:grill-with-docswith the payload. - Resolve repository facts locally and ask one decision at a time with a recommended answer.
- Use
/mattpocock-skills:researchfor external facts. - For a runnable design question, use
/mattpocock-skills:handoff, continue in a fresh prototype session, invoke/mattpocock-skills:prototype, then hand the learned decision back. Do not confuse Matt's file handoff with/agentmemory:handoff, which resumes recorded sessions. - Do not implement until the user confirms shared understanding.
- Update
workflow_statusafter shared understanding and after every later approval gate.
If the work fits one context window, agree on public testing seams, obtain a read-only Codex review of the requirements and seams, then ask the user to invoke /mattpocock-skills:implement in the same session.
If the work needs multiple sessions:
- Ask the user to invoke
/mattpocock-skills:to-spec. - Confirm the proposed public testing seams before publishing.
- Ask the user to invoke
/mattpocock-skills:to-tickets. - Obtain approval for vertical tracer-bullet tickets and their blocking edges.
- Run a read-only Codex review of the approved specification and tickets. Resolve valid findings and reapprove material scope changes.
- Record the specification, ticket frontier, and first unblocked ticket in
workflow_status, then stop. - Start each unblocked ticket in a fresh
plan_buildinvocation so it gets a clean context plus the mandatory recall gate.
Implementation Flow
For a ready ticket or approved small task:
- Record the baseline SHA,
git status --short, and pre-existing diff. - Load the full ticket or specification and verify dependency completion.
- Recall blocker outcomes, relevant file history, durable decisions, and lessons.
- Confirm public testing seams with the user before writing tests.
- Follow
/mattpocock-skills:implementand/mattpocock-skills:tddone red-green vertical slice at a time. - Run focused tests and type checking regularly; run the full project validation suite at the end.
- Update
workflow_statuswhen a red test is established, implementation turns green, focused validation passes, full validation passes, review begins, or work becomes blocked. - Do not commit when the Matt implementation skill requests it. Continue through plan-build review and explicit approval instead.
Every Codex prompt must include the project ID, active ticket or specification, and checkpoint summary. Require Codex to recall the same project independently and to treat current repository evidence as authoritative. Read-only review prompts must prohibit edits and durable saves of speculative findings.
Review Stack
Review only the intended change against its captured baseline. Capture the startup patch, then use a three-way, patch-aware comparison between HEAD, that baseline, and the current staged, unstaged, and intended untracked files. Preserve and exclude unrelated baseline changes throughout review, approval, and staging. If intended and pre-existing edits overlap in a file or hunk, stop and ask the user instead of subtracting or guessing.
- Run Matt's two axes in parallel against that filtered intended change: repository Standards and originating Spec. The stock
/mattpocock-skills:code-reviewonly compares committedHEADhistory, so apply its standards and spec briefs directly to the filtered working tree before the approval commit. - Ask Codex for an independent review focused on bugs, regressions, unsafe assumptions, missing tests, and repository fit.
- Run CodeRabbit on the local change. Investigate every concrete finding.
- Fix valid findings and repeat affected reviews after substantive changes.
- Rerun focused validation and the complete suite.
- Reconstruct the filtered change and confirm final staging contains only approved work, preserves every baseline change, and has no secret exposure.
- Present the diff summary, validation evidence, known limitations, and proposed commit message.
- Wait for explicit approval, stage only intended files, create one commit, and do not push.
Durable Memory Writes
Search before saving and store one durable idea at a time with the project ID, rationale, real file paths where relevant, and specific concept tags.
Save durable memory for:
- Approved architecture decisions and rejected alternatives.
- Non-obvious constraints and important module relationships.
- Repeated bugs with verified root causes and fixes.
- Deployment, migration, integration, and external-system gotchas.
- Durable user or team preferences.
Save reusable lessons separately. Do not save routine output, temporary progress outside workflow_status, unverified hypotheses, generated content, or secrets.
Before ending any session, update workflow_status with what is done, in flight, blocked or unverified, and exactly one next step. Automatic hooks capture raw activity; this explicit checkpoint is what makes the next case resumable.
Plan-Build Specification
Purpose
Plan-build is a self-contained Zsh launcher for memory-aware Claude Code engineering workflows. Matt Pocock's skills define discovery through delivery, AgentMemory provides project continuity across Claude and Codex sessions, Codex performs independent review or architect-dispatched implementation, and CodeRabbit reviews local changes. This repository is canonical for the executable, both plan-build skills, command tests, and documentation.
Public Interface
plan_build [--yolo] [--prompt]
plan_build --architect [--new] [--yolo]
The executable reads standard input until a line exactly equal to EOF. Empty payloads, duplicate flags, and unknown flags fail. --brainstorm, --writing-plan, and --v2 are intentionally unknown.
- Default mode uses the memory-aware Matt workflow.
--promptenhances the payload through Auggie and requires interactive approval before Claude launches.--yolotranslates to--dangerously-skip-permissionswithout bypassing workflow gates.--architectkeeps Claude documentation-only and makes Codex the implementation executor.--architect --newarchives active workflow documents before starting new state.
--architect may combine only with --new and --yolo.
Common Preflight
All modes require an interactive terminal, a normal Git worktree, Claude, Codex, CodeRabbit, Git, AgentMemory, and a readable non-empty selected workflow skill. Claude safe mode is rejected.
Default mode additionally requires the enabled Claude plugin mattpocock-skills@mattpocock. Every mode checks the AgentMemory server and enabled agentmemory@agentmemory plugins for Claude and Codex.
When memory preflight fails, an interactive user may retry, explicitly approve degraded memoryless mode, or stop. Non-interactive memory failure stops. Other preflight failures are not degradable.
Stable Memory Identity
Every target worktree uses a committed .agentmemory-project containing one stable 2-128 character identifier. Its exact grammar is [A-Za-z0-9][A-Za-z0-9._:/-]{1,127}; whitespace is forbidden. On first interactive use, the launcher proposes a normalized origin identity or asks for an explicit ID, writes the file after approval, and stops. A later invocation proceeds only when the file exists in HEAD and its working-tree value matches the committed value.
The launcher exports:
AGENTMEMORY_PROJECT_NAME=<committed-id>
AGENTMEMORY_INJECT_CONTEXT=<true unless degraded>
PLAN_BUILD_MEMORY_MODE=<required|degraded>
Claude and inherited Codex processes therefore share one scope across worktrees, clones, and machines.
Mandatory Recall And Checkpoint
When memory is available, before routing, discovery, workflow detection, or modification, each skill reads or creates one project-scoped workflow_status slot, retrieves related decisions, bugs, lessons, and file history, and reconciles them with current Git and approved artifacts.
In explicitly approved degraded mode, the skill skips memory calls, reports that recall and checkpoint persistence are unavailable, proceeds only from current repository evidence, and never claims previous context was restored. A later memory failure requires the same retry, explicitly degrade, or stop choice.
The slot records phase, active work and source, completed milestone, in-flight work, blockers, pending decisions, relevant files, last verification, one next step, and update time. It is replaced at meaningful milestones and before session end. Durable decisions and verified fixes are saved separately; routine output, secrets, personal data, generated content, and unverified hypotheses are not.
Authority order is current Git and approved issue/spec, repository documentation and ADRs, active status slot, verified durable memory, then raw observations.
Matt Workflow
The standard skill routes ordinary ideas to grilling, approved tickets to implementation, hard bugs to diagnosis, huge foggy efforts to wayfinding, incoming external issues to triage, and codebase health requests to architecture improvement.
Matt entry skills requiring explicit user invocation are never silently simulated. Small approved work remains in the discovery context. Multi-session work creates an approved spec and tracer-bullet tickets, then stops; every unblocked ticket starts in a fresh plan-build invocation.
Implementation uses pre-agreed public test seams and red-green vertical slices. Matt's automatic commit instruction is overridden. The uncommitted working tree receives Matt-equivalent Standards and Spec review, Codex review, CodeRabbit review, and complete validation before the user approves one commit. Plan-build never pushes automatically.
Architect Mode
Architect mode runs memory recall before existing-state detection. Claude may modify only its documented Markdown scope. Codex receives the project ID, task/spec references, and compact checkpoint, recalls relevant history independently, and remains prohibited from commits or out-of-scope edits.
Archive-and-start-new preserves historical memories but replaces the active slot after successful document archival. Historical memory is context, not approval for the new requirement.
Installed Skills
~/.claude/skills/plan-build/SKILL.md
~/.claude/skills/plan-build-architect/SKILL.md
Canonical sources are SKILL.md and ARCHITECT.md.
Standalone Constraints
- Support Zsh on macOS, Ubuntu, and WSL.
- Do not source user shell configuration.
- Keep helpers in the
_plan_build_namespace. - Keep external command and interaction boundaries replaceable.
- Keep tests network-free and prevent real agent launches.
- Remain safely sourceable and run main only when executed directly.
- Preserve the three-file immutable cache release contract.
Acceptance Criteria
- Default, prompt-enhanced, permissive, architect resume, and architect-new modes have command coverage.
- Removed options, invalid combinations, duplicates, and empty payloads are covered.
- Stable project IDs are validated and reach Claude's environment.
- AgentMemory success, degraded approval, and rejection paths are covered without network access.
- Recall requirements appear in standard and architect launch prompts.
- Common preflight happens before payload input.
- Prompt enhancement cannot launch Claude without approval.
--yoloreaches Claude only as--dangerously-skip-permissions.- Syntax checks, command tests, and
git diff --checkpass.
Plan-Build Tasks
Completed
PB-001: Establish the dedicated project boundary
- Extract the executable from Zsh Setup into
plan_build.zsh. - Remove dependencies on
~/.funcand unrelated shell helpers. - Make the executable directly runnable and safely sourceable.
PB-002: Preserve supported workflows
- Preserve standard and prompt-enhancement behavior.
- Preserve architect safe-resume and archive-and-start-new modes.
- Preserve EOF-terminated payload input and interactive enhanced-prompt approval.
- Translate
--yoloto Claude Code's real--dangerously-skip-permissionsoption. - Keep
--v2rejected through the unknown-option path.
PB-003: Canonicalize skills and documentation
- Publish the standard workflow as
SKILL.md. - Publish the architect workflow as
ARCHITECT.md. - Remove obsolete v2-only and distribution workflow claims from the active standard skill.
- Document installation, prerequisites, cache integration, compatibility, testing, and troubleshooting.
PB-004: Add standalone regression coverage
- Stub external CLIs, Claude launch, Auggie enhancement, and interactive approval.
- Cover all modes, invalid combinations, preflight ordering, safe-resume/new architect prompts, and normal versus bare Git repositories.
- Keep the suite network-free.
PB-005: Replace Superpowers planning with Matt Pocock's workflow
- Make Matt routing the default standard workflow.
- Remove
--brainstorm,--writing-plan, and the Superpowers dependency. - Preserve Auggie prompt enhancement and architect modes.
- Route discovery, specifications, tracer-bullet tickets, TDD, diagnosis, and wayfinding through explicit namespaced Matt skills.
- Override automatic commits with review, validation, and explicit approval.
PB-006: Add AgentMemory continuity
- Require a committed stable
.agentmemory-projectidentity. - Verify the shared AgentMemory server and Claude/Codex plugins before payload input.
- Allow only an explicitly approved interactive degraded mode when memory is unavailable.
- Pass one memory scope through Claude and inherited Codex processes.
- Require project-scoped recall and one canonical
workflow_statuscheckpoint in both standard and architect skills. - Add network-free tests for project identity, memory preflight outcomes, recall prompts, and child environment propagation.
Completed outside this repository
ZS-001: Migrate the Zsh Setup launcher
Replace the old in-repository implementation with a thin cached launcher that downloads the canonical executable and skills from the plan-build gist. The Zsh Setup migration now uses immutable complete release directories, a serialized atomic current symlink switch, and skill links through that same release.
Required launcher contract:
zsh <selected-release>/plan_build.zsh "$@"
Required remote files:
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/plan_build.zsh
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/SKILL.md
https://opengist.resetrix.work/weehong/plan-build/raw/HEAD/ARCHITECT.md
| 1 | #!/usr/bin/env zsh |
| 2 | |
| 3 | # Standalone plan-build launcher. This file is intentionally sourceable so its |
| 4 | # command seams can be replaced by the test suite. |
| 5 | |
| 6 | _plan_build_usage() { |
| 7 | print -r -- "Usage: plan_build [--yolo] [--prompt] |
| 8 | plan_build --architect [--new] [--yolo]" |
| 9 | } |
| 10 | |
| 11 | _plan_build_require_cli() { |
| 12 | local binary="$1" |
| 13 | local label="$2" |
| 14 | local resolved |
| 15 | |
| 16 | resolved="$(command -v "$binary" 2>/dev/null)" || resolved="" |
| 17 | if [[ -n "$resolved" && -x "$resolved" ]]; then |
| 18 | return 0 |
| 19 | fi |
| 20 | |
| 21 | print -u2 -r -- "Error: ${label} ('${binary}') is not installed or not in your PATH." |
| 22 | return 1 |
| 23 | } |
| 24 | |
| 25 | _plan_build_confirm_indexing() { |
| 26 | local project_root="$1" |
| 27 | local reply |
| 28 | |
| 29 | if ! (: </dev/tty) 2>/dev/null; then |
| 30 | print -u2 -r -- "Notice: No interactive terminal available; enhancing without project indexing." |
| 31 | return 1 |
| 32 | fi |
| 33 | |
| 34 | printf "Allow Auggie to index and use project context from '%s'? (y/N) " "$project_root" >/dev/tty |
| 35 | if ! IFS= read -r reply </dev/tty; then |
| 36 | print -u2 -r -- "\nNotice: Unable to read confirmation; enhancing without project indexing." |
| 37 | return 1 |
| 38 | fi |
| 39 | |
| 40 | [[ "$reply" == (y|Y|yes|YES|Yes) ]] |
| 41 | } |
| 42 | |
| 43 | _plan_build_parse_auggie_output() { |
| 44 | local log_file="$1" |
| 45 | local output_file="$2" |
| 46 | |
| 47 | perl -ne ' |
| 48 | s/\r$//; |
| 49 | s/.*\r//; |
| 50 | 1 while s/[^\x08]\x08//g; |
| 51 | s/\x08//g; |
| 52 | s/\e\][^\a]*(?:\a|\e\\)//g; |
| 53 | s/\e\[[0-?]*[ -\/]*[@-~]//g; |
| 54 | next if /Script started on/ || /Script done on/; |
| 55 | if (/^(?:✨\s*)?Enhanced prompt:\s*(.*)$/) { |
| 56 | $capturing = 1; |
| 57 | $output .= "$1\n" if length $1; |
| 58 | next; |
| 59 | } |
| 60 | next unless $capturing; |
| 61 | exit if /^🤖/ || /Tool call:/ || /Session terminated/; |
| 62 | $output .= $_; |
| 63 | END { |
| 64 | $output =~ s/^\s*\n//; |
| 65 | $output =~ s/\s+\z//; |
| 66 | print "$output\n" if length $output; |
| 67 | } |
| 68 | ' "$log_file" >| "$output_file" |
| 69 | } |
| 70 | |
| 71 | _plan_build_platform() { |
| 72 | command uname -s |
| 73 | } |
| 74 | |
| 75 | _plan_build_start_auggie_script() { |
| 76 | local platform="$1" log_file="$2" workspace="$3" cache_dir="$4" |
| 77 | local auth_file="$5" prompt_file="$6" use_project_context="$7" |
| 78 | shift 7 |
| 79 | |
| 80 | if [[ "$platform" == Darwin ]]; then |
| 81 | command script -q -t 0 "$log_file" auggie "$@" </dev/null >/dev/null 2>&1 & |
| 82 | else |
| 83 | AUGGIE_WORKSPACE="$workspace" AUGGIE_CACHE_DIR="$cache_dir" \ |
| 84 | AUGGIE_AUTH_FILE="$auth_file" AUGGIE_PROMPT_FILE="$prompt_file" \ |
| 85 | AUGGIE_INDEXING="$use_project_context" \ |
| 86 | command script -q -f -e -O "$log_file" -c ' |
| 87 | if [ "$AUGGIE_INDEXING" = 1 ]; then |
| 88 | exec auggie --print --enhance-prompt --workspace-root "$AUGGIE_WORKSPACE" --augment-cache-dir "$AUGGIE_CACHE_DIR" --augment-session-json "$AUGGIE_AUTH_FILE" --allow-indexing --wait-for-indexing --dont-save-session --instruction-file "$AUGGIE_PROMPT_FILE" |
| 89 | else |
| 90 | exec auggie --print --enhance-prompt --no-discover-workspaces --workspace-root "$AUGGIE_WORKSPACE" --augment-cache-dir "$AUGGIE_CACHE_DIR" --augment-session-json "$AUGGIE_AUTH_FILE" --dont-save-session --instruction-file "$AUGGIE_PROMPT_FILE" |
| 91 | fi |
| 92 | ' </dev/null >/dev/null 2>&1 & |
| 93 | fi |
| 94 | REPLY=$! |
| 95 | } |
| 96 | |
| 97 | _plan_build_enhance_prompt() { |
| 98 | emulate -L zsh |
| 99 | setopt localtraps |
| 100 | local prompt="$1" |
| 101 | local output_file="$2" |
| 102 | local run_dir prompt_file workspace cache_dir auth_file log_file parsed_file |
| 103 | local project_root use_project_context timeout_seconds script_pid= waited child_status=0 |
| 104 | local -a auggie_args |
| 105 | |
| 106 | trap 'return 130' INT |
| 107 | trap 'return 143' TERM |
| 108 | trap 'return 129' HUP |
| 109 | |
| 110 | if [[ -z "$prompt" ]]; then |
| 111 | print -u2 -r -- "Error: Prompt was empty." |
| 112 | return 1 |
| 113 | fi |
| 114 | if [[ ! -s "$HOME/.augment/session.json" ]]; then |
| 115 | print -u2 -r -- "Error: Auggie session file not found. Run 'auggie login' first." |
| 116 | return 1 |
| 117 | fi |
| 118 | |
| 119 | run_dir="$(mktemp -d "${TMPDIR:-/tmp}/plan-build-auggie.XXXXXX")" || return 1 |
| 120 | trap "rm -rf -- ${(q)run_dir}" EXIT |
| 121 | prompt_file="$run_dir/prompt.txt" |
| 122 | workspace="$run_dir/workspace" |
| 123 | cache_dir="$run_dir/cache" |
| 124 | auth_file="$HOME/.augment/session.json" |
| 125 | log_file="$run_dir/auggie.log" |
| 126 | parsed_file="$run_dir/enhanced.txt" |
| 127 | mkdir -p "$workspace" "$cache_dir" || { |
| 128 | return 1 |
| 129 | } |
| 130 | print -r -- "$prompt" >| "$prompt_file" || return 1 |
| 131 | |
| 132 | project_root="$(command git rev-parse --show-toplevel 2>/dev/null)" || project_root="$PWD" |
| 133 | use_project_context=0 |
| 134 | timeout_seconds=90 |
| 135 | if _plan_build_confirm_indexing "$project_root"; then |
| 136 | use_project_context=1 |
| 137 | timeout_seconds=300 |
| 138 | workspace="$project_root" |
| 139 | cache_dir="$HOME/.augment" |
| 140 | print -u2 -r -- "Indexing approved; enhancing with project context from '${project_root}'." |
| 141 | else |
| 142 | print -u2 -r -- "Enhancing without project indexing." |
| 143 | fi |
| 144 | |
| 145 | auggie_args=(--print --enhance-prompt --workspace-root "$workspace" |
| 146 | --augment-cache-dir "$cache_dir" --augment-session-json "$auth_file" |
| 147 | --dont-save-session --instruction-file "$prompt_file") |
| 148 | if (( use_project_context )); then |
| 149 | auggie_args+=(--allow-indexing --wait-for-indexing) |
| 150 | else |
| 151 | auggie_args+=(--no-discover-workspaces) |
| 152 | fi |
| 153 | |
| 154 | _plan_build_start_auggie_script "$(_plan_build_platform)" "$log_file" \ |
| 155 | "$workspace" "$cache_dir" "$auth_file" "$prompt_file" \ |
| 156 | "$use_project_context" "${auggie_args[@]}" || return 1 |
| 157 | script_pid="$REPLY" |
| 158 | trap "kill ${(q)script_pid} >/dev/null 2>&1 |
| 159 | wait ${(q)script_pid} >/dev/null 2>&1 |
| 160 | rm -rf -- ${(q)run_dir}" EXIT |
| 161 | waited=0 |
| 162 | while kill -0 "$script_pid" >/dev/null 2>&1; do |
| 163 | if command grep -aq "🤖" "$log_file" 2>/dev/null || |
| 164 | command grep -aq "Tool call:" "$log_file" 2>/dev/null; then |
| 165 | kill "$script_pid" >/dev/null 2>&1 || true |
| 166 | wait "$script_pid" >/dev/null 2>&1 || true |
| 167 | script_pid= |
| 168 | trap "rm -rf -- ${(q)run_dir}" EXIT |
| 169 | child_status=0 |
| 170 | break |
| 171 | fi |
| 172 | if (( waited >= timeout_seconds )); then |
| 173 | kill "$script_pid" >/dev/null 2>&1 || true |
| 174 | wait "$script_pid" >/dev/null 2>&1 || true |
| 175 | script_pid= |
| 176 | trap "rm -rf -- ${(q)run_dir}" EXIT |
| 177 | print -u2 -r -- "Error: Timed out waiting for Auggie to enhance the prompt." |
| 178 | return 124 |
| 179 | fi |
| 180 | sleep 1 |
| 181 | waited=$((waited + 1)) |
| 182 | done |
| 183 | if [[ -n "$script_pid" ]]; then |
| 184 | wait "$script_pid" |
| 185 | child_status=$? |
| 186 | script_pid= |
| 187 | trap "rm -rf -- ${(q)run_dir}" EXIT |
| 188 | fi |
| 189 | if (( child_status != 0 )); then |
| 190 | print -u2 -r -- "Error: Auggie process failed with status ${child_status}." |
| 191 | return "$child_status" |
| 192 | fi |
| 193 | |
| 194 | _plan_build_parse_auggie_output "$log_file" "$parsed_file" |
| 195 | if [[ ! -s "$parsed_file" ]]; then |
| 196 | print -u2 -r -- "Error: Auggie did not return an enhanced prompt." |
| 197 | return 1 |
| 198 | fi |
| 199 | command cp "$parsed_file" "$output_file" || { |
| 200 | print -u2 -r -- "Error: Unable to save the enhanced prompt." |
| 201 | return 1 |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | _plan_build_confirm_enhanced_prompt() { |
| 206 | local reply |
| 207 | |
| 208 | if ! (: </dev/tty) 2>/dev/null; then |
| 209 | print -r -- "❌ Error: Cannot review the enhanced prompt without an interactive terminal; Claude was not launched." |
| 210 | return 2 |
| 211 | fi |
| 212 | printf "Proceed with this enhanced prompt? (y/N) " >/dev/tty |
| 213 | if ! IFS= read -r reply </dev/tty; then |
| 214 | printf '\n' >/dev/tty |
| 215 | print -r -- "🛑 Review cancelled; Claude was not launched." |
| 216 | return 2 |
| 217 | fi |
| 218 | [[ "$reply" == (y|Y|yes|YES|Yes) ]] |
| 219 | } |
| 220 | |
| 221 | _plan_build_claude_plugin_state() { |
| 222 | local plugin_id="$1" |
| 223 | awk -v plugin_id="$plugin_id" ' |
| 224 | $0 ~ plugin_id { |
| 225 | found = 1 |
| 226 | next |
| 227 | } |
| 228 | found && /Status:/ { |
| 229 | if ($0 ~ /enabled/) print "enabled" |
| 230 | else print "disabled" |
| 231 | printed = 1 |
| 232 | exit |
| 233 | } |
| 234 | found && /❯/ { |
| 235 | print "installed" |
| 236 | printed = 1 |
| 237 | exit |
| 238 | } |
| 239 | END { if (!printed) print found ? "installed" : "missing" } |
| 240 | ' |
| 241 | } |
| 242 | |
| 243 | _plan_build_safe_mode_preflight() { |
| 244 | case "${CLAUDE_CODE_SAFE_MODE:-}" in |
| 245 | 1|true|TRUE|yes|YES|on|ON) |
| 246 | print -r -- "Error: Claude Code safe mode disables the Matt Pocock and AgentMemory plugins." |
| 247 | print -r -- "Unset CLAUDE_CODE_SAFE_MODE before using plan_build." |
| 248 | return 1 |
| 249 | ;; |
| 250 | esac |
| 251 | } |
| 252 | |
| 253 | _plan_build_matt_preflight() { |
| 254 | local plugin_json plugin_state |
| 255 | |
| 256 | if ! plugin_json="$(command claude plugin list 2>/dev/null)"; then |
| 257 | print -r -- "Error: Unable to inspect Claude Code plugins." |
| 258 | print -r -- "Run 'claude plugin list' to diagnose the problem." |
| 259 | return 1 |
| 260 | fi |
| 261 | plugin_state="$(print -r -- "$plugin_json" | _plan_build_claude_plugin_state \ |
| 262 | "mattpocock-skills@mattpocock")" |
| 263 | case "$plugin_state" in |
| 264 | enabled) return 0 ;; |
| 265 | disabled) |
| 266 | print -r -- "Error: Matt Pocock skills are installed in Claude Code but disabled." |
| 267 | print -r -- "Enable the mattpocock-skills@mattpocock plugin, then retry." |
| 268 | ;; |
| 269 | missing) |
| 270 | print -r -- "Error: Matt Pocock skills are required for the default workflow." |
| 271 | print -r -- "Install the mattpocock-skills@mattpocock Claude Code plugin, then retry." |
| 272 | ;; |
| 273 | *) |
| 274 | print -r -- "Error: Unable to determine Matt Pocock plugin status." |
| 275 | print -r -- "Run 'claude plugin list' to diagnose the problem." |
| 276 | ;; |
| 277 | esac |
| 278 | return 1 |
| 279 | } |
| 280 | |
| 281 | _plan_build_agentmemory_health() { |
| 282 | local pid exit_status waited=0 |
| 283 | command -v agentmemory >/dev/null 2>&1 || return 2 |
| 284 | command agentmemory status >/dev/null 2>&1 & |
| 285 | pid=$! |
| 286 | while kill -0 "$pid" >/dev/null 2>&1; do |
| 287 | if (( waited >= 10 )); then |
| 288 | kill "$pid" >/dev/null 2>&1 || true |
| 289 | wait "$pid" >/dev/null 2>&1 || true |
| 290 | return 124 |
| 291 | fi |
| 292 | sleep 1 |
| 293 | waited=$((waited + 1)) |
| 294 | done |
| 295 | wait "$pid" |
| 296 | exit_status=$? |
| 297 | return "$exit_status" |
| 298 | } |
| 299 | |
| 300 | _plan_build_claude_agentmemory_state() { |
| 301 | local plugin_json |
| 302 | plugin_json="$(command claude plugin list 2>/dev/null)" || return 1 |
| 303 | print -r -- "$plugin_json" | _plan_build_claude_plugin_state \ |
| 304 | "agentmemory@agentmemory" |
| 305 | } |
| 306 | |
| 307 | _plan_build_codex_agentmemory_state() { |
| 308 | local plugin_list |
| 309 | plugin_list="$(command codex plugin list 2>/dev/null)" || return 1 |
| 310 | print -r -- "$plugin_list" | _plan_build_codex_plugin_state |
| 311 | } |
| 312 | |
| 313 | _plan_build_codex_plugin_state() { |
| 314 | awk ' |
| 315 | $1 == "agentmemory@agentmemory" { |
| 316 | if ($0 ~ /installed, enabled/) print "enabled" |
| 317 | else print "disabled" |
| 318 | found = 1 |
| 319 | exit |
| 320 | } |
| 321 | END { if (!found) print "missing" } |
| 322 | ' |
| 323 | } |
| 324 | |
| 325 | _plan_build_agentmemory_check() { |
| 326 | local claude_state codex_state failed=0 health_status |
| 327 | |
| 328 | _plan_build_agentmemory_health |
| 329 | health_status=$? |
| 330 | case "$health_status" in |
| 331 | 0) ;; |
| 332 | 2) |
| 333 | print -r -- "AgentMemory CLI is not installed or not in PATH." |
| 334 | print -r -- "Install @agentmemory/agentmemory, then retry." |
| 335 | failed=1 |
| 336 | ;; |
| 337 | 124) |
| 338 | print -r -- "AgentMemory status check timed out after 10 seconds." |
| 339 | failed=1 |
| 340 | ;; |
| 341 | *) |
| 342 | print -r -- "AgentMemory server is unavailable." |
| 343 | failed=1 |
| 344 | ;; |
| 345 | esac |
| 346 | claude_state="$(_plan_build_claude_agentmemory_state)" || claude_state="unknown" |
| 347 | if [[ "$claude_state" != enabled ]]; then |
| 348 | print -r -- "Claude Code AgentMemory plugin state: $claude_state." |
| 349 | failed=1 |
| 350 | fi |
| 351 | codex_state="$(_plan_build_codex_agentmemory_state)" || codex_state="unknown" |
| 352 | if [[ "$codex_state" != enabled ]]; then |
| 353 | print -r -- "Codex AgentMemory plugin state: $codex_state." |
| 354 | failed=1 |
| 355 | fi |
| 356 | |
| 357 | (( failed == 0 )) |
| 358 | } |
| 359 | |
| 360 | _plan_build_confirm_memory_action() { |
| 361 | local reply |
| 362 | |
| 363 | if ! _plan_build_has_tty; then |
| 364 | print -r -- "Error: AgentMemory preflight failed without an interactive terminal." |
| 365 | return 1 |
| 366 | fi |
| 367 | printf "AgentMemory preflight failed. [r]etry, [c]ontinue without memory, or [s]top? " >/dev/tty |
| 368 | if ! IFS= read -r reply </dev/tty; then |
| 369 | return 1 |
| 370 | fi |
| 371 | _plan_build_memory_action_from_reply "$reply" |
| 372 | } |
| 373 | |
| 374 | _plan_build_memory_action_from_reply() { |
| 375 | local reply="$1" |
| 376 | case "$reply" in |
| 377 | r|R|retry|Retry|RETRY) return 2 ;; |
| 378 | c|C|continue|Continue|CONTINUE) return 0 ;; |
| 379 | *) return 1 ;; |
| 380 | esac |
| 381 | } |
| 382 | |
| 383 | _plan_build_agentmemory_preflight() { |
| 384 | local action_status |
| 385 | |
| 386 | while ! _plan_build_agentmemory_check; do |
| 387 | _plan_build_confirm_memory_action |
| 388 | action_status=$? |
| 389 | if (( action_status == 2 )); then |
| 390 | continue |
| 391 | elif (( action_status == 0 )); then |
| 392 | print -r -- "Warning: Continuing in explicitly approved memoryless mode." |
| 393 | REPLY="degraded" |
| 394 | return 0 |
| 395 | fi |
| 396 | print -r -- "Memory preflight was not approved; Claude was not launched." |
| 397 | return 1 |
| 398 | done |
| 399 | REPLY="required" |
| 400 | } |
| 401 | |
| 402 | _plan_build_project_root() { |
| 403 | command git rev-parse --show-toplevel 2>/dev/null |
| 404 | } |
| 405 | |
| 406 | _plan_build_project_id_is_valid() { |
| 407 | [[ "$1" =~ '^[A-Za-z0-9][A-Za-z0-9._:/-]{1,127}$' ]] |
| 408 | } |
| 409 | |
| 410 | _plan_build_default_project_id() { |
| 411 | local root="$1" remote is_url=0 |
| 412 | remote="$(command git -C "$root" remote get-url origin 2>/dev/null)" || return 1 |
| 413 | [[ "$remote" == *://* ]] && is_url=1 |
| 414 | remote="${remote#*://}" |
| 415 | remote="${remote#*@}" |
| 416 | if (( ! is_url )) && [[ "$remote" == *:* ]]; then |
| 417 | remote="${remote%%:*}/${remote#*:}" |
| 418 | fi |
| 419 | remote="${remote%.git}" |
| 420 | [[ -n "$remote" ]] || return 1 |
| 421 | print -r -- "$remote" |
| 422 | } |
| 423 | |
| 424 | _plan_build_initialize_project_id() { |
| 425 | local root="$1" candidate reply |
| 426 | |
| 427 | if ! _plan_build_has_tty; then |
| 428 | print -r -- "Error: Missing $root/.agentmemory-project and no interactive terminal is available." |
| 429 | return 1 |
| 430 | fi |
| 431 | candidate="$(_plan_build_default_project_id "$root")" || candidate="" |
| 432 | if [[ -n "$candidate" ]] && ! _plan_build_project_id_is_valid "$candidate"; then |
| 433 | candidate="" |
| 434 | fi |
| 435 | if [[ -n "$candidate" ]]; then |
| 436 | printf "Create .agentmemory-project with ID '%s'? (Y/n) " "$candidate" >/dev/tty |
| 437 | if ! IFS= read -r reply </dev/tty; then |
| 438 | return 1 |
| 439 | fi |
| 440 | case "$reply" in |
| 441 | n|N|no|No|NO) candidate="" ;; |
| 442 | esac |
| 443 | fi |
| 444 | if [[ -z "$candidate" ]]; then |
| 445 | printf "Enter a stable AgentMemory project ID: " >/dev/tty |
| 446 | if ! IFS= read -r candidate </dev/tty; then |
| 447 | return 1 |
| 448 | fi |
| 449 | fi |
| 450 | if ! _plan_build_project_id_is_valid "$candidate"; then |
| 451 | print -r -- "Error: Project ID must be 2-128 characters using letters, numbers, '.', '_', ':', '/', or '-'." |
| 452 | return 1 |
| 453 | fi |
| 454 | print -r -- "$candidate" >| "$root/.agentmemory-project" || return 1 |
| 455 | print -r -- "Created $root/.agentmemory-project. Commit it, then rerun plan_build." |
| 456 | return 1 |
| 457 | } |
| 458 | |
| 459 | _plan_build_resolve_project_id() { |
| 460 | local root project_file project_id committed_id |
| 461 | root="$(_plan_build_project_root)" || return 1 |
| 462 | project_file="$root/.agentmemory-project" |
| 463 | if [[ ! -e "$project_file" ]]; then |
| 464 | _plan_build_initialize_project_id "$root" |
| 465 | return $? |
| 466 | fi |
| 467 | if [[ ! -f "$project_file" || ! -r "$project_file" ]]; then |
| 468 | print -r -- "Error: AgentMemory project ID file is not a readable regular file: $project_file" |
| 469 | return 1 |
| 470 | fi |
| 471 | project_id="$(<"$project_file")" |
| 472 | if ! _plan_build_project_id_is_valid "$project_id"; then |
| 473 | print -r -- "Error: Invalid AgentMemory project ID in $project_file" |
| 474 | return 1 |
| 475 | fi |
| 476 | committed_id="$(command git -C "$root" show HEAD:.agentmemory-project 2>/dev/null)" || { |
| 477 | print -r -- "Error: .agentmemory-project must be committed before plan_build can use it." |
| 478 | return 1 |
| 479 | } |
| 480 | if [[ "$project_id" != "$committed_id" ]]; then |
| 481 | print -r -- "Error: Working-tree .agentmemory-project differs from the committed identity." |
| 482 | return 1 |
| 483 | fi |
| 484 | REPLY="$project_id" |
| 485 | } |
| 486 | |
| 487 | _plan_build_is_worktree() { |
| 488 | local inside_work_tree |
| 489 | inside_work_tree="$(command git rev-parse --is-inside-work-tree 2>/dev/null)" || return 1 |
| 490 | [[ "$inside_work_tree" == true ]] |
| 491 | } |
| 492 | |
| 493 | _plan_build_has_tty() { |
| 494 | (: </dev/tty) 2>/dev/null |
| 495 | } |
| 496 | |
| 497 | _plan_build_common_preflight() { |
| 498 | local skill_path="$1" require_matt="$2" |
| 499 | |
| 500 | if ! _plan_build_has_tty; then |
| 501 | print -r -- "Error: plan_build requires an interactive terminal." |
| 502 | return 1 |
| 503 | fi |
| 504 | _plan_build_require_cli claude "Claude Code CLI" || return 1 |
| 505 | _plan_build_require_cli codex "Codex CLI" || return 1 |
| 506 | _plan_build_require_cli coderabbit "CodeRabbit CLI" || return 1 |
| 507 | _plan_build_require_cli git "Git CLI" || return 1 |
| 508 | if ! _plan_build_is_worktree; then |
| 509 | print -r -- "Error: plan_build must run inside a Git worktree." |
| 510 | print -r -- "Change to a checked-out Git worktree, then retry." |
| 511 | return 1 |
| 512 | fi |
| 513 | if [[ ! -r "$skill_path" || ! -s "$skill_path" ]]; then |
| 514 | print -r -- "Error: Workflow skill is missing, unreadable, or empty: $skill_path" |
| 515 | return 1 |
| 516 | fi |
| 517 | _plan_build_safe_mode_preflight || return 1 |
| 518 | if (( require_matt )); then |
| 519 | _plan_build_matt_preflight || return 1 |
| 520 | fi |
| 521 | } |
| 522 | |
| 523 | _plan_build_launch_claude() { |
| 524 | local use_yolo="$1" project_id="$2" memory_mode="$3" |
| 525 | local inject_context="true" |
| 526 | shift 3 |
| 527 | [[ "$memory_mode" == degraded ]] && inject_context="false" |
| 528 | if (( use_yolo )); then |
| 529 | AGENTMEMORY_PROJECT_NAME="$project_id" AGENTMEMORY_INJECT_CONTEXT="$inject_context" \ |
| 530 | PLAN_BUILD_MEMORY_MODE="$memory_mode" \ |
| 531 | command claude --dangerously-skip-permissions "$@" |
| 532 | else |
| 533 | AGENTMEMORY_PROJECT_NAME="$project_id" AGENTMEMORY_INJECT_CONTEXT="$inject_context" \ |
| 534 | PLAN_BUILD_MEMORY_MODE="$memory_mode" command claude "$@" |
| 535 | fi |
| 536 | } |
| 537 | |
| 538 | _plan_build_read_payload() { |
| 539 | local line payload="" |
| 540 | while IFS= read -r line; do |
| 541 | [[ "$line" == EOF ]] && break |
| 542 | if [[ -z "$payload" ]]; then |
| 543 | payload="$line" |
| 544 | else |
| 545 | payload+=$'\n'"$line" |
| 546 | fi |
| 547 | done |
| 548 | print -r -- "$payload" |
| 549 | } |
| 550 | |
| 551 | plan_build() { |
| 552 | emulate -L zsh |
| 553 | setopt localtraps |
| 554 | local use_yolo=0 use_architect=0 use_new=0 enhance_payload=0 |
| 555 | local payload enhanced_file= confirm_status enhance_status architect_start_mode |
| 556 | local project_id memory_mode |
| 557 | local standard_skill="${PLAN_BUILD_SKILL_PATH:-$HOME/.claude/skills/plan-build/SKILL.md}" |
| 558 | local architect_skill="${PLAN_BUILD_ARCHITECT_SKILL_PATH:-$HOME/.claude/skills/plan-build-architect/SKILL.md}" |
| 559 | |
| 560 | trap 'return 130' INT |
| 561 | trap 'return 143' TERM |
| 562 | trap 'return 129' HUP |
| 563 | |
| 564 | while (( $# )); do |
| 565 | case "$1" in |
| 566 | --yolo) |
| 567 | (( use_yolo )) && { |
| 568 | print -r -- "Error: Duplicate argument: --yolo" |
| 569 | _plan_build_usage |
| 570 | return 1 |
| 571 | } |
| 572 | use_yolo=1 |
| 573 | ;; |
| 574 | --architect) |
| 575 | (( use_architect )) && { |
| 576 | print -r -- "Error: Duplicate argument: --architect" |
| 577 | _plan_build_usage |
| 578 | return 1 |
| 579 | } |
| 580 | use_architect=1 |
| 581 | ;; |
| 582 | --new) |
| 583 | (( use_new )) && { |
| 584 | print -r -- "Error: Duplicate argument: --new" |
| 585 | _plan_build_usage |
| 586 | return 1 |
| 587 | } |
| 588 | use_new=1 |
| 589 | ;; |
| 590 | --prompt) |
| 591 | (( enhance_payload )) && { |
| 592 | print -r -- "Error: Duplicate argument: --prompt" |
| 593 | _plan_build_usage |
| 594 | return 1 |
| 595 | } |
| 596 | enhance_payload=1 |
| 597 | ;; |
| 598 | *) |
| 599 | print -r -- "Error: Unknown argument: $1" |
| 600 | _plan_build_usage |
| 601 | return 1 |
| 602 | ;; |
| 603 | esac |
| 604 | shift |
| 605 | done |
| 606 | |
| 607 | if (( use_new && ! use_architect )); then |
| 608 | print -r -- "Error: --new requires --architect." |
| 609 | _plan_build_usage |
| 610 | return 1 |
| 611 | fi |
| 612 | if (( use_architect && enhance_payload )); then |
| 613 | print -r -- "Error: --architect may combine only with --new and --yolo." |
| 614 | _plan_build_usage |
| 615 | return 1 |
| 616 | fi |
| 617 | |
| 618 | if (( use_architect )); then |
| 619 | _plan_build_common_preflight "$architect_skill" 0 || return 1 |
| 620 | else |
| 621 | _plan_build_common_preflight "$standard_skill" 1 || return 1 |
| 622 | if (( enhance_payload )); then |
| 623 | _plan_build_require_cli auggie "Auggie CLI" || return 1 |
| 624 | _plan_build_require_cli script "script utility" || return 1 |
| 625 | _plan_build_require_cli perl "Perl" || return 1 |
| 626 | fi |
| 627 | fi |
| 628 | _plan_build_resolve_project_id || return 1 |
| 629 | project_id="$REPLY" |
| 630 | _plan_build_agentmemory_preflight || return 1 |
| 631 | memory_mode="$REPLY" |
| 632 | |
| 633 | print -r -- "📥 Reading payload... Type 'EOF' on a new line and press Enter when finished." |
| 634 | payload="$(_plan_build_read_payload)" |
| 635 | if [[ -z "$payload" ]]; then |
| 636 | print -r -- "❌ Error: Payload was empty." |
| 637 | return 1 |
| 638 | fi |
| 639 | |
| 640 | if (( enhance_payload )); then |
| 641 | enhanced_file="$(mktemp "${TMPDIR:-/tmp}/plan-build-enhanced.XXXXXX")" || return 1 |
| 642 | trap "rm -f -- ${(q)enhanced_file}" EXIT |
| 643 | print -r -- "✨ Enhancing payload with Auggie..." |
| 644 | _plan_build_enhance_prompt "$payload" "$enhanced_file" |
| 645 | enhance_status=$? |
| 646 | if (( enhance_status != 0 )); then |
| 647 | print -r -- "❌ Error: Prompt enhancement failed; Claude was not launched." |
| 648 | return "$enhance_status" |
| 649 | fi |
| 650 | payload="$(<"$enhanced_file")" |
| 651 | rm -f -- "$enhanced_file" |
| 652 | enhanced_file= |
| 653 | trap - EXIT |
| 654 | if [[ -z "$payload" ]]; then |
| 655 | print -r -- "❌ Error: Enhanced payload was empty; Claude was not launched." |
| 656 | return 1 |
| 657 | fi |
| 658 | printf '\n%s\n%s\n%s\n\n' \ |
| 659 | "━━━━━━━━━━━━━━━━ Auggie enhanced prompt ━━━━━━━━━━━━━━━━" \ |
| 660 | "$payload" \ |
| 661 | "━━━━━━━━━━━━━━━━ End enhanced prompt ━━━━━━━━━━━━━━━━━" |
| 662 | _plan_build_confirm_enhanced_prompt |
| 663 | confirm_status=$? |
| 664 | if (( confirm_status == 2 )); then |
| 665 | return 1 |
| 666 | elif (( confirm_status != 0 )); then |
| 667 | print -r -- "🛑 Enhanced prompt not approved; Claude was not launched." |
| 668 | return 0 |
| 669 | fi |
| 670 | print -r -- "✅ Enhanced prompt approved." |
| 671 | fi |
| 672 | |
| 673 | if (( use_architect )); then |
| 674 | if (( use_new )); then |
| 675 | architect_start_mode="Start mode: archive-and-start-new. Explicitly archive the prior planning state as the skill directs, then begin a new architecture plan." |
| 676 | else |
| 677 | architect_start_mode="Start mode: safe-resume-detection. Safely detect whether an existing architecture planning session should be resumed; do not archive or replace it automatically." |
| 678 | fi |
| 679 | print -r -- "🚀 Launching Claude Code in architect mode..." |
| 680 | _plan_build_launch_claude "$use_yolo" "$project_id" "$memory_mode" "Read \`$architect_skill\` and follow it strictly, including every gate even when permissive Claude execution is active. Stay in the documentation-first architect/orchestrator role: produce and coordinate documentation and planning only, and do not implement the requirement. |
| 681 | |
| 682 | AgentMemory project: $project_id |
| 683 | Memory mode: $memory_mode. Run the skill's mandatory recall gate before workflow detection or repository modification. Pass this same project identity to every Codex process. |
| 684 | |
| 685 | $architect_start_mode |
| 686 | |
| 687 | Use the following payload as the initial requirement: |
| 688 | |
| 689 | $payload" |
| 690 | return $? |
| 691 | fi |
| 692 | |
| 693 | print -r -- "🚀 Launching Claude Code with the memory-aware Matt workflow..." |
| 694 | _plan_build_launch_claude "$use_yolo" "$project_id" "$memory_mode" "Read \`$standard_skill\` and strictly follow its memory-aware Matt Pocock workflow. |
| 695 | |
| 696 | AgentMemory project: $project_id |
| 697 | Memory mode: $memory_mode. Run the mandatory recall gate before routing or modifying the repository. Pass this same project identity to every Codex process. |
| 698 | |
| 699 | $payload" |
| 700 | } |
| 701 | |
| 702 | _plan_build_main() { |
| 703 | plan_build "$@" |
| 704 | } |
| 705 | |
| 706 | if [[ "${ZSH_EVAL_CONTEXT:-}" == toplevel ]]; then |
| 707 | _plan_build_main "$@" |
| 708 | fi |
| 709 |
| 1 | #!/usr/bin/env zsh |
| 2 | |
| 3 | set -u |
| 4 | |
| 5 | typeset -r repo_dir="${0:A:h}" |
| 6 | source "$repo_dir/plan_build.zsh" |
| 7 | |
| 8 | typeset -gi failures=0 |
| 9 | functions[_plan_build_real_launch_claude]="${functions[_plan_build_launch_claude]}" |
| 10 | functions[_plan_build_real_enhance_prompt]="${functions[_plan_build_enhance_prompt]}" |
| 11 | functions[_plan_build_real_start_auggie_script]="${functions[_plan_build_start_auggie_script]}" |
| 12 | functions[_plan_build_real_agentmemory_check]="${functions[_plan_build_agentmemory_check]}" |
| 13 | |
| 14 | fail() { |
| 15 | print -u2 -r -- "FAIL: $1" |
| 16 | failures=$((failures + 1)) |
| 17 | } |
| 18 | |
| 19 | assert_equal() { |
| 20 | local expected="$1" actual="$2" label="$3" |
| 21 | [[ "$actual" == "$expected" ]] || fail "$label (expected '$expected', got '$actual')" |
| 22 | } |
| 23 | |
| 24 | assert_contains() { |
| 25 | local output="$1" expected="$2" label="$3" |
| 26 | [[ "$output" == *"$expected"* ]] || fail "$label (missing '$expected')" |
| 27 | } |
| 28 | |
| 29 | assert_not_contains() { |
| 30 | local output="$1" unexpected="$2" label="$3" |
| 31 | [[ "$output" != *"$unexpected"* ]] || fail "$label (unexpected '$unexpected')" |
| 32 | } |
| 33 | |
| 34 | run_plan() { |
| 35 | local args="$1" input="${2:-EOF\n}" |
| 36 | output="$(printf '%b' "$input" | plan_build ${(z)args} 2>&1)" |
| 37 | rc=$? |
| 38 | } |
| 39 | |
| 40 | seam_events() { |
| 41 | print -r -- "$1" | sed -n 's/^SEAM://p' | paste -sd ' ' - |
| 42 | } |
| 43 | |
| 44 | count_matches() { |
| 45 | local directory="$1" prefix="$2" |
| 46 | local -a matches |
| 47 | matches=("$directory"/"$prefix".*(N)) |
| 48 | print -r -- "$#matches" |
| 49 | } |
| 50 | |
| 51 | typeset fixture_dir |
| 52 | fixture_dir="$(mktemp -d "${TMPDIR:-/tmp}/plan-build-tests.XXXXXX")" || exit 1 |
| 53 | trap 'rm -rf -- "$fixture_dir"' EXIT |
| 54 | mkdir -p "$fixture_dir/tmp" |
| 55 | export TMPDIR="$fixture_dir/tmp" |
| 56 | |
| 57 | command git init -q "$fixture_dir/worktree" |
| 58 | command git init -q --bare "$fixture_dir/bare.git" |
| 59 | |
| 60 | (cd "$fixture_dir/worktree" && _plan_build_is_worktree) |
| 61 | assert_equal 0 "$?" "normal Git worktree accepted" |
| 62 | (cd "$fixture_dir/bare.git" && _plan_build_is_worktree) |
| 63 | assert_equal 1 "$?" "bare Git repository rejected" |
| 64 | (cd "$fixture_dir" && _plan_build_is_worktree) |
| 65 | assert_equal 1 "$?" "non-repository rejected" |
| 66 | |
| 67 | plugin_state() { |
| 68 | print -r -- "$1" | _plan_build_claude_plugin_state "$2" |
| 69 | } |
| 70 | |
| 71 | assert_equal enabled "$(plugin_state $' ❯ agentmemory@agentmemory\n Version: 1\n Status: ✔ enabled' 'agentmemory@agentmemory')" "enabled Claude plugin" |
| 72 | assert_equal disabled "$(plugin_state $' ❯ mattpocock-skills@mattpocock\n Status: disabled' 'mattpocock-skills@mattpocock')" "disabled Claude plugin" |
| 73 | assert_equal missing "$(plugin_state $' ❯ other@market\n Status: ✔ enabled' 'agentmemory@agentmemory')" "missing Claude plugin" |
| 74 | assert_equal installed "$(plugin_state ' ❯ agentmemory@agentmemory' 'agentmemory@agentmemory')" "Claude plugin without status" |
| 75 | |
| 76 | assert_equal enabled "$(print -r -- 'agentmemory@agentmemory installed, enabled 1.0 /tmp/plugin' | _plan_build_codex_plugin_state)" "enabled Codex plugin" |
| 77 | assert_equal disabled "$(print -r -- $'agentmemory@agentmemory installed, disabled 1.0 /tmp/plugin\nother@market installed, enabled 1.0 /tmp/other' | _plan_build_codex_plugin_state)" "disabled Codex plugin is not confused by later plugin" |
| 78 | assert_equal missing "$(print -r -- 'other@market installed, enabled 1.0 /tmp/other' | _plan_build_codex_plugin_state)" "missing Codex plugin" |
| 79 | |
| 80 | _plan_build_project_id_is_valid "github.com/example/project" |
| 81 | assert_equal 0 "$?" "valid project ID" |
| 82 | _plan_build_project_id_is_valid "invalid project id" |
| 83 | assert_equal 1 "$?" "project ID rejects spaces" |
| 84 | _plan_build_project_id_is_valid "x" |
| 85 | assert_equal 1 "$?" "project ID minimum length" |
| 86 | |
| 87 | command git -C "$fixture_dir/worktree" remote add origin \ |
| 88 | "https://opengist.example/owner/project.git" |
| 89 | assert_equal "opengist.example/owner/project" \ |
| 90 | "$(_plan_build_default_project_id "$fixture_dir/worktree")" \ |
| 91 | "HTTPS remote normalizes to stable project ID" |
| 92 | command git -C "$fixture_dir/worktree" remote set-url origin \ |
| 93 | "git@opengist.example:owner/project.git" |
| 94 | assert_equal "opengist.example/owner/project" \ |
| 95 | "$(_plan_build_default_project_id "$fixture_dir/worktree")" \ |
| 96 | "SSH remote normalizes to stable project ID" |
| 97 | command git -C "$fixture_dir/worktree" remote set-url origin \ |
| 98 | "https://opengist.example:8443/owner/project.git" |
| 99 | assert_equal "opengist.example:8443/owner/project" \ |
| 100 | "$(_plan_build_default_project_id "$fixture_dir/worktree")" \ |
| 101 | "HTTPS remote preserves port in stable project ID" |
| 102 | |
| 103 | print -r -- "github.com/example/project" >| "$fixture_dir/worktree/.agentmemory-project" |
| 104 | command git -C "$fixture_dir/worktree" add .agentmemory-project |
| 105 | command git -C "$fixture_dir/worktree" -c user.name=Test -c user.email=test@example.invalid \ |
| 106 | commit -qm "test: add project identity" |
| 107 | project_id_output="$(cd "$fixture_dir/worktree" && _plan_build_resolve_project_id && print -r -- "$REPLY")" |
| 108 | assert_equal "github.com/example/project" "$project_id_output" "committed project ID resolves" |
| 109 | print -r -- "invalid project id" >| "$fixture_dir/worktree/.agentmemory-project" |
| 110 | (cd "$fixture_dir/worktree" && _plan_build_resolve_project_id) >/dev/null 2>&1 |
| 111 | assert_equal 1 "$?" "invalid committed project ID rejected" |
| 112 | print -r -- "github.com/example/other" >| "$fixture_dir/worktree/.agentmemory-project" |
| 113 | (cd "$fixture_dir/worktree" && _plan_build_resolve_project_id) >/dev/null 2>&1 |
| 114 | assert_equal 1 "$?" "changed project ID rejected until committed" |
| 115 | rm -f -- "$fixture_dir/worktree/.agentmemory-project" |
| 116 | _plan_build_has_tty() { return 1 } |
| 117 | (cd "$fixture_dir/worktree" && _plan_build_resolve_project_id) >/dev/null 2>&1 |
| 118 | assert_equal 1 "$?" "missing project ID fails without terminal" |
| 119 | unfunction _plan_build_has_tty |
| 120 | |
| 121 | typeset args expected label |
| 122 | for args expected label in \ |
| 123 | "--v2" "Unknown argument: --v2" "v2 rejection" \ |
| 124 | "--unknown" "Unknown argument: --unknown" "unknown option" \ |
| 125 | "--yolo --yolo" "Duplicate argument: --yolo" "duplicate yolo" \ |
| 126 | "--prompt --prompt" "Duplicate argument: --prompt" "duplicate prompt" \ |
| 127 | "--brainstorm" "Unknown argument: --brainstorm" "removed brainstorm" \ |
| 128 | "--writing-plan" "Unknown argument: --writing-plan" "removed writing plan" \ |
| 129 | "--architect --architect" "Duplicate argument: --architect" "duplicate architect" \ |
| 130 | "--architect --new --new" "Duplicate argument: --new" "duplicate new" \ |
| 131 | "--new" "--new requires --architect" "orphan new" \ |
| 132 | "--architect --prompt" "may combine only with --new and --yolo" "architect prompt conflict"; do |
| 133 | run_plan "$args" |
| 134 | assert_equal 1 "$rc" "$label status" |
| 135 | assert_contains "$output" "$expected" "$label message" |
| 136 | done |
| 137 | |
| 138 | export CLAUDE_CODE_SAFE_MODE=1 |
| 139 | output="$(_plan_build_safe_mode_preflight 2>&1)" |
| 140 | rc=$? |
| 141 | unset CLAUDE_CODE_SAFE_MODE |
| 142 | assert_equal 1 "$rc" "safe mode failure" |
| 143 | assert_contains "$output" "safe mode disables the Matt Pocock and AgentMemory plugins" "safe mode guidance" |
| 144 | |
| 145 | _plan_build_memory_action_from_reply retry |
| 146 | assert_equal 2 "$?" "memory action parses retry" |
| 147 | _plan_build_memory_action_from_reply continue |
| 148 | assert_equal 0 "$?" "memory action parses continue" |
| 149 | _plan_build_memory_action_from_reply stop |
| 150 | assert_equal 1 "$?" "memory action parses stop" |
| 151 | |
| 152 | _plan_build_agentmemory_health() { return 0 } |
| 153 | _plan_build_claude_agentmemory_state() { print -r -- enabled } |
| 154 | _plan_build_codex_agentmemory_state() { print -r -- enabled } |
| 155 | _plan_build_real_agentmemory_check >/dev/null |
| 156 | assert_equal 0 "$?" "AgentMemory check accepts healthy shared setup" |
| 157 | _plan_build_codex_agentmemory_state() { print -r -- disabled } |
| 158 | _plan_build_real_agentmemory_check >/dev/null |
| 159 | assert_equal 1 "$?" "AgentMemory check rejects disabled Codex plugin" |
| 160 | |
| 161 | typeset -gi memory_check_attempts=0 |
| 162 | _plan_build_agentmemory_check() { |
| 163 | memory_check_attempts=$((memory_check_attempts + 1)) |
| 164 | (( memory_check_attempts >= 2 )) |
| 165 | } |
| 166 | _plan_build_confirm_memory_action() { return 2 } |
| 167 | _plan_build_agentmemory_preflight >/dev/null |
| 168 | assert_equal 0 "$?" "memory retry can recover" |
| 169 | assert_equal 2 "$memory_check_attempts" "memory retry repeats health check" |
| 170 | assert_equal required "$REPLY" "recovered memory remains required" |
| 171 | |
| 172 | _plan_build_agentmemory_check() { return 1 } |
| 173 | _plan_build_confirm_memory_action() { return 0 } |
| 174 | _plan_build_agentmemory_preflight >/dev/null |
| 175 | assert_equal 0 "$?" "approved degraded memory status" |
| 176 | assert_equal degraded "$REPLY" "approved degraded memory mode" |
| 177 | _plan_build_confirm_memory_action() { return 1 } |
| 178 | _plan_build_agentmemory_preflight >/dev/null |
| 179 | assert_equal 1 "$?" "rejected degraded memory status" |
| 180 | unfunction _plan_build_agentmemory_check _plan_build_confirm_memory_action |
| 181 | |
| 182 | mkdir -p "$fixture_dir/bin" "$fixture_dir/home/.augment" "$fixture_dir/enhance-tmp" |
| 183 | print -r -- '{}' >| "$fixture_dir/home/.augment/session.json" |
| 184 | print -r -- '#!/bin/sh' >| "$fixture_dir/bin/script" |
| 185 | print -r -- 'printf "%s\n" "$@" > "$PLAN_BUILD_SCRIPT_ARGS"' >> "$fixture_dir/bin/script" |
| 186 | print -r -- 'if [ "$1" = -q ] && [ "$2" = -t ]; then log_file=$4; shift 4; "$@" > "$log_file"; exit $?; fi' >> "$fixture_dir/bin/script" |
| 187 | print -r -- 'log_file=$5; printf "Enhanced prompt: linux result\n" > "$log_file"; exit "${PLAN_BUILD_SCRIPT_STATUS:-0}"' >> "$fixture_dir/bin/script" |
| 188 | print -r -- '#!/bin/sh' >| "$fixture_dir/bin/auggie" |
| 189 | print -r -- 'printf "Enhanced prompt: mac result\n"; exit "${PLAN_BUILD_AUGGIE_STATUS:-0}"' >> "$fixture_dir/bin/auggie" |
| 190 | chmod +x "$fixture_dir/bin/script" "$fixture_dir/bin/auggie" |
| 191 | |
| 192 | _plan_build_confirm_indexing() { return 1 } |
| 193 | |
| 194 | typeset platform script_args enhance_output |
| 195 | trap 'print -u2 -r -- "test INT trap"' INT |
| 196 | typeset caller_int_trap="$(trap -p INT)" |
| 197 | for platform in Darwin Linux; do |
| 198 | _plan_build_platform() { print -r -- "$platform" } |
| 199 | : >| "$fixture_dir/script-args" |
| 200 | enhance_output="$fixture_dir/enhanced-$platform" |
| 201 | HOME="$fixture_dir/home" TMPDIR="$fixture_dir/enhance-tmp" \ |
| 202 | PATH="$fixture_dir/bin:$PATH" PLAN_BUILD_SCRIPT_ARGS="$fixture_dir/script-args" \ |
| 203 | _plan_build_real_enhance_prompt "raw prompt" "$enhance_output" |
| 204 | rc=$? |
| 205 | assert_equal 0 "$rc" "$platform script enhancement status" |
| 206 | script_args="$(<"$fixture_dir/script-args")" |
| 207 | if [[ "$platform" == Darwin ]]; then |
| 208 | assert_contains "$script_args" $'-t\n0' "macOS script immediate flushing" |
| 209 | assert_contains "$script_args" $'auggie\n--print' "macOS script direct executable dispatch" |
| 210 | assert_not_contains "$script_args" $'\ncommand\n' "macOS script excludes shell builtin" |
| 211 | assert_equal "mac result" "$(<"$enhance_output")" "macOS parsed enhancement" |
| 212 | else |
| 213 | assert_contains "$script_args" $'-q\n-f' "Linux script immediate flushing" |
| 214 | assert_contains "$script_args" $'-e\n-O' "Linux script propagates child status" |
| 215 | assert_contains "$script_args" "-c" "Linux script command mode" |
| 216 | assert_equal "linux result" "$(<"$enhance_output")" "Linux parsed enhancement" |
| 217 | fi |
| 218 | assert_equal 0 "$(count_matches "$fixture_dir/enhance-tmp" plan-build-auggie)" "$platform run directory cleanup" |
| 219 | done |
| 220 | assert_equal "$caller_int_trap" "$(trap -p INT)" "enhancement traps remain local to caller" |
| 221 | trap - INT |
| 222 | |
| 223 | platform=Darwin |
| 224 | _plan_build_platform() { print -r -- "$platform" } |
| 225 | PLAN_BUILD_AUGGIE_STATUS=7 HOME="$fixture_dir/home" TMPDIR="$fixture_dir/enhance-tmp" \ |
| 226 | PATH="$fixture_dir/bin:$PATH" PLAN_BUILD_SCRIPT_ARGS="$fixture_dir/script-args" \ |
| 227 | _plan_build_real_enhance_prompt "partial prompt" "$fixture_dir/failed-enhancement" >/dev/null 2>&1 |
| 228 | rc=$? |
| 229 | assert_equal 7 "$rc" "nonzero Auggie status propagated" |
| 230 | [[ ! -e "$fixture_dir/failed-enhancement" ]] || fail "failed Auggie output was accepted" |
| 231 | assert_equal 0 "$(count_matches "$fixture_dir/enhance-tmp" plan-build-auggie)" "failed run directory cleanup" |
| 232 | |
| 233 | platform=Linux |
| 234 | PLAN_BUILD_SCRIPT_STATUS=7 HOME="$fixture_dir/home" TMPDIR="$fixture_dir/enhance-tmp" \ |
| 235 | PATH="$fixture_dir/bin:$PATH" PLAN_BUILD_SCRIPT_ARGS="$fixture_dir/script-args" \ |
| 236 | _plan_build_real_enhance_prompt "partial prompt" "$fixture_dir/failed-linux-enhancement" >/dev/null 2>&1 |
| 237 | rc=$? |
| 238 | assert_equal 7 "$rc" "Linux script child status propagated" |
| 239 | [[ ! -e "$fixture_dir/failed-linux-enhancement" ]] || fail "failed Linux Auggie output was accepted" |
| 240 | |
| 241 | print -r -- $'noise\r\n\e[32m✨ Enhanced prompt: first\e[0m\r\nsecond\r\n🤖 tool' >| "$fixture_dir/parser.log" |
| 242 | _plan_build_parse_auggie_output "$fixture_dir/parser.log" "$fixture_dir/parser.out" |
| 243 | assert_equal $'first\nsecond' "$(<"$fixture_dir/parser.out")" "parser strips terminal output and stops at marker" |
| 244 | print -r -- "no enhanced prompt" >| "$fixture_dir/parser-empty.log" |
| 245 | _plan_build_parse_auggie_output "$fixture_dir/parser-empty.log" "$fixture_dir/parser-empty.out" |
| 246 | [[ ! -s "$fixture_dir/parser-empty.out" ]] || fail "parser accepted output without marker" |
| 247 | |
| 248 | typeset -g enhanced_text="enhanced payload" |
| 249 | typeset -gi enhanced_approval=0 |
| 250 | typeset -gi common_preflight_result=0 |
| 251 | typeset -gi enhancement_result=0 |
| 252 | |
| 253 | _plan_build_require_cli() { |
| 254 | print -r -- "SEAM:cli:$1" |
| 255 | return 0 |
| 256 | } |
| 257 | _plan_build_common_preflight() { |
| 258 | print -r -- "SEAM:common:$2" |
| 259 | return "$common_preflight_result" |
| 260 | } |
| 261 | _plan_build_resolve_project_id() { |
| 262 | print -r -- "SEAM:project-id" |
| 263 | REPLY="github.com/example/project" |
| 264 | } |
| 265 | _plan_build_agentmemory_preflight() { |
| 266 | print -r -- "SEAM:memory" |
| 267 | REPLY="required" |
| 268 | } |
| 269 | _plan_build_enhance_prompt() { |
| 270 | print -r -- "SEAM:auggie:$1" |
| 271 | print -r -- "$enhanced_text" >| "$2" |
| 272 | return "$enhancement_result" |
| 273 | } |
| 274 | _plan_build_confirm_enhanced_prompt() { |
| 275 | print -r -- "SEAM:enhanced-approval" |
| 276 | return "$enhanced_approval" |
| 277 | } |
| 278 | _plan_build_launch_claude() { |
| 279 | print -r -- "SEAM:claude" |
| 280 | printf 'CLAUDE_YOLO=<%s>\nCLAUDE_PROJECT=<%s>\nCLAUDE_MEMORY=<%s>\nCLAUDE_PROMPT=<%s>\n' "$1" "$2" "$3" "$4" |
| 281 | } |
| 282 | |
| 283 | run_plan "" "first line\nsecond line\nEOF\nignored line\n" |
| 284 | assert_equal 0 "$rc" "Matt default mode status" |
| 285 | assert_contains "$output" "memory-aware Matt Pocock workflow" "Matt workflow prompt" |
| 286 | assert_contains "$output" "AgentMemory project: github.com/example/project" "memory project prompt" |
| 287 | assert_contains "$output" "Run the mandatory recall gate" "recall gate prompt" |
| 288 | assert_contains "$output" $'first line\nsecond line' "multiline payload" |
| 289 | assert_not_contains "$output" "ignored line" "EOF terminates payload" |
| 290 | assert_equal "common:1 project-id memory claude" "$(seam_events "$output")" "default preflight ordering" |
| 291 | |
| 292 | enhanced_approval=0 |
| 293 | run_plan "--prompt" "raw payload\nEOF\n" |
| 294 | assert_equal 0 "$rc" "prompt mode approved status" |
| 295 | assert_contains "$output" "enhanced payload" "enhanced prompt used" |
| 296 | assert_contains "$output" "Enhanced prompt approved" "enhanced approval reported" |
| 297 | assert_equal "common:1 cli:auggie cli:script cli:perl project-id memory auggie:raw payload enhanced-approval claude" "$(seam_events "$output")" "prompt seams ordering" |
| 298 | |
| 299 | enhancement_result=9 |
| 300 | run_plan "--prompt" "failed child\nEOF\n" |
| 301 | assert_equal 9 "$rc" "prompt child failure status propagated" |
| 302 | assert_not_contains "$output" "enhanced-approval" "failed enhancement is never parsed or approved" |
| 303 | assert_not_contains "$output" "SEAM:claude" "failed enhancement prevents launch" |
| 304 | assert_equal 0 "$(count_matches "$TMPDIR" plan-build-enhanced)" "enhanced temporary file cleanup" |
| 305 | enhancement_result=0 |
| 306 | |
| 307 | enhanced_approval=1 |
| 308 | run_plan "--prompt" "declined\nEOF\n" |
| 309 | assert_equal 0 "$rc" "prompt rejection exits cleanly" |
| 310 | assert_contains "$output" "not approved" "prompt rejection message" |
| 311 | assert_equal "common:1 cli:auggie cli:script cli:perl project-id memory auggie:declined enhanced-approval" "$(seam_events "$output")" "prompt rejection prevents launch" |
| 312 | enhanced_approval=0 |
| 313 | |
| 314 | run_plan "--architect" "design feature\nEOF\n" |
| 315 | assert_equal 0 "$rc" "architect safe-resume status" |
| 316 | assert_contains "$output" "Start mode: safe-resume-detection" "architect safe-resume mode" |
| 317 | assert_contains "$output" "documentation-first architect/orchestrator role" "architect role boundary" |
| 318 | assert_contains "$output" "Run the skill's mandatory recall gate" "architect recall gate prompt" |
| 319 | assert_equal "common:0 project-id memory claude" "$(seam_events "$output")" "architect preflight before launch" |
| 320 | |
| 321 | run_plan "--architect --new" "fresh design\nEOF\n" |
| 322 | assert_equal 0 "$rc" "architect new status" |
| 323 | assert_contains "$output" "Start mode: archive-and-start-new" "architect new mode" |
| 324 | |
| 325 | run_plan "--architect --yolo" "fast design\nEOF\n" |
| 326 | assert_equal 0 "$rc" "architect yolo status" |
| 327 | assert_contains "$output" "CLAUDE_YOLO=<1>" "architect yolo reaches launch seam" |
| 328 | assert_contains "$output" "including every gate" "architect yolo retains gates" |
| 329 | |
| 330 | common_preflight_result=1 |
| 331 | run_plan "--architect" "must not be read\nEOF\n" |
| 332 | assert_equal 1 "$rc" "architect preflight failure status" |
| 333 | assert_not_contains "$output" "Reading payload" "architect preflight precedes payload" |
| 334 | assert_equal "common:0" "$(seam_events "$output")" "architect failure stops processing" |
| 335 | common_preflight_result=0 |
| 336 | |
| 337 | run_plan "" "EOF\n" |
| 338 | assert_equal 1 "$rc" "empty payload status" |
| 339 | assert_contains "$output" "Payload was empty" "empty payload message" |
| 340 | |
| 341 | print -r -- '#!/bin/sh' >| "$fixture_dir/bin/claude" |
| 342 | print -r -- 'printf "PROJECT=<%s> MEMORY=<%s> INJECT=<%s> REAL_CLAUDE:" "$AGENTMEMORY_PROJECT_NAME" "$PLAN_BUILD_MEMORY_MODE" "$AGENTMEMORY_INJECT_CONTEXT"; printf " <%s>" "$@"; printf "\n"' >> "$fixture_dir/bin/claude" |
| 343 | chmod +x "$fixture_dir/bin/claude" |
| 344 | output="$(PATH="$fixture_dir/bin:$PATH" _plan_build_real_launch_claude 1 "github.com/example/project" required "payload")" |
| 345 | assert_contains "$output" "<--dangerously-skip-permissions>" "yolo translates to real Claude argument" |
| 346 | assert_not_contains "$output" "<--yolo>" "yolo alias not forwarded" |
| 347 | assert_contains "$output" "PROJECT=<github.com/example/project>" "project ID reaches Claude environment" |
| 348 | assert_contains "$output" "MEMORY=<required>" "memory mode reaches Claude environment" |
| 349 | assert_contains "$output" "INJECT=<true>" "context injection reaches Claude environment" |
| 350 | output="$(PATH="$fixture_dir/bin:$PATH" _plan_build_real_launch_claude 0 "github.com/example/project" degraded "payload")" |
| 351 | assert_contains "$output" "MEMORY=<degraded>" "degraded memory mode reaches Claude environment" |
| 352 | assert_contains "$output" "INJECT=<false>" "degraded mode disables context injection" |
| 353 | |
| 354 | if (( failures )); then |
| 355 | print -u2 -r -- "FAIL: $failures plan_build test(s)" |
| 356 | exit 1 |
| 357 | fi |
| 358 | |
| 359 | print -r -- "PASS: plan_build tests" |
| 360 |