From 7dc282b72438c2e23a08d506c711ef515aa38e68 Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 12:42:32 +0200 Subject: [PATCH 01/21] next-task: Implement reviewed task execution workflow Replace the broad agent prompt set with a focused /next-task workflow that separates readiness review, implementation approval, task execution, and durable context reconciliation. Add structured contracts, strict plan argument handling, and explicit blocked and continuation guidance across workflow handoffs. Co-authored-by: SCE --- .pi/prompts/agent-shared-context-code.md | 62 ---- .pi/prompts/agent-shared-context-plan.md | 68 ---- .pi/prompts/commit.md | 42 --- .pi/prompts/handover.md | 15 - .pi/prompts/next-task.md | 209 ++++++++++-- .pi/prompts/validate.md | 15 - .pi/skills/sce-atomic-commit/SKILL.md | 102 ------ .pi/skills/sce-bootstrap-context/SKILL.md | 55 ---- .pi/skills/sce-context-sync/SKILL.md | 91 ------ .pi/skills/sce-handover-writer/SKILL.md | 46 --- .pi/skills/sce-plan-review/SKILL.md | 229 ++++++++----- .../references/readiness-contract.yaml | 246 ++++++++++++++ .pi/skills/sce-task-context-sync/SKILL.md | 216 +++++++++++++ .../references/sync-report.md | 102 ++++++ .pi/skills/sce-task-execution/SKILL.md | 294 ++++++++++++++--- .../references/execution-contract.yaml | 306 ++++++++++++++++++ .../references/implementation-gate.md | 69 ++++ .pi/skills/sce-validation/SKILL.md | 45 --- 18 files changed, 1513 insertions(+), 699 deletions(-) delete mode 100644 .pi/prompts/agent-shared-context-code.md delete mode 100644 .pi/prompts/agent-shared-context-plan.md delete mode 100644 .pi/prompts/commit.md delete mode 100644 .pi/prompts/handover.md delete mode 100644 .pi/prompts/validate.md delete mode 100644 .pi/skills/sce-atomic-commit/SKILL.md delete mode 100644 .pi/skills/sce-bootstrap-context/SKILL.md delete mode 100644 .pi/skills/sce-context-sync/SKILL.md delete mode 100644 .pi/skills/sce-handover-writer/SKILL.md create mode 100644 .pi/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 .pi/skills/sce-task-context-sync/SKILL.md create mode 100644 .pi/skills/sce-task-context-sync/references/sync-report.md create mode 100644 .pi/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 .pi/skills/sce-task-execution/references/implementation-gate.md delete mode 100644 .pi/skills/sce-validation/SKILL.md diff --git a/.pi/prompts/agent-shared-context-code.md b/.pi/prompts/agent-shared-context-code.md deleted file mode 100644 index 9d3abdd5..00000000 --- a/.pi/prompts/agent-shared-context-code.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -description: "Act in the shared-context-code role to execute one approved SCE task and sync context." -argument-hint: " [T0X]" ---- - -Act as the Shared Context Code agent for the rest of this session. Load and follow the `sce-task-execution` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/.pi/prompts/agent-shared-context-plan.md b/.pi/prompts/agent-shared-context-plan.md deleted file mode 100644 index 5dbad4e1..00000000 --- a/.pi/prompts/agent-shared-context-plan.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -description: "Act in the shared-context-plan role to create or update an SCE plan before implementation." -argument-hint: "" ---- - -Act as the Shared Context Plan agent for the rest of this session. Load and follow the `sce-plan-authoring` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/.pi/prompts/commit.md b/.pi/prompts/commit.md deleted file mode 100644 index b868096a..00000000 --- a/.pi/prompts/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -argument-hint: "[oneshot|skip]" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/.pi/prompts/handover.md b/.pi/prompts/handover.md deleted file mode 100644 index af3666ff..00000000 --- a/.pi/prompts/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -argument-hint: "[task context]" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/.pi/prompts/next-task.md b/.pi/prompts/next-task.md index 3cfa8607..6859e4d4 100644 --- a/.pi/prompts/next-task.md +++ b/.pi/prompts/next-task.md @@ -1,24 +1,191 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -argument-hint: " [T0X]" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/.pi/prompts/validate.md b/.pi/prompts/validate.md deleted file mode 100644 index e2c32ffe..00000000 --- a/.pi/prompts/validate.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" -argument-hint: "" ---- - -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. diff --git a/.pi/skills/sce-atomic-commit/SKILL.md b/.pi/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7fe5bd..00000000 --- a/.pi/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: sce-atomic-commit -description: Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/.pi/skills/sce-bootstrap-context/SKILL.md b/.pi/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 69610b01..00000000 --- a/.pi/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: sce-bootstrap-context -description: Use when user wants to Bootstrap SCE baseline context directory when missing. ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/.pi/skills/sce-context-sync/SKILL.md b/.pi/skills/sce-context-sync/SKILL.md deleted file mode 100644 index f051a981..00000000 --- a/.pi/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: sce-context-sync -description: Use when user wants to Synchronize context files to match current code behavior after task execution. ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/.pi/skills/sce-handover-writer/SKILL.md b/.pi/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 73292812..00000000 --- a/.pi/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: sce-handover-writer -description: Use when user wants to create a structured SCE handover for the current task. ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/.pi/skills/sce-plan-review/SKILL.md b/.pi/skills/sce-plan-review/SKILL.md index 471baf7b..77c36481 100644 --- a/.pi/skills/sce-plan-review/SKILL.md +++ b/.pi/skills/sce-plan-review/SKILL.md @@ -1,89 +1,148 @@ --- name: sce-plan-review -description: Use when user wants to review an existing plan and prepare the next task safely. +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/.pi/skills/sce-plan-review/references/readiness-contract.yaml b/.pi/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/.pi/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/.pi/skills/sce-task-context-sync/SKILL.md b/.pi/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..c96ad1e2 --- /dev/null +++ b/.pi/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,216 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 3. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows: + +- `none`: Verify that existing context remains accurate; normally make no edits. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 4. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +### 5. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 6. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Add documentation solely because files changed. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.pi/skills/sce-task-context-sync/references/sync-report.md b/.pi/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..41d4a7fd --- /dev/null +++ b/.pi/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,102 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/.pi/skills/sce-task-execution/SKILL.md b/.pi/skills/sce-task-execution/SKILL.md index 36a78e5b..3c8f7f70 100644 --- a/.pi/skills/sce-task-execution/SKILL.md +++ b/.pi/skills/sce-task-execution/SKILL.md @@ -1,56 +1,246 @@ --- name: sce-task-execution -description: Use when user wants to Execute one approved task with explicit scope, evidence, and status updates. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/.pi/skills/sce-task-execution/references/execution-contract.yaml b/.pi/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/.pi/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.pi/skills/sce-task-execution/references/implementation-gate.md b/.pi/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/.pi/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/.pi/skills/sce-validation/SKILL.md b/.pi/skills/sce-validation/SKILL.md deleted file mode 100644 index efb7a23e..00000000 --- a/.pi/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: sce-validation -description: Use when user wants to Run final plan validation and cleanup with evidence capture. ---- - -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` From 32d84fbd23fd6adf35eb3c447c8aaf5fd0388d7b Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 15:51:12 +0200 Subject: [PATCH 02/21] change-to-plan: Implement context-driven plan authoring Split durable context loading from plan authoring, add structured contracts for both phases, and strengthen post-task context reconciliation. Keep the implementation gate explicit while ensuring /change-to-plan stops after producing an implementation-ready plan. Co-authored-by: SCE --- .pi/prompts/change-to-plan.md | 182 ++++++++- .pi/skills/sce-context-load/SKILL.md | 128 ++++++ .../references/context-brief.yaml | 153 ++++++++ .pi/skills/sce-plan-authoring/SKILL.md | 368 ++++++++++++++---- .../references/authoring-contract.yaml | 256 ++++++++++++ .../references/plan-summary.md | 94 +++++ .../references/plan-template.md | 170 ++++++++ .pi/skills/sce-task-context-sync/SKILL.md | 112 +++++- .../references/sync-report.md | 31 ++ 9 files changed, 1390 insertions(+), 104 deletions(-) create mode 100644 .pi/skills/sce-context-load/SKILL.md create mode 100644 .pi/skills/sce-context-load/references/context-brief.yaml create mode 100644 .pi/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 .pi/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 .pi/skills/sce-plan-authoring/references/plan-template.md diff --git a/.pi/prompts/change-to-plan.md b/.pi/prompts/change-to-plan.md index 8a782aea..9ee4f81f 100644 --- a/.pi/prompts/change-to-plan.md +++ b/.pi/prompts/change-to-plan.md @@ -1,17 +1,175 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/.pi/skills/sce-context-load/SKILL.md b/.pi/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..c944be76 --- /dev/null +++ b/.pi/skills/sce-context-load/SKILL.md @@ -0,0 +1,128 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/.pi/skills/sce-context-load/references/context-brief.yaml b/.pi/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/.pi/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/.pi/skills/sce-plan-authoring/SKILL.md b/.pi/skills/sce-plan-authoring/SKILL.md index 02c177e4..946e686b 100644 --- a/.pi/skills/sce-plan-authoring/SKILL.md +++ b/.pi/skills/sce-plan-authoring/SKILL.md @@ -1,87 +1,289 @@ --- name: sce-plan-authoring -description: Use when user wants to Create or update an SCE implementation plan with scoped atomic tasks. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml b/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/.pi/skills/sce-plan-authoring/references/plan-summary.md b/.pi/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/.pi/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/.pi/skills/sce-plan-authoring/references/plan-template.md b/.pi/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/.pi/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/.pi/skills/sce-task-context-sync/SKILL.md b/.pi/skills/sce-task-context-sync/SKILL.md index c96ad1e2..7af7c880 100644 --- a/.pi/skills/sce-task-context-sync/SKILL.md +++ b/.pi/skills/sce-task-context-sync/SKILL.md @@ -19,6 +19,7 @@ Markdown report. This skill owns: - Validating the execution handoff. +- Confirming the context root exists. - Discovering the context affected by one completed task. - Deciding whether durable context changed. - Editing and verifying the affected context files. @@ -71,7 +72,21 @@ Confirm that: If the handoff is missing required information or is internally contradictory, do not modify context. Return a `blocked` Markdown report. -### 2. Discover applicable context +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context Start with the execution result: @@ -88,7 +103,8 @@ Then inspect existing repository context in this order when present: 3. `context/overview.md` 4. `context/architecture.md` 5. `context/glossary.md` -6. Operational, product, or decision records directly related to the change +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change Use the context map and existing links to locate authoritative files. @@ -97,7 +113,29 @@ Do not scan or rewrite the entire `context/` tree by default. Do not create a new context file when an existing authoritative file can be updated coherently. -### 3. Determine whether durable context changed +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed Use the reported context impact as a strong hint, then verify it against the implementation and existing context. @@ -121,19 +159,26 @@ Do not document: - Speculation or future work not established by the completed implementation. - Generic engineering practices. -Interpret impact classifications as follows: +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. -- `none`: Verify that existing context remains accurate; normally make no edits. +- `none`: Make no edits beyond any correction the root pass turns up. - `local`: Update the nearest existing authoritative context only when the new behavior is not reliably discoverable from code. - `domain`: Update affected domain context and the context map when its links or summaries changed. - `root`: Update the relevant root context and any affected domain context. +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + If the reported classification is inconsistent with the actual change, use the verified classification and explain the difference in the report. -### 4. Synchronize context +### 5. Synchronize context Make the smallest coherent documentation change that preserves repository truth. @@ -153,12 +198,55 @@ Create a new context file only when: - No existing file owns it coherently. - The new file has a clear place in the context map. -### 5. Verify synchronization +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization After edits, verify: - Every changed context file accurately reflects the completed implementation. - No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. - Links and referenced paths resolve when practical to check. - New context files are reachable from the context map or another authoritative index. @@ -173,7 +261,7 @@ If synchronization cannot be completed without inventing facts or resolving a material contradiction, preserve safe edits when appropriate and return a `blocked` report. -### 6. Return the Markdown report +### 7. Return the Markdown report Return exactly one report status: @@ -204,13 +292,19 @@ Do not: - Run full-plan validation. - Mark the plan validated, closed, or archived. - Create a Git commit or push changes. -- Add documentation solely because files changed. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. - Return an execution-style YAML result. ## Completion The skill is complete after: +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. - Applicable durable context was synchronized and verified, no context change was warranted, or a synchronization blocker was reported. - One Markdown report matching `references/sync-report.md` was returned. diff --git a/.pi/skills/sce-task-context-sync/references/sync-report.md b/.pi/skills/sce-task-context-sync/references/sync-report.md index 41d4a7fd..7d5acb94 100644 --- a/.pi/skills/sce-task-context-sync/references/sync-report.md +++ b/.pi/skills/sce-task-context-sync/references/sync-report.md @@ -32,9 +32,22 @@ constraint required synchronization.} - `{context file}` — {concise description of the durable truth updated} +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + ## Verification - {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} - {Documentation, link, or formatting checks that were run, when applicable.} ## Notes @@ -63,6 +76,18 @@ non-obvious repository knowledge requiring an update.} - `{context file or area}` — {what was checked and why it remains accurate} +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + ## Verification - {How existing context was compared with implementation and execution evidence.} @@ -95,6 +120,12 @@ again.} ## Report rules - Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. - Describe durable truth, not implementation-session chronology. - Keep evidence concise and factual. - Do not claim final validation passed. From 578d09aa7a61997aab362ac96299e5b25f036a4d Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 15:11:43 +0200 Subject: [PATCH 03/21] validate: Add final validation and plan context sync workflows Introduce /validate as a report-only final verification phase and add a separate plan context synchronization skill that runs only after validation passes. Structured result and report references keep failure, blocking, and success handoffs unambiguous. --- .pi/prompts/validate.md | 144 ++++++++ .pi/skills/sce-plan-context-sync/SKILL.md | 308 ++++++++++++++++++ .../references/sync-report.md | 142 ++++++++ .pi/skills/sce-validation/SKILL.md | 189 +++++++++++ .../references/validation-report.md | 84 +++++ .../references/validation-result.md | 186 +++++++++++ 6 files changed, 1053 insertions(+) create mode 100644 .pi/prompts/validate.md create mode 100644 .pi/skills/sce-plan-context-sync/SKILL.md create mode 100644 .pi/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 .pi/skills/sce-validation/SKILL.md create mode 100644 .pi/skills/sce-validation/references/validation-report.md create mode 100644 .pi/skills/sce-validation/references/validation-result.md diff --git a/.pi/prompts/validate.md b/.pi/prompts/validate.md new file mode 100644 index 00000000..d35fb89c --- /dev/null +++ b/.pi/prompts/validate.md @@ -0,0 +1,144 @@ +--- +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +argument-hint: "" +--- + +SCE VALIDATE `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/.pi/skills/sce-plan-context-sync/SKILL.md b/.pi/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..04958458 --- /dev/null +++ b/.pi/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,308 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.pi/skills/sce-plan-context-sync/references/sync-report.md b/.pi/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/.pi/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.pi/skills/sce-validation/SKILL.md b/.pi/skills/sce-validation/SKILL.md new file mode 100644 index 00000000..2cd7557b --- /dev/null +++ b/.pi/skills/sce-validation/SKILL.md @@ -0,0 +1,189 @@ +--- +name: sce-validation +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. +--- + +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/.pi/skills/sce-validation/references/validation-report.md b/.pi/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/.pi/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/.pi/skills/sce-validation/references/validation-result.md b/.pi/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/.pi/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. From e7c745a60d7403aeb7b94d129e3d6cd10e1571bf Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 17:05:34 +0200 Subject: [PATCH 04/21] pkl: Rebuild generation around workflow packages Replace the shared-content catalog with canonical packages for /change-to-plan, /next-task, and /validate. Generate self-contained Pi, OpenCode, and Claude skills from workflow-owned Pkl, remove the automated and legacy workflow trees, and enforce the new inventory in parity checks. Plan: rebuild-pkl-workflow-markdown (T01, T02, T03, T04, T05, T06, T07, T08, T09) Co-authored-by: SCE --- config/.claude/agents/shared-context-code.md | 60 - config/.claude/agents/shared-context-plan.md | 66 - config/.claude/commands/change-to-plan.md | 181 ++- config/.claude/commands/commit.md | 42 - config/.claude/commands/handover.md | 15 - config/.claude/commands/next-task.md | 208 ++- config/.claude/commands/validate.md | 148 +- .../.claude/skills/sce-atomic-commit/SKILL.md | 104 -- .../skills/sce-bootstrap-context/SKILL.md | 57 - .../.claude/skills/sce-context-load/SKILL.md | 129 ++ .../references/context-brief.yaml | 153 ++ .../.claude/skills/sce-context-sync/SKILL.md | 93 -- .../skills/sce-handover-writer/SKILL.md | 48 - .../skills/sce-plan-authoring/SKILL.md | 369 ++++- .../references/authoring-contract.yaml | 256 +++ .../references/plan-summary.md | 94 ++ .../references/plan-template.md | 170 ++ .../skills/sce-plan-context-sync/SKILL.md | 309 ++++ .../references/sync-report.md | 142 ++ .../.claude/skills/sce-plan-review/SKILL.md | 230 ++- .../references/readiness-contract.yaml | 246 +++ .../skills/sce-task-context-sync/SKILL.md | 311 ++++ .../references/sync-report.md | 133 ++ .../skills/sce-task-execution/SKILL.md | 295 +++- .../references/execution-contract.yaml | 306 ++++ .../references/implementation-gate.md | 69 + config/.claude/skills/sce-validation/SKILL.md | 227 ++- .../references/validation-report.md | 84 + .../references/validation-result.md | 186 +++ config/.opencode/agent/Shared Context Code.md | 57 +- config/.opencode/agent/Shared Context Plan.md | 61 +- config/.opencode/command/change-to-plan.md | 184 ++- config/.opencode/command/commit.md | 45 - config/.opencode/command/handover.md | 18 - config/.opencode/command/next-task.md | 211 ++- config/.opencode/command/validate.md | 149 +- .../skills/sce-atomic-commit/SKILL.md | 104 -- .../skills/sce-bootstrap-context/SKILL.md | 57 - .../skills/sce-context-load/SKILL.md | 129 ++ .../references/context-brief.yaml | 153 ++ .../skills/sce-context-sync/SKILL.md | 93 -- .../skills/sce-handover-writer/SKILL.md | 48 - .../skills/sce-plan-authoring/SKILL.md | 369 ++++- .../references/authoring-contract.yaml | 256 +++ .../references/plan-summary.md | 94 ++ .../references/plan-template.md | 170 ++ .../skills/sce-plan-context-sync/SKILL.md | 309 ++++ .../references/sync-report.md | 142 ++ .../.opencode/skills/sce-plan-review/SKILL.md | 230 ++- .../references/readiness-contract.yaml | 246 +++ .../skills/sce-task-context-sync/SKILL.md | 311 ++++ .../references/sync-report.md | 133 ++ .../skills/sce-task-execution/SKILL.md | 295 +++- .../references/execution-contract.yaml | 306 ++++ .../references/implementation-gate.md | 69 + .../.opencode/skills/sce-validation/SKILL.md | 227 ++- .../references/validation-report.md | 84 + .../references/validation-result.md | 186 +++ .../.pi/prompts/agent-shared-context-code.md | 62 - .../.pi/prompts/agent-shared-context-plan.md | 68 - config/.pi/prompts/change-to-plan.md | 182 ++- config/.pi/prompts/commit.md | 42 - config/.pi/prompts/handover.md | 15 - config/.pi/prompts/next-task.md | 209 ++- config/.pi/prompts/validate.md | 147 +- config/.pi/skills/sce-atomic-commit/SKILL.md | 102 -- .../.pi/skills/sce-bootstrap-context/SKILL.md | 55 - config/.pi/skills/sce-context-load/SKILL.md | 128 ++ .../references/context-brief.yaml | 153 ++ config/.pi/skills/sce-context-sync/SKILL.md | 91 -- .../.pi/skills/sce-handover-writer/SKILL.md | 46 - config/.pi/skills/sce-plan-authoring/SKILL.md | 368 ++++- .../references/authoring-contract.yaml | 256 +++ .../references/plan-summary.md | 94 ++ .../references/plan-template.md | 170 ++ .../.pi/skills/sce-plan-context-sync/SKILL.md | 308 ++++ .../references/sync-report.md | 142 ++ config/.pi/skills/sce-plan-review/SKILL.md | 229 ++- .../references/readiness-contract.yaml | 246 +++ .../.pi/skills/sce-task-context-sync/SKILL.md | 310 ++++ .../references/sync-report.md | 133 ++ config/.pi/skills/sce-task-execution/SKILL.md | 294 +++- .../references/execution-contract.yaml | 306 ++++ .../references/implementation-gate.md | 69 + config/.pi/skills/sce-validation/SKILL.md | 226 ++- .../references/validation-report.md | 84 + .../references/validation-result.md | 186 +++ .../.opencode/agent/Shared Context Code.md | 83 - .../.opencode/agent/Shared Context Plan.md | 87 -- .../command/change-to-plan-interactive.md | 17 - .../.opencode/command/change-to-plan.md | 19 - config/automated/.opencode/command/commit.md | 20 - .../automated/.opencode/command/handover.md | 19 - .../automated/.opencode/command/next-task.md | 24 - .../automated/.opencode/command/validate.md | 14 - .../.opencode/lib/bash-policy-presets.json | 84 - config/automated/.opencode/opencode.json | 6 - .../.opencode/plugins/sce-agent-trace.ts | 422 ----- .../.opencode/plugins/sce-bash-policy.ts | 84 - .../skills/sce-atomic-commit/SKILL.md | 81 - .../skills/sce-bootstrap-context/SKILL.md | 37 - .../skills/sce-context-sync/SKILL.md | 93 -- .../skills/sce-handover-writer/SKILL.md | 48 - .../sce-plan-authoring-interactive/SKILL.md | 163 -- .../skills/sce-plan-authoring/SKILL.md | 138 -- .../.opencode/skills/sce-plan-review/SKILL.md | 78 - .../skills/sce-task-execution/SKILL.md | 47 - .../.opencode/skills/sce-validation/SKILL.md | 47 - config/pkl/README.md | 107 +- .../base/shared-content-automated-code.pkl | 282 ---- .../base/shared-content-automated-commit.pkl | 111 -- .../base/shared-content-automated-common.pkl | 39 - .../base/shared-content-automated-plan.pkl | 578 ------- config/pkl/base/shared-content-automated.pkl | 134 -- config/pkl/base/shared-content-code.pkl | 295 ---- config/pkl/base/shared-content-commit.pkl | 156 -- config/pkl/base/shared-content-common.pkl | 38 - config/pkl/base/shared-content-plan.pkl | 378 ----- config/pkl/base/shared-content.pkl | 120 -- config/pkl/base/workflow-change-to-plan.pkl | 1335 ++++++++++++++++ config/pkl/base/workflow-content.pkl | 31 + config/pkl/base/workflow-context-sync.pkl | 1391 +++++++++++++++++ config/pkl/base/workflow-next-task.pkl | 1274 +++++++++++++++ config/pkl/base/workflow-validate.pkl | 655 ++++++++ config/pkl/check-generated.sh | 46 +- config/pkl/generate.pkl | 63 +- config/pkl/renderers/claude-content.pkl | 99 +- config/pkl/renderers/claude-metadata.pkl | 30 - config/pkl/renderers/common.pkl | 25 - .../pkl/renderers/metadata-coverage-check.pkl | 195 +-- .../renderers/opencode-automated-content.pkl | 88 -- .../renderers/opencode-automated-metadata.pkl | 99 -- config/pkl/renderers/opencode-content.pkl | 146 +- config/pkl/renderers/opencode-metadata.pkl | 26 +- config/pkl/renderers/pi-content.pkl | 93 +- config/pkl/renderers/pi-metadata.pkl | 22 - context/architecture.md | 51 +- context/context-map.md | 7 +- ...-07-27-workflow-oriented-pkl-generation.md | 34 + context/glossary.md | 32 +- context/overview.md | 26 +- context/patterns.md | 35 +- .../plans/rebuild-pkl-workflow-markdown.md | 202 +++ context/sce/atomic-commit-workflow.md | 58 - context/sce/automated-profile-contract.md | 220 --- context/sce/dedup-ownership-table.md | 35 +- .../generated-opencode-plugin-registration.md | 15 +- context/sce/plan-code-overlap-map.md | 53 +- context/sce/shared-context-code-workflow.md | 120 +- context/sce/shared-context-plan-workflow.md | 122 +- flake.nix | 69 +- 151 files changed, 17346 insertions(+), 7388 deletions(-) delete mode 100644 config/.claude/agents/shared-context-code.md delete mode 100644 config/.claude/agents/shared-context-plan.md delete mode 100644 config/.claude/commands/commit.md delete mode 100644 config/.claude/commands/handover.md delete mode 100644 config/.claude/skills/sce-atomic-commit/SKILL.md delete mode 100644 config/.claude/skills/sce-bootstrap-context/SKILL.md create mode 100644 config/.claude/skills/sce-context-load/SKILL.md create mode 100644 config/.claude/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.claude/skills/sce-context-sync/SKILL.md delete mode 100644 config/.claude/skills/sce-handover-writer/SKILL.md create mode 100644 config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 config/.claude/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 config/.claude/skills/sce-plan-authoring/references/plan-template.md create mode 100644 config/.claude/skills/sce-plan-context-sync/SKILL.md create mode 100644 config/.claude/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 config/.claude/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 config/.claude/skills/sce-task-context-sync/SKILL.md create mode 100644 config/.claude/skills/sce-task-context-sync/references/sync-report.md create mode 100644 config/.claude/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 config/.claude/skills/sce-task-execution/references/implementation-gate.md create mode 100644 config/.claude/skills/sce-validation/references/validation-report.md create mode 100644 config/.claude/skills/sce-validation/references/validation-result.md delete mode 100644 config/.opencode/command/commit.md delete mode 100644 config/.opencode/command/handover.md delete mode 100644 config/.opencode/skills/sce-atomic-commit/SKILL.md delete mode 100644 config/.opencode/skills/sce-bootstrap-context/SKILL.md create mode 100644 config/.opencode/skills/sce-context-load/SKILL.md create mode 100644 config/.opencode/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.opencode/skills/sce-context-sync/SKILL.md delete mode 100644 config/.opencode/skills/sce-handover-writer/SKILL.md create mode 100644 config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 config/.opencode/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 config/.opencode/skills/sce-plan-authoring/references/plan-template.md create mode 100644 config/.opencode/skills/sce-plan-context-sync/SKILL.md create mode 100644 config/.opencode/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 config/.opencode/skills/sce-task-context-sync/SKILL.md create mode 100644 config/.opencode/skills/sce-task-context-sync/references/sync-report.md create mode 100644 config/.opencode/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 config/.opencode/skills/sce-task-execution/references/implementation-gate.md create mode 100644 config/.opencode/skills/sce-validation/references/validation-report.md create mode 100644 config/.opencode/skills/sce-validation/references/validation-result.md delete mode 100644 config/.pi/prompts/agent-shared-context-code.md delete mode 100644 config/.pi/prompts/agent-shared-context-plan.md delete mode 100644 config/.pi/prompts/commit.md delete mode 100644 config/.pi/prompts/handover.md delete mode 100644 config/.pi/skills/sce-atomic-commit/SKILL.md delete mode 100644 config/.pi/skills/sce-bootstrap-context/SKILL.md create mode 100644 config/.pi/skills/sce-context-load/SKILL.md create mode 100644 config/.pi/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.pi/skills/sce-context-sync/SKILL.md delete mode 100644 config/.pi/skills/sce-handover-writer/SKILL.md create mode 100644 config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 config/.pi/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 config/.pi/skills/sce-plan-authoring/references/plan-template.md create mode 100644 config/.pi/skills/sce-plan-context-sync/SKILL.md create mode 100644 config/.pi/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 config/.pi/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 config/.pi/skills/sce-task-context-sync/SKILL.md create mode 100644 config/.pi/skills/sce-task-context-sync/references/sync-report.md create mode 100644 config/.pi/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 config/.pi/skills/sce-task-execution/references/implementation-gate.md create mode 100644 config/.pi/skills/sce-validation/references/validation-report.md create mode 100644 config/.pi/skills/sce-validation/references/validation-result.md delete mode 100644 config/automated/.opencode/agent/Shared Context Code.md delete mode 100644 config/automated/.opencode/agent/Shared Context Plan.md delete mode 100644 config/automated/.opencode/command/change-to-plan-interactive.md delete mode 100644 config/automated/.opencode/command/change-to-plan.md delete mode 100644 config/automated/.opencode/command/commit.md delete mode 100644 config/automated/.opencode/command/handover.md delete mode 100644 config/automated/.opencode/command/next-task.md delete mode 100644 config/automated/.opencode/command/validate.md delete mode 100644 config/automated/.opencode/lib/bash-policy-presets.json delete mode 100644 config/automated/.opencode/opencode.json delete mode 100644 config/automated/.opencode/plugins/sce-agent-trace.ts delete mode 100644 config/automated/.opencode/plugins/sce-bash-policy.ts delete mode 100644 config/automated/.opencode/skills/sce-atomic-commit/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-bootstrap-context/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-context-sync/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-handover-writer/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-plan-authoring-interactive/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-plan-authoring/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-plan-review/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-task-execution/SKILL.md delete mode 100644 config/automated/.opencode/skills/sce-validation/SKILL.md delete mode 100644 config/pkl/base/shared-content-automated-code.pkl delete mode 100644 config/pkl/base/shared-content-automated-commit.pkl delete mode 100644 config/pkl/base/shared-content-automated-common.pkl delete mode 100644 config/pkl/base/shared-content-automated-plan.pkl delete mode 100644 config/pkl/base/shared-content-automated.pkl delete mode 100644 config/pkl/base/shared-content-code.pkl delete mode 100644 config/pkl/base/shared-content-commit.pkl delete mode 100644 config/pkl/base/shared-content-common.pkl delete mode 100644 config/pkl/base/shared-content-plan.pkl delete mode 100644 config/pkl/base/shared-content.pkl create mode 100644 config/pkl/base/workflow-change-to-plan.pkl create mode 100644 config/pkl/base/workflow-content.pkl create mode 100644 config/pkl/base/workflow-context-sync.pkl create mode 100644 config/pkl/base/workflow-next-task.pkl create mode 100644 config/pkl/base/workflow-validate.pkl delete mode 100644 config/pkl/renderers/opencode-automated-content.pkl delete mode 100644 config/pkl/renderers/opencode-automated-metadata.pkl delete mode 100644 config/pkl/renderers/pi-metadata.pkl create mode 100644 context/decisions/2026-07-27-workflow-oriented-pkl-generation.md create mode 100644 context/plans/rebuild-pkl-workflow-markdown.md delete mode 100644 context/sce/atomic-commit-workflow.md delete mode 100644 context/sce/automated-profile-contract.md diff --git a/config/.claude/agents/shared-context-code.md b/config/.claude/agents/shared-context-code.md deleted file mode 100644 index b56786a0..00000000 --- a/config/.claude/agents/shared-context-code.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: shared-context-code -description: Use when the user wants to execute one approved SCE task and sync context. -model: inherit -color: green -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/config/.claude/agents/shared-context-plan.md b/config/.claude/agents/shared-context-plan.md deleted file mode 100644 index c81866e7..00000000 --- a/config/.claude/agents/shared-context-plan.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: shared-context-plan -description: Use when the user needs to create or update an SCE plan before implementation. -model: inherit -color: blue -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/config/.claude/commands/change-to-plan.md b/config/.claude/commands/change-to-plan.md index 310ebb5b..556c578e 100644 --- a/config/.claude/commands/change-to-plan.md +++ b/config/.claude/commands/change-to-plan.md @@ -1,17 +1,176 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.claude/commands/commit.md b/config/.claude/commands/commit.md deleted file mode 100644 index 1192e4f5..00000000 --- a/config/.claude/commands/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/config/.claude/commands/handover.md b/config/.claude/commands/handover.md deleted file mode 100644 index 0e91be08..00000000 --- a/config/.claude/commands/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/config/.claude/commands/next-task.md b/config/.claude/commands/next-task.md index b74c996a..a52e26ff 100644 --- a/config/.claude/commands/next-task.md +++ b/config/.claude/commands/next-task.md @@ -1,24 +1,192 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/config/.claude/commands/validate.md b/config/.claude/commands/validate.md index ece8cebc..bbaeca4f 100644 --- a/config/.claude/commands/validate.md +++ b/config/.claude/commands/validate.md @@ -1,15 +1,145 @@ --- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -Load and follow the `sce-validation` skill. +SCE VALIDATE `$ARGUMENTS` -Input: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/config/.claude/skills/sce-atomic-commit/SKILL.md b/config/.claude/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7a3cf4..00000000 --- a/config/.claude/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: claude ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/config/.claude/skills/sce-bootstrap-context/SKILL.md b/config/.claude/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 2981a743..00000000 --- a/config/.claude/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: claude ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/config/.claude/skills/sce-context-load/SKILL.md b/config/.claude/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..67e569b8 --- /dev/null +++ b/config/.claude/skills/sce-context-load/SKILL.md @@ -0,0 +1,129 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +compatibility: claude +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.claude/skills/sce-context-load/references/context-brief.yaml b/config/.claude/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/config/.claude/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/config/.claude/skills/sce-context-sync/SKILL.md b/config/.claude/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 199413fc..00000000 --- a/config/.claude/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: claude ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/config/.claude/skills/sce-handover-writer/SKILL.md b/config/.claude/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 07a14634..00000000 --- a/config/.claude/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: claude ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/config/.claude/skills/sce-plan-authoring/SKILL.md b/config/.claude/skills/sce-plan-authoring/SKILL.md index 3f1af5d9..1b34665e 100644 --- a/config/.claude/skills/sce-plan-authoring/SKILL.md +++ b/config/.claude/skills/sce-plan-authoring/SKILL.md @@ -1,89 +1,290 @@ --- name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. compatibility: claude --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/config/.claude/skills/sce-plan-authoring/references/plan-summary.md b/config/.claude/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/config/.claude/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/config/.claude/skills/sce-plan-authoring/references/plan-template.md b/config/.claude/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/config/.claude/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/config/.claude/skills/sce-plan-context-sync/SKILL.md b/config/.claude/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..96127523 --- /dev/null +++ b/config/.claude/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,309 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +compatibility: claude +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.claude/skills/sce-plan-context-sync/references/sync-report.md b/config/.claude/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/config/.claude/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/config/.claude/skills/sce-plan-review/SKILL.md b/config/.claude/skills/sce-plan-review/SKILL.md index 69cf6ba0..a55fee1d 100644 --- a/config/.claude/skills/sce-plan-review/SKILL.md +++ b/config/.claude/skills/sce-plan-review/SKILL.md @@ -1,91 +1,149 @@ --- name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. compatibility: claude --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml b/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/config/.claude/skills/sce-task-context-sync/SKILL.md b/config/.claude/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..437585c2 --- /dev/null +++ b/config/.claude/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,311 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +compatibility: claude +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.claude/skills/sce-task-context-sync/references/sync-report.md b/config/.claude/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..7d5acb94 --- /dev/null +++ b/config/.claude/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,133 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/config/.claude/skills/sce-task-execution/SKILL.md b/config/.claude/skills/sce-task-execution/SKILL.md index d90a14fb..da53bb98 100644 --- a/config/.claude/skills/sce-task-execution/SKILL.md +++ b/config/.claude/skills/sce-task-execution/SKILL.md @@ -1,58 +1,247 @@ --- name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. compatibility: claude --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/config/.claude/skills/sce-task-execution/references/execution-contract.yaml b/config/.claude/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/config/.claude/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.claude/skills/sce-task-execution/references/implementation-gate.md b/config/.claude/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/config/.claude/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/config/.claude/skills/sce-validation/SKILL.md b/config/.claude/skills/sce-validation/SKILL.md index 22068f7f..ddb04f99 100644 --- a/config/.claude/skills/sce-validation/SKILL.md +++ b/config/.claude/skills/sce-validation/SKILL.md @@ -1,47 +1,190 @@ --- name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. compatibility: claude --- -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/config/.claude/skills/sce-validation/references/validation-report.md b/config/.claude/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/config/.claude/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/config/.claude/skills/sce-validation/references/validation-result.md b/config/.claude/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/config/.claude/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. diff --git a/config/.opencode/agent/Shared Context Code.md b/config/.opencode/agent/Shared Context Code.md index d5edcd48..c88395a2 100644 --- a/config/.opencode/agent/Shared Context Code.md +++ b/config/.opencode/agent/Shared Context Code.md @@ -25,60 +25,9 @@ permission: "*": ask "sce-plan-review": allow "sce-task-execution": allow - "sce-context-sync": allow + "sce-task-context-sync": allow "sce-validation": allow - "sce-atomic-commit": allow + "sce-plan-context-sync": allow --- -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. +Route implementation work through `/next-task` and final plan validation through `/validate`. diff --git a/config/.opencode/agent/Shared Context Plan.md b/config/.opencode/agent/Shared Context Plan.md index 4499d961..23425736 100644 --- a/config/.opencode/agent/Shared Context Plan.md +++ b/config/.opencode/agent/Shared Context Plan.md @@ -23,65 +23,8 @@ permission: doom_loop: ask skill: "*": ask - "sce-bootstrap-context": allow + "sce-context-load": allow "sce-plan-authoring": allow --- -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. +Route plan creation and revision through `/change-to-plan`. diff --git a/config/.opencode/command/change-to-plan.md b/config/.opencode/command/change-to-plan.md index 1f2cd988..27cc07a2 100644 --- a/config/.opencode/command/change-to-plan.md +++ b/config/.opencode/command/change-to-plan.md @@ -1,20 +1,180 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" agent: "Shared Context Plan" -entry-skill: "sce-plan-authoring" +entry-skill: "sce-context-load" skills: + - "sce-context-load" - "sce-plan-authoring" --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.opencode/command/commit.md b/config/.opencode/command/commit.md deleted file mode 100644 index 384b7803..00000000 --- a/config/.opencode/command/commit.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -agent: "Shared Context Code" -entry-skill: "sce-atomic-commit" -skills: - - "sce-atomic-commit" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/config/.opencode/command/handover.md b/config/.opencode/command/handover.md deleted file mode 100644 index ce592cda..00000000 --- a/config/.opencode/command/handover.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -agent: "Shared Context Code" -entry-skill: "sce-handover-writer" -skills: - - "sce-handover-writer" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/config/.opencode/command/next-task.md b/config/.opencode/command/next-task.md index 71a1f974..9c2ff4e3 100644 --- a/config/.opencode/command/next-task.md +++ b/config/.opencode/command/next-task.md @@ -1,30 +1,197 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" agent: "Shared Context Code" entry-skill: "sce-plan-review" skills: - "sce-plan-review" - "sce-task-execution" - - "sce-context-sync" - - "sce-validation" + - "sce-task-context-sync" --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/config/.opencode/command/validate.md b/config/.opencode/command/validate.md index 3c128608..4b95c2ab 100644 --- a/config/.opencode/command/validate.md +++ b/config/.opencode/command/validate.md @@ -1,18 +1,149 @@ --- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +argument-hint: "" agent: "Shared Context Code" entry-skill: "sce-validation" skills: - "sce-validation" + - "sce-plan-context-sync" --- -Load and follow the `sce-validation` skill. +SCE VALIDATE `$ARGUMENTS` -Input: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/config/.opencode/skills/sce-atomic-commit/SKILL.md b/config/.opencode/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 50c63fe8..00000000 --- a/config/.opencode/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: opencode ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/config/.opencode/skills/sce-bootstrap-context/SKILL.md b/config/.opencode/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index c0193c49..00000000 --- a/config/.opencode/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: opencode ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/config/.opencode/skills/sce-context-load/SKILL.md b/config/.opencode/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..5e28b0ee --- /dev/null +++ b/config/.opencode/skills/sce-context-load/SKILL.md @@ -0,0 +1,129 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +compatibility: opencode +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.opencode/skills/sce-context-load/references/context-brief.yaml b/config/.opencode/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/config/.opencode/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/config/.opencode/skills/sce-context-sync/SKILL.md b/config/.opencode/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 16e27bf7..00000000 --- a/config/.opencode/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: opencode ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/config/.opencode/skills/sce-handover-writer/SKILL.md b/config/.opencode/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 43bb1238..00000000 --- a/config/.opencode/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: opencode ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/config/.opencode/skills/sce-plan-authoring/SKILL.md b/config/.opencode/skills/sce-plan-authoring/SKILL.md index 3632b0b8..fdc754a9 100644 --- a/config/.opencode/skills/sce-plan-authoring/SKILL.md +++ b/config/.opencode/skills/sce-plan-authoring/SKILL.md @@ -1,89 +1,290 @@ --- name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. compatibility: opencode --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md b/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/config/.opencode/skills/sce-plan-authoring/references/plan-template.md b/config/.opencode/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/config/.opencode/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/config/.opencode/skills/sce-plan-context-sync/SKILL.md b/config/.opencode/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..a59c57f8 --- /dev/null +++ b/config/.opencode/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,309 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +compatibility: opencode +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md b/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/config/.opencode/skills/sce-plan-review/SKILL.md b/config/.opencode/skills/sce-plan-review/SKILL.md index da87e50e..cb98f485 100644 --- a/config/.opencode/skills/sce-plan-review/SKILL.md +++ b/config/.opencode/skills/sce-plan-review/SKILL.md @@ -1,91 +1,149 @@ --- name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. compatibility: opencode --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml b/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/config/.opencode/skills/sce-task-context-sync/SKILL.md b/config/.opencode/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..3b3b5d80 --- /dev/null +++ b/config/.opencode/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,311 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +compatibility: opencode +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.opencode/skills/sce-task-context-sync/references/sync-report.md b/config/.opencode/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..7d5acb94 --- /dev/null +++ b/config/.opencode/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,133 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/config/.opencode/skills/sce-task-execution/SKILL.md b/config/.opencode/skills/sce-task-execution/SKILL.md index 2e13a754..267f608c 100644 --- a/config/.opencode/skills/sce-task-execution/SKILL.md +++ b/config/.opencode/skills/sce-task-execution/SKILL.md @@ -1,58 +1,247 @@ --- name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. compatibility: opencode --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml b/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.opencode/skills/sce-task-execution/references/implementation-gate.md b/config/.opencode/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/config/.opencode/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/config/.opencode/skills/sce-validation/SKILL.md b/config/.opencode/skills/sce-validation/SKILL.md index 9391ee6d..a2dc559d 100644 --- a/config/.opencode/skills/sce-validation/SKILL.md +++ b/config/.opencode/skills/sce-validation/SKILL.md @@ -1,47 +1,190 @@ --- name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. compatibility: opencode --- -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/config/.opencode/skills/sce-validation/references/validation-report.md b/config/.opencode/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/config/.opencode/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/config/.opencode/skills/sce-validation/references/validation-result.md b/config/.opencode/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/config/.opencode/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. diff --git a/config/.pi/prompts/agent-shared-context-code.md b/config/.pi/prompts/agent-shared-context-code.md deleted file mode 100644 index 9d3abdd5..00000000 --- a/config/.pi/prompts/agent-shared-context-code.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -description: "Act in the shared-context-code role to execute one approved SCE task and sync context." -argument-hint: " [T0X]" ---- - -Act as the Shared Context Code agent for the rest of this session. Load and follow the `sce-task-execution` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/config/.pi/prompts/agent-shared-context-plan.md b/config/.pi/prompts/agent-shared-context-plan.md deleted file mode 100644 index 5dbad4e1..00000000 --- a/config/.pi/prompts/agent-shared-context-plan.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -description: "Act in the shared-context-plan role to create or update an SCE plan before implementation." -argument-hint: "" ---- - -Act as the Shared Context Plan agent for the rest of this session. Load and follow the `sce-plan-authoring` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/config/.pi/prompts/change-to-plan.md b/config/.pi/prompts/change-to-plan.md index 8a782aea..9ee4f81f 100644 --- a/config/.pi/prompts/change-to-plan.md +++ b/config/.pi/prompts/change-to-plan.md @@ -1,17 +1,175 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.pi/prompts/commit.md b/config/.pi/prompts/commit.md deleted file mode 100644 index b868096a..00000000 --- a/config/.pi/prompts/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -argument-hint: "[oneshot|skip]" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/config/.pi/prompts/handover.md b/config/.pi/prompts/handover.md deleted file mode 100644 index af3666ff..00000000 --- a/config/.pi/prompts/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -argument-hint: "[task context]" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/config/.pi/prompts/next-task.md b/config/.pi/prompts/next-task.md index 3cfa8607..6859e4d4 100644 --- a/config/.pi/prompts/next-task.md +++ b/config/.pi/prompts/next-task.md @@ -1,24 +1,191 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -argument-hint: " [T0X]" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/config/.pi/prompts/validate.md b/config/.pi/prompts/validate.md index e2c32ffe..d35fb89c 100644 --- a/config/.pi/prompts/validate.md +++ b/config/.pi/prompts/validate.md @@ -1,15 +1,144 @@ --- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" argument-hint: "" --- -Load and follow the `sce-validation` skill. +SCE VALIDATE `$ARGUMENTS` -Input: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/config/.pi/skills/sce-atomic-commit/SKILL.md b/config/.pi/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7fe5bd..00000000 --- a/config/.pi/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: sce-atomic-commit -description: Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/config/.pi/skills/sce-bootstrap-context/SKILL.md b/config/.pi/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 69610b01..00000000 --- a/config/.pi/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: sce-bootstrap-context -description: Use when user wants to Bootstrap SCE baseline context directory when missing. ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/config/.pi/skills/sce-context-load/SKILL.md b/config/.pi/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..c944be76 --- /dev/null +++ b/config/.pi/skills/sce-context-load/SKILL.md @@ -0,0 +1,128 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.pi/skills/sce-context-load/references/context-brief.yaml b/config/.pi/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/config/.pi/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/config/.pi/skills/sce-context-sync/SKILL.md b/config/.pi/skills/sce-context-sync/SKILL.md deleted file mode 100644 index f051a981..00000000 --- a/config/.pi/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: sce-context-sync -description: Use when user wants to Synchronize context files to match current code behavior after task execution. ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/config/.pi/skills/sce-handover-writer/SKILL.md b/config/.pi/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 73292812..00000000 --- a/config/.pi/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: sce-handover-writer -description: Use when user wants to create a structured SCE handover for the current task. ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/config/.pi/skills/sce-plan-authoring/SKILL.md b/config/.pi/skills/sce-plan-authoring/SKILL.md index 02c177e4..946e686b 100644 --- a/config/.pi/skills/sce-plan-authoring/SKILL.md +++ b/config/.pi/skills/sce-plan-authoring/SKILL.md @@ -1,87 +1,289 @@ --- name: sce-plan-authoring -description: Use when user wants to Create or update an SCE implementation plan with scoped atomic tasks. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/config/.pi/skills/sce-plan-authoring/references/plan-summary.md b/config/.pi/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/config/.pi/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/config/.pi/skills/sce-plan-authoring/references/plan-template.md b/config/.pi/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/config/.pi/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/config/.pi/skills/sce-plan-context-sync/SKILL.md b/config/.pi/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..04958458 --- /dev/null +++ b/config/.pi/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,308 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.pi/skills/sce-plan-context-sync/references/sync-report.md b/config/.pi/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/config/.pi/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/config/.pi/skills/sce-plan-review/SKILL.md b/config/.pi/skills/sce-plan-review/SKILL.md index 471baf7b..77c36481 100644 --- a/config/.pi/skills/sce-plan-review/SKILL.md +++ b/config/.pi/skills/sce-plan-review/SKILL.md @@ -1,89 +1,148 @@ --- name: sce-plan-review -description: Use when user wants to review an existing plan and prepare the next task safely. +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml b/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/config/.pi/skills/sce-task-context-sync/SKILL.md b/config/.pi/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..7af7c880 --- /dev/null +++ b/config/.pi/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,310 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.pi/skills/sce-task-context-sync/references/sync-report.md b/config/.pi/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..7d5acb94 --- /dev/null +++ b/config/.pi/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,133 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/config/.pi/skills/sce-task-execution/SKILL.md b/config/.pi/skills/sce-task-execution/SKILL.md index 36a78e5b..3c8f7f70 100644 --- a/config/.pi/skills/sce-task-execution/SKILL.md +++ b/config/.pi/skills/sce-task-execution/SKILL.md @@ -1,56 +1,246 @@ --- name: sce-task-execution -description: Use when user wants to Execute one approved task with explicit scope, evidence, and status updates. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/config/.pi/skills/sce-task-execution/references/execution-contract.yaml b/config/.pi/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/config/.pi/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.pi/skills/sce-task-execution/references/implementation-gate.md b/config/.pi/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/config/.pi/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/config/.pi/skills/sce-validation/SKILL.md b/config/.pi/skills/sce-validation/SKILL.md index efb7a23e..2cd7557b 100644 --- a/config/.pi/skills/sce-validation/SKILL.md +++ b/config/.pi/skills/sce-validation/SKILL.md @@ -1,45 +1,189 @@ --- name: sce-validation -description: Use when user wants to Run final plan validation and cleanup with evidence capture. +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. --- -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/config/.pi/skills/sce-validation/references/validation-report.md b/config/.pi/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/config/.pi/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/config/.pi/skills/sce-validation/references/validation-result.md b/config/.pi/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/config/.pi/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. diff --git a/config/automated/.opencode/agent/Shared Context Code.md b/config/automated/.opencode/agent/Shared Context Code.md deleted file mode 100644 index ca4e6507..00000000 --- a/config/automated/.opencode/agent/Shared Context Code.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: "Shared Context Code" -description: Executes one approved SCE task, validates behavior, and syncs context. -temperature: 0.1 -color: "#059669" -permission: - default: allow - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: block - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: block - skill: - "*": allow - "sce-plan-review": allow - "sce-task-execution": allow - "sce-context-sync": allow - "sce-validation": allow - "sce-atomic-commit": allow ---- - -You are the Shared Context Code agent (automated profile). - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session. Multi-task execution is not supported in automated profile. -- Do not change plan structure or reorder tasks. -- If scope expansion is required, stop immediately with structured error. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Apply readiness confirmation gate: auto-pass only when both plan + task ID are provided and review reports no blockers/ambiguity/missing acceptance criteria; otherwise stop with structured error. -- After readiness check passes, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/config/automated/.opencode/agent/Shared Context Plan.md b/config/automated/.opencode/agent/Shared Context Plan.md deleted file mode 100644 index d0f8da85..00000000 --- a/config/automated/.opencode/agent/Shared Context Plan.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: "Shared Context Plan" -description: Plans a change into atomic tasks in context/plans without touching application code. -temperature: 0.1 -color: "#2563eb" -permission: - default: allow - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: block - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: block - skill: - "*": allow - "sce-bootstrap-context": allow - "sce-plan-authoring": allow ---- - -You are the Shared Context Plan agent (automated profile). - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, stop with error: "Automated profile requires existing context/. Run manual bootstrap first." -3) Do not auto-create context structure. -4) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -5) Before broad exploration, consult `context/context-map.md` for relevant context files. -6) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- If any critical detail is unclear (scope, success criteria, constraints, dependencies, domain ambiguity, architecture concerns, task ordering), stop with structured error listing all unresolved items with category labels. -- Do not invent assumptions silently. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/config/automated/.opencode/command/change-to-plan-interactive.md b/config/automated/.opencode/command/change-to-plan-interactive.md deleted file mode 100644 index bdcf851b..00000000 --- a/config/automated/.opencode/command/change-to-plan-interactive.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -description: "Create or update an SCE plan from a change request with interactive clarification" -agent: "Shared Context Plan" ---- - -Load and follow the `sce-plan-authoring-interactive` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; delegate clarification/ambiguity handling and plan-shape contracts to `sce-plan-authoring-interactive`. -- Ensure plan output follows one-task/one-atomic-commit slicing through `sce-plan-authoring-interactive` task-shape rules. -- Write/update `context/plans/{plan_name}.md`. -- Confirm plan creation with `{plan_name}` and exact path. -- Return the full ordered task list. -- Prompt user to start a new session to implement `T01` and provide `/next-task {plan_name} T01`. diff --git a/config/automated/.opencode/command/change-to-plan.md b/config/automated/.opencode/command/change-to-plan.md deleted file mode 100644 index 7f57c300..00000000 --- a/config/automated/.opencode/command/change-to-plan.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -agent: "Shared Context Plan" ---- - -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; delegate clarification/ambiguity handling and plan-shape contracts to `sce-plan-authoring`. -- If any critical detail is unclear, stop with structured error listing all unresolved items with category labels. -- Do not invent assumptions silently. -- Ensure plan output follows one-task/one-atomic-commit slicing through `sce-plan-authoring` task-shape rules. -- Write/update `context/plans/{plan_name}.md`. -- Confirm plan creation with `{plan_name}` and exact path. -- Return the full ordered task list. -- Prompt user to start a new session to implement `T01` and provide `/next-task {plan_name} T01`. diff --git a/config/automated/.opencode/command/commit.md b/config/automated/.opencode/command/commit.md deleted file mode 100644 index f2441091..00000000 --- a/config/automated/.opencode/command/commit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -agent: "Shared Context Code" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine the one commit message. -- Skip staging confirmation prompt. -- Validate staged content exists; if empty, stop with error: "No staged changes. Stage changes before commit." -- Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. -- Run `sce-atomic-commit` to produce exactly one commit message for the staged diff. -- Do not branch into multi-commit or split guidance. -- Use the resulting message to run `git commit` against the staged changes. -- If `git commit` fails, stop and report the failure without inventing fallback commits. diff --git a/config/automated/.opencode/command/handover.md b/config/automated/.opencode/command/handover.md deleted file mode 100644 index 554b9f2a..00000000 --- a/config/automated/.opencode/command/handover.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -agent: "Shared Context Code" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Create a new handover file in `context/handovers/` that captures: - -- current task state -- decisions made and rationale -- open questions or blockers -- next recommended step - -Default naming should align with task execution handovers: `context/handovers/{plan_name}-{task_id}-{timestamp}.md`. -If key details are missing, infer what you can from the current repo state and clearly label assumptions. diff --git a/config/automated/.opencode/command/next-task.md b/config/automated/.opencode/command/next-task.md deleted file mode 100644 index 9468144b..00000000 --- a/config/automated/.opencode/command/next-task.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -agent: "Shared Context Code" ---- - -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Run `sce-plan-review` first to resolve plan target/task and readiness. -- Apply readiness confirmation gate from `sce-plan-review`: - - auto-pass only when both plan + task ID are provided and review reports no blockers/ambiguity/missing acceptance criteria - - otherwise stop with structured error listing unresolved items -- Run `sce-task-execution`; keep mandatory implementation stop (auto-proceed with logging), scoped implementation, checks/lints/build, and plan status updates skill-owned. -- Run `sce-context-sync` as the required done gate. -- Wait for user feedback; if in-scope fixes are requested, apply fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this is the final plan task, run `sce-validation`. -- If more tasks remain, prompt a new session with `/next-task {plan_name} T0X`. diff --git a/config/automated/.opencode/command/validate.md b/config/automated/.opencode/command/validate.md deleted file mode 100644 index f70dbac6..00000000 --- a/config/automated/.opencode/command/validate.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" -agent: "Shared Context Code" ---- - -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Run full validation checks. -- Capture evidence. -- Report pass/fail and any residual risks. diff --git a/config/automated/.opencode/lib/bash-policy-presets.json b/config/automated/.opencode/lib/bash-policy-presets.json deleted file mode 100644 index 88afd047..00000000 --- a/config/automated/.opencode/lib/bash-policy-presets.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "schema_version": 1, - "presets": [ - { - "id": "forbid-git-all", - "match": { - "argv_prefixes": [ - [ - "git" - ] - ] - }, - "message": "This repository blocks `git` via SCE bash-tool policy. Explain to user that they should run `git` commands themselves." - }, - { - "id": "forbid-git-commit", - "match": { - "argv_prefixes": [ - [ - "git", - "add" - ], - [ - "git", - "commit" - ], - [ - "git", - "push" - ] - ] - }, - "message": "This repository blocks direct `git add`, `git commit`, and `git push`. Explain to user that they should run `git` commands themselves." - }, - { - "id": "use-pnpm-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `pnpm` over `npm`. Use `pnpm` instead." - }, - { - "id": "use-bun-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `bun` over `npm`. Use `bun` instead." - }, - { - "id": "use-nix-flake-over-cargo", - "match": { - "argv_prefixes": [ - [ - "cargo" - ] - ] - }, - "message": "This repository prefers Nix flake entrypoints over direct `cargo` commands. Run Cargo through the documented `nix develop` / flake workflows instead." - } - ], - "mutually_exclusive": [ - [ - "use-pnpm-over-npm", - "use-bun-over-npm" - ] - ], - "redundancy_warnings": [ - { - "if_enabled": [ - "forbid-git-all", - "forbid-git-commit" - ], - "warning": "Preset 'forbid-git-commit' is redundant when 'forbid-git-all' is also enabled." - } - ] -} diff --git a/config/automated/.opencode/opencode.json b/config/automated/.opencode/opencode.json deleted file mode 100644 index dbd5d890..00000000 --- a/config/automated/.opencode/opencode.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "plugin": [ - "./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts" - ] -} \ No newline at end of file diff --git a/config/automated/.opencode/plugins/sce-agent-trace.ts b/config/automated/.opencode/plugins/sce-agent-trace.ts deleted file mode 100644 index 980ceb06..00000000 --- a/config/automated/.opencode/plugins/sce-agent-trace.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { spawn } from "node:child_process"; -import type { Hooks, Plugin } from "@opencode-ai/plugin"; - -type OpenCodeEvent = Parameters>[0]["event"]; - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -const REQUIRED_EVENTS: Set = new Set([ - "message.updated", - "message.part.updated", - "session.created", - "session.updated", -]); - -const ALL_CAPTURED_EVENTS = REQUIRED_EVENTS; - -type TraceInput = { - event?: OpenCodeEvent; -}; - -type DiffTracePayload = { - sessionID: string; - diff: string; - time: number; - model_id: string; -}; - -type ConversationTraceMessageUpdatedItem = { - type: "message"; - session_id: string; - message_id: string; - role: EventMessageUpdated["properties"]["info"]["role"]; - generated_at_unix_ms: number; -}; - -type ConversationTraceMessagePartUpdatedItem = { - type: "message.part"; - session_id: string; - message_id: string; - part_type: "text" | "reasoning" | "patch" | "question"; - text: unknown; - generated_at_unix_ms: number; -}; - -type ConversationTraceItem = - | ConversationTraceMessageUpdatedItem - | ConversationTraceMessagePartUpdatedItem; - -type ConversationTracePayload = { - payloads: ConversationTraceItem[]; -}; - -type QuestionToolAnswer = { - question: string; - answer: string; -}; - -const QUESTION_TOOL_ANSWER_SEPARATOR = ", "; - -type EventMessageUpdated = Extract< - NonNullable, - { type: "message.updated" } ->; - -type EventMessagePartUpdated = Extract< - NonNullable, - { type: "message.part.updated" } ->; - -type EventMessagePart = EventMessagePartUpdated["properties"]["part"]; -type EventMessageToolPart = Extract; -type EventAllowedPart = - | Extract - | Extract; - -function extractDiffEntries( - eventInfo: EventMessageUpdated["properties"]["info"], -) { - if (typeof eventInfo.summary === "object") { - return eventInfo.summary.diffs; - } - return undefined; -} - -function extractDiffTracePayload( - event: EventMessageUpdated, -): DiffTracePayload | undefined { - const eventInfo = event.properties.info; - // Only capture user messages (filter out assistant, system, etc.) - if (eventInfo.role !== "user") { - return undefined; - } - - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patches: string[] = []; - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - patches.push(entry.patch); - } - } - - if (patches.length === 0) { - return undefined; - } - - return { - sessionID: eventInfo.sessionID, - diff: patches.join("\n"), - time: Date.now(), - model_id: `${eventInfo.model.providerID}/${eventInfo.model.modelID}`, - }; -} - -function shouldCaptureEvent(eventType: OpenCodeEvent["type"]): boolean { - return ALL_CAPTURED_EVENTS.has(eventType); -} - -function extractQuestionToolAnswers( - eventPart: EventMessageToolPart, -): QuestionToolAnswer[] | undefined { - const state = eventPart.state; - - if (state.status !== "completed") { - return undefined; - } - - const questions = - "questions" in state.input && Array.isArray(state.input.questions) - ? state.input.questions - : []; - const answers = - "answers" in state.metadata && Array.isArray(state.metadata.answers) - ? state.metadata.answers - : []; - - if (questions.length === 0 || questions.length !== answers.length) { - return undefined; - } - - const result: QuestionToolAnswer[] = []; - - questions.forEach((q, index) => { - const question = - "question" in q && typeof q.question === "string" ? q.question : ""; - if (question) { - const answer = Array.isArray(answers[index]) ? answers[index] : []; - result.push({ - question, - answer: answer.join(QUESTION_TOOL_ANSWER_SEPARATOR), - }); - } - }); - - return result; -} - -function buildConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload { - const eventInfo = event.properties.info; - - return { - payloads: [ - { - type: "message", - session_id: eventInfo.sessionID, - message_id: eventInfo.id, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -export function buildMessagePartConversationTracePayload( - eventPart: EventAllowedPart, -): ConversationTracePayload { - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: eventPart.type, - text: "text" in eventPart ? eventPart.text : "", - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildQuestionToolConversationTracePayload( - eventPart: EventMessageToolPart, -): ConversationTracePayload | undefined { - const pairedAnswers = extractQuestionToolAnswers(eventPart); - - if (pairedAnswers === undefined) { - return undefined; - } - - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: "question", - text: JSON.stringify(pairedAnswers), - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildPatchConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload | undefined { - const eventInfo = event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patchMessageId = `${eventInfo.id}-patch`; - const payloads: ConversationTraceItem[] = []; - - payloads.push({ - type: "message", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }); - - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - payloads.push({ - type: "message.part", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - part_type: "patch", - text: entry.patch, - generated_at_unix_ms: Date.now(), - }); - } - } - - return { payloads }; -} - -export async function recordConversationTrace( - repoRoot: string, - event: EventMessageUpdated | EventMessagePartUpdated, -): Promise { - if ( - event.type === "message.part.updated" && - event.properties.part.type === "tool" && - event.properties.part.tool === "question" - ) { - const questionToolPayload = buildQuestionToolConversationTracePayload( - event.properties.part, - ); - if (questionToolPayload !== undefined) { - await runConversationTraceHook(repoRoot, questionToolPayload); - return; - } - } - - if ( - event.type === "message.part.updated" && - (event.properties.part.type === "reasoning" || - event.properties.part.type === "text") && - event.properties.part.text - ) { - await runConversationTraceHook( - repoRoot, - buildMessagePartConversationTracePayload(event.properties.part), - ); - return; - } - - if (event.type === "message.updated") { - const patchPayload = buildPatchConversationTracePayload(event); - - if (patchPayload !== undefined) { - await runConversationTraceHook(repoRoot, patchPayload); - return; - } - - await runConversationTraceHook( - repoRoot, - buildConversationTracePayload(event), - ); - } -} - -async function buildTrace( - repoRoot: string, - event: EventMessageUpdated, - clientVersion: string | null, -): Promise { - const diffTracePayload = extractDiffTracePayload(event); - - if (diffTracePayload === undefined) { - return; - } - - await runDiffTraceHook(repoRoot, { - ...diffTracePayload, - tool_name: "opencode", - tool_version: clientVersion, - }); -} - -async function runDiffTraceHook( - repoRoot: string, - payload: DiffTracePayload & { - tool_name: string; - tool_version: string | null; - }, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "diff-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -async function runConversationTraceHook( - repoRoot: string, - payload: ConversationTracePayload, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "conversation-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -export const SceAgentTracePlugin: Plugin = async ({ directory, worktree }) => { - const repoRoot = worktree ?? directory ?? process.cwd(); - const clientVersionsBySessionId: Map = new Map(); - const processedDiffsMessageIds: Set = new Set(); - - return { - event: async (input) => { - if (!shouldCaptureEvent(input.event.type)) { - return; - } - - if ( - input.event.type === "session.created" || - input.event.type === "session.updated" - ) { - clientVersionsBySessionId.set( - input.event.properties.info.id, - input.event.properties.info.version, - ); - } - - if (input.event.type === "message.updated") { - const eventInfo = input.event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - const hasDiffs = diffEntries !== undefined && diffEntries.length > 0; - - if (hasDiffs) { - const dedupKey = `${eventInfo.sessionID}:${eventInfo.id}`; - if (processedDiffsMessageIds.has(dedupKey)) { - return; - } - processedDiffsMessageIds.add(dedupKey); - } - - const clientVersion = - clientVersionsBySessionId.get( - input.event.properties.info.sessionID, - ) || null; - await recordConversationTrace(repoRoot, input.event); - await buildTrace(repoRoot, input.event, clientVersion); - } - - if (input.event.type === "message.part.updated") { - await recordConversationTrace(repoRoot, input.event); - } - }, - }; -}; diff --git a/config/automated/.opencode/plugins/sce-bash-policy.ts b/config/automated/.opencode/plugins/sce-bash-policy.ts deleted file mode 100644 index 0b2b8d9c..00000000 --- a/config/automated/.opencode/plugins/sce-bash-policy.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { spawnSync } from "node:child_process"; -import type { Plugin } from "@opencode-ai/plugin"; - -interface JsonPolicyResult { - status: string; - decision: string; - command: string; - normalized_argv?: string[]; - reason?: string; - policy_id?: string; -} - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -/** - * Evaluate a bash command against SCE bash-tool policy by delegating to the - * Rust `sce policy bash` command. Returns the parsed JSON result, or null if - * the policy check could not be performed (fail-open). - */ -function evaluateBashCommandPolicy(command: string): JsonPolicyResult | null { - try { - const result = spawnSync( - "sce", - ["policy", "bash", "--input", "normalized", "--output", "json"], - { - input: JSON.stringify({ command }), - encoding: "utf8", - timeout: 10_000, - }, - ); - - if (result.error) { - if ((result.error as NodeJS.ErrnoException).code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - return null; - } - - if (result.status !== 0) { - return null; - } - - const stdout = result.stdout?.trim(); - if (!stdout) { - return null; - } - - const parsed: JsonPolicyResult = JSON.parse(stdout); - return parsed; - } catch { - return null; - } -} - -export const SceBashPolicyPlugin: Plugin = async () => { - return { - "tool.execute.before": async (input, output) => { - if (input.tool !== "bash") { - return; - } - - const args = output?.args; - if (args === undefined || args === null) { - return; - } - - const command = (args as { command?: unknown }).command; - if (typeof command !== "string" || command.length === 0) { - return; - } - - const policyResult = evaluateBashCommandPolicy(command); - if (!policyResult) { - // Fail open: if the policy check cannot be performed, allow the command. - return; - } - - if (policyResult.decision === "deny" && policyResult.reason) { - throw new Error(policyResult.reason); - } - }, - }; -}; diff --git a/config/automated/.opencode/skills/sce-atomic-commit/SKILL.md b/config/automated/.opencode/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index f8e18797..00000000 --- a/config/automated/.opencode/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: opencode ---- - -## Goal - -Turn the current staged changes into one straightforward repository-style commit message. - -For this workflow: -- produce exactly one commit message -- keep the message focused on the staged change as a single coherent unit -- do not default to multi-commit split planning - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce one commit message that follows: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, the commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Procedure - -1) Review the staged change as one unit -- Infer the main reason for the staged change from the staged diff first. -- Use optional notes only to refine wording, not to override the staged truth. - -2) Choose scope -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) Apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) Validate the single-message result -- The message should describe the staged diff faithfully as one coherent change. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file Guidance gating - -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits diff --git a/config/automated/.opencode/skills/sce-bootstrap-context/SKILL.md b/config/automated/.opencode/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 8cebf7fa..00000000 --- a/config/automated/.opencode/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Use when user wants to Bootstrap SCE baseline context directory when missing. -compatibility: opencode ---- - -## When to use -- Use only when `context/` is missing. -- Automated profile does not support auto-bootstrap; stop with error requiring manual bootstrap. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/config/automated/.opencode/skills/sce-context-sync/SKILL.md b/config/automated/.opencode/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 16e27bf7..00000000 --- a/config/automated/.opencode/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: opencode ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/config/automated/.opencode/skills/sce-handover-writer/SKILL.md b/config/automated/.opencode/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 43bb1238..00000000 --- a/config/automated/.opencode/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: opencode ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/config/automated/.opencode/skills/sce-plan-authoring-interactive/SKILL.md b/config/automated/.opencode/skills/sce-plan-authoring-interactive/SKILL.md deleted file mode 100644 index fcc75b13..00000000 --- a/config/automated/.opencode/skills/sce-plan-authoring-interactive/SKILL.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -name: sce-plan-authoring-interactive -description: | - Use when a user wants to create or update a Shared Context Engineering (SCE) implementation plan with interactive clarification. Triggers on requests like "write a plan", "create an implementation roadmap", "draft a rollout plan", "plan this change", or "break this into tasks" for a software change. Interactively resolves ambiguity by asking targeted clarifying questions, then produces a structured markdown plan under `context/plans/` with a change summary, success criteria, constraints, atomic task stack, and verification steps — ready to hand off to the Shared Context Code agent for execution. -compatibility: opencode ---- - -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -### Clarification gate example - -**User request:** "Add rate limiting to the API." - -**Clarification questions asked before writing the plan:** -1. Which endpoints should be rate-limited - all public routes, authenticated routes only, or specific ones? -2. What are the limits (e.g., requests per minute per IP/token) and what should happen when a limit is exceeded (429 response, queue, or silent drop)? -3. Should this use an existing library (e.g., `express-rate-limit`) or is a custom middleware preferred? - -*(Planning is blocked until the user answers all three.)* - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Use this quick atomicity check before accepting each task: -- `single_intent`: task delivers one primary outcome -- `single_area`: task touch scope is narrow and related -- `single_verification`: done checks validate one coherent change set - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - ---- - -## Complete plan example - -The following shows what a finished plan file looks like for a realistic request: *"Add per-user rate limiting to the REST API using `express-rate-limit`."* - -**File:** `context/plans/api-rate-limiting.md` - -```markdown -# Plan: api-rate-limiting - -## Change summary -Add per-user rate limiting to all authenticated REST API endpoints using the -`express-rate-limit` library. Unauthenticated endpoints are out of scope. - -## Success criteria -- Authenticated requests exceeding 100 req/min per token receive a 429 response - with a `Retry-After` header. -- All existing authenticated-endpoint tests continue to pass. -- A new integration test confirms the 429 path is exercised. - -## Constraints and non-goals -- **In scope:** authenticated routes under `/api/v1/` -- **Out of scope:** unauthenticated routes, IP-based limiting, admin bypass logic -- **Constraint:** must use `express-rate-limit ^7`; no custom Redis store in this change -- **Non-goal:** dashboarding or alerting on rate-limit events - -## Task stack - -- [ ] T01: Install and configure `express-rate-limit` middleware (status:todo) - - Task ID: T01 - - Goal: Add `express-rate-limit` as a dependency and wire a per-token limiter - into the authenticated router. - - Boundaries (in/out of scope): `src/middleware/rateLimiter.ts` and - `src/router/authenticated.ts` only; no changes to unauthenticated routes. - - Done when: Middleware is applied to the authenticated router and the dev - server starts without errors. - - Verification notes: `npm install` succeeds; `npm run dev` starts; manual - `curl` with a valid token returns 200. - -- [ ] T02: Return correct 429 response with `Retry-After` header (status:todo) - - Task ID: T02 - - Goal: Configure the limiter to respond with HTTP 429 and a `Retry-After` - header when the per-token limit is exceeded. - - Boundaries (in/out of scope): `src/middleware/rateLimiter.ts` handler only; - no route logic changes. - - Done when: Exceeding the limit returns `{ "error": "Too Many Requests" }` - with status 429 and a `Retry-After` value in seconds. - - Verification notes: `npm run test -- --grep "rate limit"` passes; manual - burst test with `artillery` confirms 429 after 100 req/min. - -- [ ] T03: Add integration test for the 429 path (status:todo) - - Task ID: T03 - - Goal: Write one integration test that fires 101 requests and asserts the - 101st receives 429 with `Retry-After`. - - Boundaries (in/out of scope): `tests/integration/rateLimiter.test.ts` only; - no changes to existing test files. - - Done when: New test file exists and `npm run test:integration` is green. - - Verification notes: `npm run test:integration` exits 0; coverage report - shows the 429 branch covered. - -- [ ] T04: Validation and cleanup (status:todo) - - Task ID: T04 - - Goal: Confirm full test suite passes, no regressions, and context files are - in sync. - - Boundaries (in/out of scope): Read-only audit of test results and context - directory; no new code changes. - - Done when: `npm test` exits 0; `context/` reflects the completed plan state. - - Verification notes: `npm test && npm run lint`; verify - `context/plans/api-rate-limiting.md` task statuses are all `done`. - -## Open questions -_(none - all clarifications resolved before planning)_ -``` diff --git a/config/automated/.opencode/skills/sce-plan-authoring/SKILL.md b/config/automated/.opencode/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 482b7f25..00000000 --- a/config/automated/.opencode/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -name: sce-plan-authoring -description: | - Transforms a change request into a structured implementation plan saved under context/plans/, breaking work down into atomic, commit-sized tasks with clear goals, scope boundaries, acceptance criteria, and verification steps. Use when a user wants to create or update a project plan, task breakdown, implementation roadmap, or work plan — including requests like "plan this feature", "break this into tasks", "write an implementation plan", or "scope out this change". Handles ambiguity resolution through a blocking clarification gate before writing any plan, and produces a machine-friendly task list ready for handoff to the Shared Context Engineering (SCE) implementation agent. -compatibility: opencode ---- - -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, stop with structured error listing all unresolved items with category labels. -- Do not write or update `context/plans/{plan_name}.md` until all critical details are resolved. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate resolved details into the plan before handoff. - -**Example structured error (clarification gate triggered):** -``` -PLANNING BLOCKED - unresolved critical details: - -[scope] Is the auth middleware change limited to the API gateway, or does it also cover the admin panel? -[dependency] Should the new Redis client use the existing `ioredis` version (4.x) or upgrade to 5.x? -[criteria] What does "performance acceptable" mean? Specific p95 threshold required. - -Resolve all items above before planning can proceed. -``` - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Assumptions (if any) -5) Task stack (`T01..T0N`) -6) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Use this quick atomicity check before accepting each task: -- `single_intent`: task delivers one primary outcome -- `single_area`: task touch scope is narrow and related -- `single_verification`: done checks validate one coherent change set - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Worked example - -**Input change request:** -> "Add rate limiting to the public API so that unauthenticated requests are capped at 60 req/min per IP. Use Redis for the counter store. No changes to authenticated routes." - -**Output plan (`context/plans/rate-limiting-public-api.md`):** - -```markdown -# Plan: rate-limiting-public-api - -## Change summary -Introduce per-IP rate limiting (60 req/min) for unauthenticated requests to the public API using a Redis-backed counter. Authenticated routes are out of scope. - -## Success criteria -- Unauthenticated requests exceeding 60/min from a single IP receive HTTP 429. -- Authenticated requests are unaffected. -- Rate limit headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) are present on all public responses. - -## Constraints and non-goals -- Out of scope: authenticated route limiting, user-level quotas, Redis cluster setup. -- Must not increase p95 latency on public endpoints by more than 5 ms. - -## Task stack - -- [ ] T01: Add Redis rate-limit middleware for unauthenticated routes (status:todo) - - Task ID: T01 - - Goal: Implement middleware that increments a Redis counter keyed by IP and returns 429 when the limit is exceeded. - - Boundaries in scope: middleware module, unauthenticated route registration. - - Boundaries out of scope: authenticated routes, Redis connection config (use existing client). - - Done when: Middleware rejects the 61st request in a 60 s window with HTTP 429; requests 1-60 pass through. - - Verification notes: `npm test src/middleware/rateLimiter.test.ts`; manual smoke test with `wrk -d 65s -c 1 http://localhost:3000/api/public`. - -- [ ] T02: Expose rate limit response headers (status:todo) - - Task ID: T02 - - Goal: Attach `X-RateLimit-*` headers to every response from the rate-limited middleware. - - Boundaries in scope: header injection in the middleware added in T01. - - Boundaries out of scope: changing status codes, logging, or metrics. - - Done when: All public API responses include the three headers with correct values. - - Verification notes: `curl -I http://localhost:3000/api/public/health` shows all three headers. - -- [ ] T03: Validate, measure latency, and sync context (status:todo) - - Task ID: T03 - - Goal: Run full test suite, confirm no regression on authenticated routes, verify latency budget, update context docs. - - Boundaries in scope: integration tests, latency benchmarks, context/plans status update. - - Boundaries out of scope: new feature work. - - Done when: All tests green; p95 latency delta < 5 ms; plan marked complete. - - Verification notes: `npm test`; `npm run bench:public`; review `context/plans/rate-limiting-public-api.md` checkboxes. -``` - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. diff --git a/config/automated/.opencode/skills/sce-plan-review/SKILL.md b/config/automated/.opencode/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 18b569c9..00000000 --- a/config/automated/.opencode/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -name: sce-plan-review -description: | - Use when the user wants to continue, resume, or pick up the next step from a markdown plan file stored in `context/plans/`. Reads the selected plan file, identifies the first unchecked checkbox as the next task, validates that acceptance criteria are clear and blockers are resolved, then issues an explicit readiness verdict before proceeding to implementation. Use when the user says "continue the plan", "what's the next task", "resume work", "pick up where we left off", or references a specific plan file. -compatibility: opencode ---- - -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Stop with structured error for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, stop with error: "Automated profile requires existing context/. Run manual bootstrap first." -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If no plan path specified and multiple plans exist, stop with error listing available plans and requiring explicit plan path. - - If no plan path specified and single plan exists, auto-select the single plan. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- If any blockers, ambiguity, or missing acceptance criteria exist, stop with structured error listing all unresolved items with category labels. -- Confirm scope explicitly for this session: one task only (multi-task execution not supported in automated profile). - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until all issues are resolved. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output -Emit a readiness verdict using this structure: - -``` -next_task: "Task title or description from plan" -acceptance_criteria: - - Criterion A - - Criterion B -ready_for_implementation: yes | no -``` - -If `ready_for_implementation: no`, include an issues block: - -``` -issues: - blockers: - - "Dependency on X is unresolved" - ambiguity: - - "It is unclear whether Y should be replaced or extended" - missing_acceptance_criteria: - - "No definition of done for the migration step" -``` - -- Auto-proceed to implementation when `ready_for_implementation: yes`. - -## Structured error examples - -**Multiple plans found (no path specified):** -``` -ERROR: Multiple plans found. Specify an explicit plan path. -Available plans: - - context/plans/migrate-auth.md - - context/plans/refactor-api.md -``` - -**Blockers or ambiguity detected:** -``` -ERROR: Next task cannot proceed. Unresolved items: - [blocker] Auth service interface not yet defined - task depends on it. - [ambiguity] "Update schema" - unclear whether additive or destructive migration. - [missing_acceptance_criteria] No rollback criteria specified for the deployment step. -Resolve all items above before re-running plan review. -``` diff --git a/config/automated/.opencode/skills/sce-task-execution/SKILL.md b/config/automated/.opencode/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 5c8aa4dd..00000000 --- a/config/automated/.opencode/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: sce-task-execution -description: | - Executes a single scoped coding task with structured implementation logging, test and lint evidence capture, and plan status updates. Use when the user wants to run, implement, or complete one approved task from a plan — such as writing code changes, applying fixes, or executing a defined unit of work — while enforcing strict single-task scope boundaries, logging intent to context/tmp/automated-session-log.md, and updating task status in context/plans/{plan_id}.md. Triggers on phrases like "execute task", "run this task", "implement task", "do the next task", or "apply this change". -compatibility: opencode ---- - -## Scope rule -- Execute exactly one task per session. -- Multi-task execution is not supported in automated profile; if requested, stop with error: "Automated profile does not support multi-task execution. Use single-task handoffs." - -## Mandatory implementation stop (auto-proceed with logging) -- Before writing or modifying any code, log implementation intent to `context/tmp/automated-session-log.md`. -- The log must include: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Proceed without waiting for confirmation. -- Preserve all safety constraints (one-task, no scope expansion, no plan reordering). - -## Log format -``` -## [timestamp] T0X: {task_title} -- Goal: {goal} -- In scope: {in_scope} -- Out of scope: {out_of_scope} -- Expected files: {file_list} -- Approach: {approach_summary} -- Status: proceeding -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Log implementation intent and proceed without waiting for confirmation. -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -## Scope expansion rule -- If out-of-scope edits are needed, stop immediately with structured error: `BLOCKER: scope_expansion_required`. -- List specific out-of-scope items detected. -- Require human session to approve scope change or split task. diff --git a/config/automated/.opencode/skills/sce-validation/SKILL.md b/config/automated/.opencode/skills/sce-validation/SKILL.md deleted file mode 100644 index 9391ee6d..00000000 --- a/config/automated/.opencode/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. -compatibility: opencode ---- - -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` diff --git a/config/pkl/README.md b/config/pkl/README.md index b7f81de1..d0cb66cd 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -1,84 +1,105 @@ # Pkl Generation Workflow -Canonical generation pipeline for authored configuration content. +Canonical generation pipeline for the three SCE workflows across OpenCode, Claude, and Pi. ---- +## Ownership and target matrix -## Understand ownership +Author workflow behavior in: -Generated by `config/pkl/generate.pkl`: +- `config/pkl/base/workflow-change-to-plan.pkl` +- `config/pkl/base/workflow-next-task.pkl` +- `config/pkl/base/workflow-validate.pkl` +- `config/pkl/base/workflow-content.pkl` for command and self-contained skill-package types +- `config/pkl/base/workflow-context-sync.pkl` for the shared task/plan synchronization skeleton -**Manual profile** (interactive approval gates): `config/.opencode/agent/*.md`, `config/.opencode/command/*.md`, `config/.opencode/skills/*/SKILL.md`, `config/.opencode/lib/*` shared runtime assets, and `config/.opencode/opencode.json` including generated SCE plugin registration. +Apply target-specific rendering and supported metadata under `config/pkl/renderers/`. Do not hand-edit generated artifacts. -**Automated profile** (non-interactive deterministic behavior): `config/automated/.opencode/agent/*.md`, `config/automated/.opencode/command/*.md`, `config/automated/.opencode/skills/*/SKILL.md`, `config/automated/.opencode/lib/*` shared runtime assets, and `config/automated/.opencode/opencode.json` including generated SCE plugin registration. +`config/pkl/generate.pkl` emits: -**Claude profile**: `config/.claude/agents/*.md`, `config/.claude/commands/*.md`, `config/.claude/skills/*/SKILL.md`, `config/.claude/lib/*` shared runtime assets, generated hooks under `config/.claude/hooks/*`, and generated settings at `config/.claude/settings.json`. +| Target | Workflow Markdown | Retained non-Markdown | +| --- | --- | --- | +| OpenCode | Three commands, seven self-contained skill packages, two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | +| Claude | Three commands and seven self-contained skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | +| Pi | Three prompts and seven self-contained skill packages; no agent-role prompts | `extensions/sce/index.ts` | +| SCE config | None | `config/schema/sce-config.schema.json` | -**Pi profile**: `config/.pi/prompts/*.md` command prompt templates, `config/.pi/prompts/agent-*.md` SCE agent-role prompt templates, `config/.pi/skills/*/SKILL.md` Agent Skills-format skill packages, and the project-local extension at `config/.pi/extensions/sce/index.ts`. Pi is manual-profile only and has no generated settings/plugin manifest; the extension is auto-discovered by Pi and emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`. +Each skill package includes its package-local `SKILL.md` and any nested `references/` documents. Generated skill trees must remain self-contained; a generated skill must not depend on a sibling skill package. -Generated Markdown outputs render deterministic frontmatter + body without injected warning marker comments. Generated JavaScript library outputs render without a leading generated warning header. +The automated OpenCode profile, generated `/commit` and `/handover` commands, legacy bootstrap/commit/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. -Edit the canonical Pkl sources when generated config changes are needed: base modules under `config/pkl/base/`, renderer modules under `config/pkl/renderers/`, and `config/pkl/generate.pkl`. Do not hand-edit generated artifacts. +Not generated by this pipeline: dependency artifacts such as `node_modules`, lockfiles, install outputs, and manifests outside the paths above. -Not generated by this pipeline: dependency artifacts (for example `node_modules`), lockfiles and install outputs, and manifests outside generated-owned paths. +## Prerequisites ---- +Run commands from the repository root with Nix flakes enabled. Use the Nix dev shell so no host-level Pkl installation is required. -## Choose a profile +## Evaluate and generate -This repository maintains two OpenCode configuration profiles plus single generated target trees for Claude Code and Pi: +Validate the target inventory and nested package documents: -**Manual profile** (`config/.opencode/**`): Interactive SCE workflows with human approval gates. Preserves ask/confirm prompts for safety-critical decisions. +```bash +nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl +``` -**Automated profile** (`config/automated/.opencode/**`): Non-interactive SCE workflows for CI/automation. Replaces interactive gates with deterministic policies (see `context/sce/automated-profile-contract.md`). +Validate the generator entrypoint: -Both OpenCode profiles are generated together by `config/pkl/generate.pkl` and must stay in sync with their canonical sources. The same generator also emits the Claude target tree and the Pi target tree (`config/.pi/**`) from shared canonical content with target-specific renderer metadata. +```bash +nix develop -c pkl eval config/pkl/generate.pkl +``` ---- +Preview generation without touching committed outputs: -## Prepare prerequisites +```bash +nix develop -c pkl eval -m context/tmp/pkl-generated config/pkl/generate.pkl +``` -Nix with flakes enabled is required. Repository root must be the current working directory. +Regenerate tracked outputs in place: -All commands use the Nix dev shell so no host-level Pkl install is required. +```bash +nix develop -c pkl eval -m . config/pkl/generate.pkl +``` ---- +Inspect the target trees: -## Run commands +```bash +git status --short config/.opencode config/.claude config/.pi config/schema/sce-config.schema.json +``` -Validate the generator entrypoint evaluates with nix develop -c pkl eval config/pkl/generate.pkl. +## Verify parity -Preview non-destructively (writes under `context/tmp/` only) with nix develop -c pkl eval -m context/tmp/pkl-generated config/pkl/generate.pkl. +Run the focused generated-output check: -Regenerate tracked outputs in place with nix develop -c pkl eval -m . config/pkl/generate.pkl. This regenerates both manual and automated OpenCode profiles plus Claude and Pi outputs, including `config/.opencode/opencode.json`, `config/automated/.opencode/opencode.json`, `config/.claude/hooks/*`, `config/.claude/settings.json`, `config/.pi/{prompts,skills}/**`, and `config/.pi/extensions/sce/index.ts`. +```bash +nix run .#pkl-check-generated +``` -Inspect resulting changes with git status --short config/.opencode config/automated/.opencode config/.claude config/.pi. This includes the generated Claude hook/settings outputs and Pi prompt/skill/extension outputs. If regeneration is deterministic and current, there should be no diff after a clean re-run. +The check: -Run the Nix dev-shell integration stale-output test with nix develop -c ./config/pkl/check-generated.sh. This test intentionally exits non-zero when run outside `nix develop`. +- evaluates `metadata-coverage-check.pkl` for the exact three-command, seven-skill-package, nested-reference, and two-agent OpenCode inventory; +- regenerates into a temporary directory; +- compares complete OpenCode, Claude, and Pi generated directories, so extra, missing, or changed nested files fail parity; +- compares retained scalar outputs and the generated SCE config schema; +- rejects removed whole-tree outputs such as `config/automated/.opencode` and `config/.claude/agents`. -> **Coupling note:** `config/pkl/check-generated.sh` must be kept in sync with `config/pkl/generate.pkl`. Whenever `generate.pkl` gains or loses outputs, update the `paths` array in `check-generated.sh` to match so parity checks remain accurate. - -GitHub CI enforces the same parity contract through `.github/workflows/pr-ci.yml`, which runs `nix flake check` (including the `pkl-parity` derivation). For a focused local check without the full flake suite, use `nix run .#pkl-check-generated`. - ---- +`nix flake check` runs the same contract through the `pkl-parity` derivation. Keep `config/pkl/check-generated.sh`, the `pklParitySrc` fileset, and the `pklParityCheck` path lists in `flake.nix` aligned with `config/pkl/generate.pkl` whenever output ownership changes. ## Vendored dependencies -This repository vendors Pkl dependencies in `config/pkl/deps/` for Nix sandbox compatibility: +Pkl dependencies are vendored under `config/pkl/deps/` for Nix sandbox compatibility: -- `org.json_schema/JsonSchema.pkl` - Apple's pkl-pantry JSON Schema module (version 1.1.0) -- `pkl.experimental.uri/URI.pkl` - Transitive dependency for URI handling (version 1.0.3) +- `org.json_schema/JsonSchema.pkl` — Apple's pkl-pantry JSON Schema module, version 1.1.0 +- `pkl.experimental.uri/URI.pkl` — transitive URI dependency, version 1.0.3 -These are used by `config/pkl/base/sce-config-schema.pkl` to author typed JSON Schema definitions instead of `Dynamic` objects. The vendored approach ensures deterministic builds in Nix sandboxes where network access is restricted. +`config/pkl/base/sce-config-schema.pkl` consumes these modules. Update them by replacing the vendored files with reviewed newer versions. -To update these dependencies, download newer versions from the pkl-pantry repository and replace the vendored files. +## Troubleshooting ---- +**`pkl: command not found`** — Run the documented commands through `nix develop -c`. -## Troubleshoot issues +**Inventory check failure** — Compare the three workflow modules and renderer output mappings with the expected commands, agents, skill entrypoints, and package-local reference paths in `metadata-coverage-check.pkl`. -**pkl: command not found**: Run commands via nix develop -c ... exactly as shown. +**Generated output drift** — Regenerate with `nix develop -c pkl eval -m . config/pkl/generate.pkl`, inspect the diff, and rerun `nix run .#pkl-check-generated`. -**Missing metadata key errors**: Run nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl and add missing per-target entries in `config/pkl/renderers/opencode-metadata.pkl`, `config/pkl/renderers/claude-metadata.pkl`, or `config/pkl/renderers/pi-metadata.pkl`. +**Removed output still exists** — Delete the reported obsolete generated path after confirming it is generation-owned; do not add it back to the generator or parity source list. -**Unexpected file drift outside generated-owned paths**: Stop and verify whether those paths are intentionally manual/runtime-managed before editing the generator map. +**Unexpected drift outside generated-owned paths** — Stop and confirm whether the path is manual or runtime-managed before changing generation ownership. diff --git a/config/pkl/base/shared-content-automated-code.pkl b/config/pkl/base/shared-content-automated-code.pkl deleted file mode 100644 index 30317b42..00000000 --- a/config/pkl/base/shared-content-automated-code.pkl +++ /dev/null @@ -1,282 +0,0 @@ -import "shared-content-automated-common.pkl" as common - -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping { - ["shared-context-code"] = new UnitSpec { - title = "Shared Context Code" - canonicalBody = """ -You are the Shared Context Code agent (automated profile). - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -\(common.sharedSceCorePrinciplesSection) - -Hard boundaries -- One task per session. Multi-task execution is not supported in automated profile. -- Do not change plan structure or reorder tasks. -- If scope expansion is required, stop immediately with structured error. - -\(common.sharedSceContextAuthoritySection) - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Apply readiness confirmation gate: auto-pass only when both plan + task ID are provided and review reports no blockers/ambiguity/missing acceptance criteria; otherwise stop with structured error. -- After readiness check passes, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -\(common.sharedSceQualityPosturePrefixBullets) -- After accepted implementation changes, context synchronization is part of done. -\(common.sharedSceLongTermQualityBullet) - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. -""" - } -} - -commands = new Mapping { - ["next-task"] = new UnitSpec { - title = "Next Task" - canonicalBody = """ -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Run `sce-plan-review` first to resolve plan target/task and readiness. -- Apply readiness confirmation gate from `sce-plan-review`: - - auto-pass only when both plan + task ID are provided and review reports no blockers/ambiguity/missing acceptance criteria - - otherwise stop with structured error listing unresolved items -- Run `sce-task-execution`; keep mandatory implementation stop (auto-proceed with logging), scoped implementation, checks/lints/build, and plan status updates skill-owned. -- Run `sce-context-sync` as the required done gate. -- Wait for user feedback; if in-scope fixes are requested, apply fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this is the final plan task, run `sce-validation`. -- If more tasks remain, prompt a new session with `/next-task {plan_name} T0X`. -""" - } - ["validate"] = new UnitSpec { - title = "Validate" - canonicalBody = """ -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Run full validation checks. -- Capture evidence. -- Report pass/fail and any residual risks. -""" - } -} - -skills = new Mapping { - ["sce-context-sync"] = new UnitSpec { - title = "SCE Context Sync" - canonicalBody = """ -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. -""" - } - ["sce-task-execution"] = new UnitSpec { - title = "SCE Task Execution" - canonicalBody = """ -## Scope rule -- Execute exactly one task per session. -- Multi-task execution is not supported in automated profile; if requested, stop with error: "Automated profile does not support multi-task execution. Use single-task handoffs." - -## Mandatory implementation stop (auto-proceed with logging) -- Before writing or modifying any code, log implementation intent to `context/tmp/automated-session-log.md`. -- The log must include: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Proceed without waiting for confirmation. -- Preserve all safety constraints (one-task, no scope expansion, no plan reordering). - -## Log format -``` -## [timestamp] T0X: {task_title} -- Goal: {goal} -- In scope: {in_scope} -- Out of scope: {out_of_scope} -- Expected files: {file_list} -- Approach: {approach_summary} -- Status: proceeding -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Log implementation intent and proceed without waiting for confirmation. -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -## Scope expansion rule -- If out-of-scope edits are needed, stop immediately with structured error: `BLOCKER: scope_expansion_required`. -- List specific out-of-scope items detected. -- Require human session to approve scope change or split task. -""" - } - ["sce-validation"] = new UnitSpec { - title = "SCE Validation" - canonicalBody = """ -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` -""" - } -} \ No newline at end of file diff --git a/config/pkl/base/shared-content-automated-commit.pkl b/config/pkl/base/shared-content-automated-commit.pkl deleted file mode 100644 index 094c4b5e..00000000 --- a/config/pkl/base/shared-content-automated-commit.pkl +++ /dev/null @@ -1,111 +0,0 @@ -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping {} - -commands = new Mapping { - ["commit"] = new UnitSpec { - title = "Commit" - canonicalBody = """ -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine the one commit message. -- Skip staging confirmation prompt. -- Validate staged content exists; if empty, stop with error: "No staged changes. Stage changes before commit." -- Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. -- Run `sce-atomic-commit` to produce exactly one commit message for the staged diff. -- Do not branch into multi-commit or split guidance. -- Use the resulting message to run `git commit` against the staged changes. -- If `git commit` fails, stop and report the failure without inventing fallback commits. -""" - } -} - -skills = new Mapping { - ["sce-atomic-commit"] = new UnitSpec { - title = "SCE Atomic Commit" - canonicalBody = """ -## Goal - -Turn the current staged changes into one straightforward repository-style commit message. - -For this workflow: -- produce exactly one commit message -- keep the message focused on the staged change as a single coherent unit -- do not default to multi-commit split planning - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce one commit message that follows: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, the commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Procedure - -1) Review the staged change as one unit -- Infer the main reason for the staged change from the staged diff first. -- Use optional notes only to refine wording, not to override the staged truth. - -2) Choose scope -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) Apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) Validate the single-message result -- The message should describe the staged diff faithfully as one coherent change. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file Guidance gating - -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -""" - } -} diff --git a/config/pkl/base/shared-content-automated-common.pkl b/config/pkl/base/shared-content-automated-common.pkl deleted file mode 100644 index 57b97835..00000000 --- a/config/pkl/base/shared-content-automated-common.pkl +++ /dev/null @@ -1,39 +0,0 @@ -/// Shared schema and reusable snippets for canonical authored content units (automated profile). -/// See context/sce/automated-profile-contract.md for gate policies P1-P10. - -class ContentUnit { - id: String - kind: String - slug: String - title: String - canonicalBody: String -} - -sharedSceCorePrinciplesSection = """ -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. -""" - -sharedSceContextAuthoritySection = """ -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. -""" - -sharedSceQualityPosturePrefixBullets = """ -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -""" - -sharedSceLongTermQualityBullet = """ -- Long-term quality is measured by code quality and context accuracy. -""" - -sharedSceDisposablePlanLifecycleBullet = """ -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -""" \ No newline at end of file diff --git a/config/pkl/base/shared-content-automated-plan.pkl b/config/pkl/base/shared-content-automated-plan.pkl deleted file mode 100644 index 202a23e3..00000000 --- a/config/pkl/base/shared-content-automated-plan.pkl +++ /dev/null @@ -1,578 +0,0 @@ -import "shared-content-automated-common.pkl" as common - -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping { - ["shared-context-plan"] = new UnitSpec { - title = "Shared Context Plan" - canonicalBody = """ -You are the Shared Context Plan agent (automated profile). - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -\(common.sharedSceCorePrinciplesSection) - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -\(common.sharedSceContextAuthoritySection) - -Startup -1) Check for `context/`. -2) If missing, stop with error: "Automated profile requires existing context/. Run manual bootstrap first." -3) Do not auto-create context structure. -4) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -5) Before broad exploration, consult `context/context-map.md` for relevant context files. -6) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- If any critical detail is unclear (scope, success criteria, constraints, dependencies, domain ambiguity, architecture concerns, task ordering), stop with structured error listing all unresolved items with category labels. -- Do not invent assumptions silently. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -\(common.sharedSceQualityPosturePrefixBullets) -\(common.sharedSceDisposablePlanLifecycleBullet) -\(common.sharedSceLongTermQualityBullet) - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. -""" - } -} - -commands = new Mapping { - ["change-to-plan"] = new UnitSpec { - title = "Change To Plan" - canonicalBody = """ -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; delegate clarification/ambiguity handling and plan-shape contracts to `sce-plan-authoring`. -- If any critical detail is unclear, stop with structured error listing all unresolved items with category labels. -- Do not invent assumptions silently. -- Ensure plan output follows one-task/one-atomic-commit slicing through `sce-plan-authoring` task-shape rules. -- Write/update `context/plans/{plan_name}.md`. -- Confirm plan creation with `{plan_name}` and exact path. -- Return the full ordered task list. -- Prompt user to start a new session to implement `T01` and provide `/next-task {plan_name} T01`. -""" - } - ["change-to-plan-interactive"] = new UnitSpec { - title = "Change To Plan (Interactive)" - canonicalBody = """ -Load and follow the `sce-plan-authoring-interactive` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; delegate clarification/ambiguity handling and plan-shape contracts to `sce-plan-authoring-interactive`. -- Ensure plan output follows one-task/one-atomic-commit slicing through `sce-plan-authoring-interactive` task-shape rules. -- Write/update `context/plans/{plan_name}.md`. -- Confirm plan creation with `{plan_name}` and exact path. -- Return the full ordered task list. -- Prompt user to start a new session to implement `T01` and provide `/next-task {plan_name} T01`. -""" - } - ["handover"] = new UnitSpec { - title = "Handover" - canonicalBody = """ -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Create a new handover file in `context/handovers/` that captures: - -- current task state -- decisions made and rationale -- open questions or blockers -- next recommended step - -Default naming should align with task execution handovers: `context/handovers/{plan_name}-{task_id}-{timestamp}.md`. -If key details are missing, infer what you can from the current repo state and clearly label assumptions. -""" - } -} - -skills = new Mapping { - ["sce-bootstrap-context"] = new UnitSpec { - title = "SCE Bootstrap Context" - canonicalBody = """ -## When to use -- Use only when `context/` is missing. -- Automated profile does not support auto-bootstrap; stop with error requiring manual bootstrap. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. -""" - } - ["sce-handover-writer"] = new UnitSpec { - title = "SCE Handover Writer" - canonicalBody = """ -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. -""" - } - ["sce-plan-authoring"] = new UnitSpec { - title = "SCE Plan Authoring" - canonicalBody = """ -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, stop with structured error listing all unresolved items with category labels. -- Do not write or update `context/plans/{plan_name}.md` until all critical details are resolved. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate resolved details into the plan before handoff. - -**Example structured error (clarification gate triggered):** -``` -PLANNING BLOCKED - unresolved critical details: - -[scope] Is the auth middleware change limited to the API gateway, or does it also cover the admin panel? -[dependency] Should the new Redis client use the existing `ioredis` version (4.x) or upgrade to 5.x? -[criteria] What does "performance acceptable" mean? Specific p95 threshold required. - -Resolve all items above before planning can proceed. -``` - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Assumptions (if any) -5) Task stack (`T01..T0N`) -6) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Use this quick atomicity check before accepting each task: -- `single_intent`: task delivers one primary outcome -- `single_area`: task touch scope is narrow and related -- `single_verification`: done checks validate one coherent change set - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Worked example - -**Input change request:** -> "Add rate limiting to the public API so that unauthenticated requests are capped at 60 req/min per IP. Use Redis for the counter store. No changes to authenticated routes." - -**Output plan (`context/plans/rate-limiting-public-api.md`):** - -```markdown -# Plan: rate-limiting-public-api - -## Change summary -Introduce per-IP rate limiting (60 req/min) for unauthenticated requests to the public API using a Redis-backed counter. Authenticated routes are out of scope. - -## Success criteria -- Unauthenticated requests exceeding 60/min from a single IP receive HTTP 429. -- Authenticated requests are unaffected. -- Rate limit headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) are present on all public responses. - -## Constraints and non-goals -- Out of scope: authenticated route limiting, user-level quotas, Redis cluster setup. -- Must not increase p95 latency on public endpoints by more than 5 ms. - -## Task stack - -- [ ] T01: Add Redis rate-limit middleware for unauthenticated routes (status:todo) - - Task ID: T01 - - Goal: Implement middleware that increments a Redis counter keyed by IP and returns 429 when the limit is exceeded. - - Boundaries in scope: middleware module, unauthenticated route registration. - - Boundaries out of scope: authenticated routes, Redis connection config (use existing client). - - Done when: Middleware rejects the 61st request in a 60 s window with HTTP 429; requests 1-60 pass through. - - Verification notes: `npm test src/middleware/rateLimiter.test.ts`; manual smoke test with `wrk -d 65s -c 1 http://localhost:3000/api/public`. - -- [ ] T02: Expose rate limit response headers (status:todo) - - Task ID: T02 - - Goal: Attach `X-RateLimit-*` headers to every response from the rate-limited middleware. - - Boundaries in scope: header injection in the middleware added in T01. - - Boundaries out of scope: changing status codes, logging, or metrics. - - Done when: All public API responses include the three headers with correct values. - - Verification notes: `curl -I http://localhost:3000/api/public/health` shows all three headers. - -- [ ] T03: Validate, measure latency, and sync context (status:todo) - - Task ID: T03 - - Goal: Run full test suite, confirm no regression on authenticated routes, verify latency budget, update context docs. - - Boundaries in scope: integration tests, latency benchmarks, context/plans status update. - - Boundaries out of scope: new feature work. - - Done when: All tests green; p95 latency delta < 5 ms; plan marked complete. - - Verification notes: `npm test`; `npm run bench:public`; review `context/plans/rate-limiting-public-api.md` checkboxes. -``` - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. -""" - } - ["sce-plan-authoring-interactive"] = new UnitSpec { - title = "SCE Plan Authoring (Interactive)" - canonicalBody = """ -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -### Clarification gate example - -**User request:** "Add rate limiting to the API." - -**Clarification questions asked before writing the plan:** -1. Which endpoints should be rate-limited - all public routes, authenticated routes only, or specific ones? -2. What are the limits (e.g., requests per minute per IP/token) and what should happen when a limit is exceeded (429 response, queue, or silent drop)? -3. Should this use an existing library (e.g., `express-rate-limit`) or is a custom middleware preferred? - -*(Planning is blocked until the user answers all three.)* - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Use this quick atomicity check before accepting each task: -- `single_intent`: task delivers one primary outcome -- `single_area`: task touch scope is narrow and related -- `single_verification`: done checks validate one coherent change set - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - ---- - -## Complete plan example - -The following shows what a finished plan file looks like for a realistic request: *"Add per-user rate limiting to the REST API using `express-rate-limit`."* - -**File:** `context/plans/api-rate-limiting.md` - -```markdown -# Plan: api-rate-limiting - -## Change summary -Add per-user rate limiting to all authenticated REST API endpoints using the -`express-rate-limit` library. Unauthenticated endpoints are out of scope. - -## Success criteria -- Authenticated requests exceeding 100 req/min per token receive a 429 response - with a `Retry-After` header. -- All existing authenticated-endpoint tests continue to pass. -- A new integration test confirms the 429 path is exercised. - -## Constraints and non-goals -- **In scope:** authenticated routes under `/api/v1/` -- **Out of scope:** unauthenticated routes, IP-based limiting, admin bypass logic -- **Constraint:** must use `express-rate-limit ^7`; no custom Redis store in this change -- **Non-goal:** dashboarding or alerting on rate-limit events - -## Task stack - -- [ ] T01: Install and configure `express-rate-limit` middleware (status:todo) - - Task ID: T01 - - Goal: Add `express-rate-limit` as a dependency and wire a per-token limiter - into the authenticated router. - - Boundaries (in/out of scope): `src/middleware/rateLimiter.ts` and - `src/router/authenticated.ts` only; no changes to unauthenticated routes. - - Done when: Middleware is applied to the authenticated router and the dev - server starts without errors. - - Verification notes: `npm install` succeeds; `npm run dev` starts; manual - `curl` with a valid token returns 200. - -- [ ] T02: Return correct 429 response with `Retry-After` header (status:todo) - - Task ID: T02 - - Goal: Configure the limiter to respond with HTTP 429 and a `Retry-After` - header when the per-token limit is exceeded. - - Boundaries (in/out of scope): `src/middleware/rateLimiter.ts` handler only; - no route logic changes. - - Done when: Exceeding the limit returns `{ "error": "Too Many Requests" }` - with status 429 and a `Retry-After` value in seconds. - - Verification notes: `npm run test -- --grep "rate limit"` passes; manual - burst test with `artillery` confirms 429 after 100 req/min. - -- [ ] T03: Add integration test for the 429 path (status:todo) - - Task ID: T03 - - Goal: Write one integration test that fires 101 requests and asserts the - 101st receives 429 with `Retry-After`. - - Boundaries (in/out of scope): `tests/integration/rateLimiter.test.ts` only; - no changes to existing test files. - - Done when: New test file exists and `npm run test:integration` is green. - - Verification notes: `npm run test:integration` exits 0; coverage report - shows the 429 branch covered. - -- [ ] T04: Validation and cleanup (status:todo) - - Task ID: T04 - - Goal: Confirm full test suite passes, no regressions, and context files are - in sync. - - Boundaries (in/out of scope): Read-only audit of test results and context - directory; no new code changes. - - Done when: `npm test` exits 0; `context/` reflects the completed plan state. - - Verification notes: `npm test && npm run lint`; verify - `context/plans/api-rate-limiting.md` task statuses are all `done`. - -## Open questions -_(none - all clarifications resolved before planning)_ -``` -""" - } - ["sce-plan-review"] = new UnitSpec { - title = "SCE Plan Review" - canonicalBody = """ -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Stop with structured error for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, stop with error: "Automated profile requires existing context/. Run manual bootstrap first." -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If no plan path specified and multiple plans exist, stop with error listing available plans and requiring explicit plan path. - - If no plan path specified and single plan exists, auto-select the single plan. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- If any blockers, ambiguity, or missing acceptance criteria exist, stop with structured error listing all unresolved items with category labels. -- Confirm scope explicitly for this session: one task only (multi-task execution not supported in automated profile). - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until all issues are resolved. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output -Emit a readiness verdict using this structure: - -``` -next_task: "Task title or description from plan" -acceptance_criteria: - - Criterion A - - Criterion B -ready_for_implementation: yes | no -``` - -If `ready_for_implementation: no`, include an issues block: - -``` -issues: - blockers: - - "Dependency on X is unresolved" - ambiguity: - - "It is unclear whether Y should be replaced or extended" - missing_acceptance_criteria: - - "No definition of done for the migration step" -``` - -- Auto-proceed to implementation when `ready_for_implementation: yes`. - -## Structured error examples - -**Multiple plans found (no path specified):** -``` -ERROR: Multiple plans found. Specify an explicit plan path. -Available plans: - - context/plans/migrate-auth.md - - context/plans/refactor-api.md -``` - -**Blockers or ambiguity detected:** -``` -ERROR: Next task cannot proceed. Unresolved items: - [blocker] Auth service interface not yet defined - task depends on it. - [ambiguity] "Update schema" - unclear whether additive or destructive migration. - [missing_acceptance_criteria] No rollback criteria specified for the deployment step. -Resolve all items above before re-running plan review. -``` -""" - } -} \ No newline at end of file diff --git a/config/pkl/base/shared-content-automated.pkl b/config/pkl/base/shared-content-automated.pkl deleted file mode 100644 index 169f7419..00000000 --- a/config/pkl/base/shared-content-automated.pkl +++ /dev/null @@ -1,134 +0,0 @@ -import "shared-content-automated-common.pkl" as common -import "shared-content-automated-plan.pkl" as plan -import "shared-content-automated-code.pkl" as code -import "shared-content-automated-commit.pkl" as commit - -/// Shared aggregation surface for canonical authored content units (automated profile). - -agents = new Mapping { - ["shared-context-plan"] = new common.ContentUnit { - id = "agent.shared-context-plan" - kind = "agent" - slug = "shared-context-plan" - title = plan.agents["shared-context-plan"].title - canonicalBody = plan.agents["shared-context-plan"].canonicalBody - } - ["shared-context-code"] = new common.ContentUnit { - id = "agent.shared-context-code" - kind = "agent" - slug = "shared-context-code" - title = code.agents["shared-context-code"].title - canonicalBody = code.agents["shared-context-code"].canonicalBody - } -} - -commands = new Mapping { - ["next-task"] = new common.ContentUnit { - id = "command.next-task" - kind = "command" - slug = "next-task" - title = code.commands["next-task"].title - canonicalBody = code.commands["next-task"].canonicalBody - } - ["change-to-plan"] = new common.ContentUnit { - id = "command.change-to-plan" - kind = "command" - slug = "change-to-plan" - title = plan.commands["change-to-plan"].title - canonicalBody = plan.commands["change-to-plan"].canonicalBody - } - ["change-to-plan-interactive"] = new common.ContentUnit { - id = "command.change-to-plan-interactive" - kind = "command" - slug = "change-to-plan-interactive" - title = plan.commands["change-to-plan-interactive"].title - canonicalBody = plan.commands["change-to-plan-interactive"].canonicalBody - } - ["handover"] = new common.ContentUnit { - id = "command.handover" - kind = "command" - slug = "handover" - title = plan.commands["handover"].title - canonicalBody = plan.commands["handover"].canonicalBody - } - ["commit"] = new common.ContentUnit { - id = "command.commit" - kind = "command" - slug = "commit" - title = commit.commands["commit"].title - canonicalBody = commit.commands["commit"].canonicalBody - } - ["validate"] = new common.ContentUnit { - id = "command.validate" - kind = "command" - slug = "validate" - title = code.commands["validate"].title - canonicalBody = code.commands["validate"].canonicalBody - } -} - -skills = new Mapping { - ["sce-bootstrap-context"] = new common.ContentUnit { - id = "skill.sce-bootstrap-context" - kind = "skill" - slug = "sce-bootstrap-context" - title = plan.skills["sce-bootstrap-context"].title - canonicalBody = plan.skills["sce-bootstrap-context"].canonicalBody - } - ["sce-context-sync"] = new common.ContentUnit { - id = "skill.sce-context-sync" - kind = "skill" - slug = "sce-context-sync" - title = code.skills["sce-context-sync"].title - canonicalBody = code.skills["sce-context-sync"].canonicalBody - } - ["sce-handover-writer"] = new common.ContentUnit { - id = "skill.sce-handover-writer" - kind = "skill" - slug = "sce-handover-writer" - title = plan.skills["sce-handover-writer"].title - canonicalBody = plan.skills["sce-handover-writer"].canonicalBody - } - ["sce-plan-authoring"] = new common.ContentUnit { - id = "skill.sce-plan-authoring" - kind = "skill" - slug = "sce-plan-authoring" - title = plan.skills["sce-plan-authoring"].title - canonicalBody = plan.skills["sce-plan-authoring"].canonicalBody - } - ["sce-plan-authoring-interactive"] = new common.ContentUnit { - id = "skill.sce-plan-authoring-interactive" - kind = "skill" - slug = "sce-plan-authoring-interactive" - title = plan.skills["sce-plan-authoring-interactive"].title - canonicalBody = plan.skills["sce-plan-authoring-interactive"].canonicalBody - } - ["sce-plan-review"] = new common.ContentUnit { - id = "skill.sce-plan-review" - kind = "skill" - slug = "sce-plan-review" - title = plan.skills["sce-plan-review"].title - canonicalBody = plan.skills["sce-plan-review"].canonicalBody - } - ["sce-task-execution"] = new common.ContentUnit { - id = "skill.sce-task-execution" - kind = "skill" - slug = "sce-task-execution" - title = code.skills["sce-task-execution"].title - canonicalBody = code.skills["sce-task-execution"].canonicalBody - } - ["sce-atomic-commit"] = new common.ContentUnit { - id = "skill.sce-atomic-commit" - kind = "skill" - slug = "sce-atomic-commit" - title = commit.skills["sce-atomic-commit"].title - canonicalBody = commit.skills["sce-atomic-commit"].canonicalBody - } - ["sce-validation"] = new common.ContentUnit { - id = "skill.sce-validation" - kind = "skill" - slug = "sce-validation" - title = code.skills["sce-validation"].title - canonicalBody = code.skills["sce-validation"].canonicalBody - } -} \ No newline at end of file diff --git a/config/pkl/base/shared-content-code.pkl b/config/pkl/base/shared-content-code.pkl deleted file mode 100644 index 682dfcec..00000000 --- a/config/pkl/base/shared-content-code.pkl +++ /dev/null @@ -1,295 +0,0 @@ -import "shared-content-common.pkl" as common - -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping { - ["shared-context-code"] = new UnitSpec { - title = "Shared Context Code" - canonicalBody = """ -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -\(common.sharedSceCorePrinciplesSection) - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -\(common.sharedSceContextAuthoritySection) - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -\(common.sharedSceQualityPosturePrefixBullets) -- After accepted implementation changes, context synchronization is part of done. -\(common.sharedSceLongTermQualityBullet) - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. -""" - } -} - -commands = new Mapping { - ["next-task"] = new UnitSpec { - title = "Next Task" - canonicalBody = """ -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. -""" - } - ["validate"] = new UnitSpec { - title = "Validate" - canonicalBody = """ -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. -""" - } -} - -skills = new Mapping { - ["sce-context-sync"] = new UnitSpec { - title = "SCE Context Sync" - canonicalBody = """ -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. -""" - } - ["sce-task-execution"] = new UnitSpec { - title = "SCE Task Execution" - canonicalBody = """ -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. -""" - } - ["sce-validation"] = new UnitSpec { - title = "SCE Validation" - canonicalBody = """ -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` -""" - } -} diff --git a/config/pkl/base/shared-content-commit.pkl b/config/pkl/base/shared-content-commit.pkl deleted file mode 100644 index 74bb328b..00000000 --- a/config/pkl/base/shared-content-commit.pkl +++ /dev/null @@ -1,156 +0,0 @@ -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping {} - -commands = new Mapping { - ["commit"] = new UnitSpec { - title = "Commit" - canonicalBody = """ -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. -""" - } -} - -skills = new Mapping { - ["sce-atomic-commit"] = new UnitSpec { - title = "SCE Atomic Commit" - canonicalBody = """ -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode -""" - } -} diff --git a/config/pkl/base/shared-content-common.pkl b/config/pkl/base/shared-content-common.pkl deleted file mode 100644 index 7948d405..00000000 --- a/config/pkl/base/shared-content-common.pkl +++ /dev/null @@ -1,38 +0,0 @@ -/// Shared schema and reusable snippets for canonical authored content units. - -class ContentUnit { - id: String - kind: String - slug: String - title: String - canonicalBody: String -} - -sharedSceCorePrinciplesSection = """ -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. -""" - -sharedSceContextAuthoritySection = """ -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. -""" - -sharedSceQualityPosturePrefixBullets = """ -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -""" - -sharedSceLongTermQualityBullet = """ -- Long-term quality is measured by code quality and context accuracy. -""" - -sharedSceDisposablePlanLifecycleBullet = """ -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -""" diff --git a/config/pkl/base/shared-content-plan.pkl b/config/pkl/base/shared-content-plan.pkl deleted file mode 100644 index 2b09dd41..00000000 --- a/config/pkl/base/shared-content-plan.pkl +++ /dev/null @@ -1,378 +0,0 @@ -import "shared-content-common.pkl" as common - -local class UnitSpec { - title: String - canonicalBody: String -} - -agents = new Mapping { - ["shared-context-plan"] = new UnitSpec { - title = "Shared Context Plan" - canonicalBody = """ -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -\(common.sharedSceCorePrinciplesSection) - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -\(common.sharedSceContextAuthoritySection) - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -\(common.sharedSceQualityPosturePrefixBullets) -\(common.sharedSceDisposablePlanLifecycleBullet) -\(common.sharedSceLongTermQualityBullet) - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. -""" - } -} - -commands = new Mapping { - ["change-to-plan"] = new UnitSpec { - title = "Change To Plan" - canonicalBody = """ -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. -""" - } - ["handover"] = new UnitSpec { - title = "Handover" - canonicalBody = """ -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. -""" - } -} - -skills = new Mapping { - ["sce-bootstrap-context"] = new UnitSpec { - title = "SCE Bootstrap Context" - canonicalBody = """ -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. -""" - } - ["sce-handover-writer"] = new UnitSpec { - title = "SCE Handover Writer" - canonicalBody = """ -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. -""" - } - ["sce-plan-authoring"] = new UnitSpec { - title = "SCE Plan Authoring" - canonicalBody = """ -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. -""" - } - ["sce-plan-review"] = new UnitSpec { - title = "SCE Plan Review" - canonicalBody = """ -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill -""" - } -} diff --git a/config/pkl/base/shared-content.pkl b/config/pkl/base/shared-content.pkl deleted file mode 100644 index 5f2b7ec6..00000000 --- a/config/pkl/base/shared-content.pkl +++ /dev/null @@ -1,120 +0,0 @@ -import "shared-content-common.pkl" as common -import "shared-content-plan.pkl" as plan -import "shared-content-code.pkl" as code -import "shared-content-commit.pkl" as commit - -/// Shared aggregation surface for canonical authored content units. - -agents = new Mapping { - ["shared-context-plan"] = new common.ContentUnit { - id = "agent.shared-context-plan" - kind = "agent" - slug = "shared-context-plan" - title = plan.agents["shared-context-plan"].title - canonicalBody = plan.agents["shared-context-plan"].canonicalBody - } - ["shared-context-code"] = new common.ContentUnit { - id = "agent.shared-context-code" - kind = "agent" - slug = "shared-context-code" - title = code.agents["shared-context-code"].title - canonicalBody = code.agents["shared-context-code"].canonicalBody - } -} - -commands = new Mapping { - ["next-task"] = new common.ContentUnit { - id = "command.next-task" - kind = "command" - slug = "next-task" - title = code.commands["next-task"].title - canonicalBody = code.commands["next-task"].canonicalBody - } - ["change-to-plan"] = new common.ContentUnit { - id = "command.change-to-plan" - kind = "command" - slug = "change-to-plan" - title = plan.commands["change-to-plan"].title - canonicalBody = plan.commands["change-to-plan"].canonicalBody - } - ["handover"] = new common.ContentUnit { - id = "command.handover" - kind = "command" - slug = "handover" - title = plan.commands["handover"].title - canonicalBody = plan.commands["handover"].canonicalBody - } - ["commit"] = new common.ContentUnit { - id = "command.commit" - kind = "command" - slug = "commit" - title = commit.commands["commit"].title - canonicalBody = commit.commands["commit"].canonicalBody - } - ["validate"] = new common.ContentUnit { - id = "command.validate" - kind = "command" - slug = "validate" - title = code.commands["validate"].title - canonicalBody = code.commands["validate"].canonicalBody - } -} - -skills = new Mapping { - ["sce-bootstrap-context"] = new common.ContentUnit { - id = "skill.sce-bootstrap-context" - kind = "skill" - slug = "sce-bootstrap-context" - title = plan.skills["sce-bootstrap-context"].title - canonicalBody = plan.skills["sce-bootstrap-context"].canonicalBody - } - ["sce-context-sync"] = new common.ContentUnit { - id = "skill.sce-context-sync" - kind = "skill" - slug = "sce-context-sync" - title = code.skills["sce-context-sync"].title - canonicalBody = code.skills["sce-context-sync"].canonicalBody - } - ["sce-handover-writer"] = new common.ContentUnit { - id = "skill.sce-handover-writer" - kind = "skill" - slug = "sce-handover-writer" - title = plan.skills["sce-handover-writer"].title - canonicalBody = plan.skills["sce-handover-writer"].canonicalBody - } - ["sce-plan-authoring"] = new common.ContentUnit { - id = "skill.sce-plan-authoring" - kind = "skill" - slug = "sce-plan-authoring" - title = plan.skills["sce-plan-authoring"].title - canonicalBody = plan.skills["sce-plan-authoring"].canonicalBody - } - ["sce-plan-review"] = new common.ContentUnit { - id = "skill.sce-plan-review" - kind = "skill" - slug = "sce-plan-review" - title = plan.skills["sce-plan-review"].title - canonicalBody = plan.skills["sce-plan-review"].canonicalBody - } - ["sce-task-execution"] = new common.ContentUnit { - id = "skill.sce-task-execution" - kind = "skill" - slug = "sce-task-execution" - title = code.skills["sce-task-execution"].title - canonicalBody = code.skills["sce-task-execution"].canonicalBody - } - ["sce-atomic-commit"] = new common.ContentUnit { - id = "skill.sce-atomic-commit" - kind = "skill" - slug = "sce-atomic-commit" - title = commit.skills["sce-atomic-commit"].title - canonicalBody = commit.skills["sce-atomic-commit"].canonicalBody - } - ["sce-validation"] = new common.ContentUnit { - id = "skill.sce-validation" - kind = "skill" - slug = "sce-validation" - title = code.skills["sce-validation"].title - canonicalBody = code.skills["sce-validation"].canonicalBody - } -} diff --git a/config/pkl/base/workflow-change-to-plan.pkl b/config/pkl/base/workflow-change-to-plan.pkl new file mode 100644 index 00000000..275c450a --- /dev/null +++ b/config/pkl/base/workflow-change-to-plan.pkl @@ -0,0 +1,1335 @@ +import "workflow-content.pkl" as model + +/// Canonical `/change-to-plan` workflow command and its self-contained skill +/// packages. Text mirrors the project-root `.pi/` behavioral baseline; target +/// renderers consume this model in later workflow-rendering tasks. + +local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { + path = documentPath + text = documentText +} + +local packageDocuments = (documents: Listing) -> new Mapping { + for (item in documents) { + [item.path] = item + } +} + +local contextLoadPackage = new model.SkillPackage { + slug = "sce-context-load" + title = "SCE Context Load" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", CONTEXT_SKILL) + makeDocument.apply("references/context-brief.yaml", CONTEXT_CONTRACT) + }) +} + +local planAuthoringPackage = new model.SkillPackage { + slug = "sce-plan-authoring" + title = "SCE Plan Authoring" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", AUTHORING_SKILL) + makeDocument.apply("references/authoring-contract.yaml", AUTHORING_CONTRACT) + makeDocument.apply("references/plan-template.md", PLAN_TEMPLATE) + makeDocument.apply("references/plan-summary.md", PLAN_SUMMARY) + }) +} + +local COMMAND = """ + --- + description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" + argument-hint: "" + --- + + SCE CHANGE TO PLAN `$ARGUMENTS` + + ## Input + + `$ARGUMENTS` is the change request, in free-form prose. + + - The change request is required. + - It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + + When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + + Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + + Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + + ## Workflow + + ### 1. Load durable context + + Invoke `sce-context-load` with the change request as the focus. + + `context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + + The skill must return a result matching its context brief contract. + + Branch on `status`: + + `bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + + ``` + + ------------------------------------- + + # This repository has no durable context. + + Bootstrap it, then continue in this session: + + `sce setup --bootstrap-context` + ``` + + Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + + `loaded` -> Continue to the next step. + + Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + + ### 2. Author the plan + + Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + + Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + + `sce-plan-authoring` exclusively owns: + + - Resolving whether the request targets a new or an existing plan. + - The clarification gate. + - Normalizing the change summary, acceptance criteria, constraints, and non-goals. + - Slicing the task stack into one-task/one-atomic-commit units. + - Writing `context/plans/{plan_name}.md`. + + Do not duplicate any of it. Do not write or edit the plan file yourself. + + The skill must return a result matching its authoring contract. + + Branch on `status`: + + `needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + + ``` + + ------------------------------------- + + # Clarification needed. + + No plan was written. + + Answer each question below. + + ## {question-id} · {category} + + {question} + + Why this blocks planning: {why_blocking} + ``` + + Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + + Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + + `blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + + - Each issue in `issues`: its problem, its impact, and the decision it requires. + - When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + + Stop. + + `plan_ready` -> Continue to the next step. + + ### 3. Determine the continuation + + Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + + Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + + The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + + Write `task` rather than `tasks` when `total_tasks` is 1. + + Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + + Return: + + ``` + + ------------------------------------- + + # Plan {plan-name} is ready. + + {total-tasks} tasks planned. + + This plan is a draft. State a correction and it will be updated. + + Next up: + + {next-task-id} — {next-task-title} + + `/next-task {plan-path} {next-task-id}` + ``` + + Then stop and wait. Do not implement, and do not run the handoff yourself. + + ### 4. Revise the plan on request + + When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + + Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + + An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + + Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + + Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + + On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + + Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + + When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + + Stop. + + ## Rules + + - Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. + - Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. + - Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. + - Do not suppress, soften, or answer an open question or clarification question on the user's behalf. + - Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. + - Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. + - Do not duplicate the internal instructions of invoked skills. + - Do not plan before durable context is loaded. + - Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. + - Do not modify any file under `context/` outside `context/plans/`. + - Do not implement any part of the plan. + - Do not ask for implementation confirmation. + - Do not run task execution, context synchronization, or full-plan validation. + - Do not emit a `/validate` command. This workflow always hands off to `/next-task`. + - Do not answer the skill's clarification questions on the user's behalf. + - Do not execute the continuation returned at the end. + - Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. + """ + +local CONTEXT_SKILL = """ + --- + name: sce-context-load + description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. + --- + + # SCE Context Load + + ## Purpose + + Load the durable context needed to reason about one focus, and no more. + + `context/` is AI-first memory describing current state. This skill turns it into + a scoped brief so later phases start from recorded truth instead of rediscovering + the repository. + + This skill owns: + + - Confirming `context/` exists. + - Reading the context entry points. + - Selecting the domain context relevant to the focus. + - Reporting focus areas with no durable context. + - Reporting context that contradicts the code. + - Returning one structured context brief. + + Return a result matching: + + `references/context-brief.yaml` + + ## Input + + The invoking workflow provides: + + - One focus: a change request, a task, or a named area. + - Optionally, paths or areas already known to be relevant. + + ## Workflow + + ### 1. Confirm the context root + + When `context/` does not exist, return `bootstrap_required` immediately. Read + nothing further. + + Bootstrapping is the invoking workflow's decision, not this skill's. + + ### 2. Read the entry points + + Read, when present: + + - `context/context-map.md` + - `context/overview.md` + - `context/glossary.md` + + Read `context/architecture.md` when the focus touches structure, boundaries, or + data flow. Read `context/patterns.md` when it touches conventions the change + must follow. + + A missing entry point is a gap, not a failure. Record it and continue. + + ### 3. Select the relevant domain context + + Consult `context/context-map.md` before any broad exploration. The map's + annotations name what each domain file owns; use them to select files, rather + than globbing or searching `context/`. + + Select only files whose subject overlaps the focus. Follow at most one level of + links out of a selected file, and only when the link is needed to understand the + focus. + + Do not read every domain file. A brief that includes everything has selected + nothing. + + Record focus areas with no matching context file under `gaps`. + + ### 4. Check recorded context against the code + + For each selected file, spot-check its central claims against the code it + describes. + + When context and code diverge, the code is the source of truth. Record the + divergence under `drift` with what context says, what the code shows, and the + repair the context needs. + + Do not repair it here. Later phases decide whether repair belongs in the current + work. + + Keep this proportional: check the claims the focus depends on, not every + sentence. + + ### 5. Return the brief + + Return exactly one structured result: + + - `loaded` + - `bootstrap_required` + + Report facts the invoking workflow can act on. A brief that only lists file + paths has moved no knowledge. + + Return only the structured result. Do not add explanatory prose before or after + it. + + ## Boundaries + + Do not: + + - Create, update, move, or delete any file under `context/`. + - Bootstrap `context/`. + - Repair drift or stale context. + - Modify application code or tests. + - Read the entire `context/` tree by default. + - Explore the repository beyond what the focus and the selected context require. + - Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. + - Author a plan, select a task, or implement anything. + + ## Completion + + The skill is complete after: + + - The context root was confirmed, or `bootstrap_required` was returned. + - The entry points were read, and the relevant domain context was selected and + read. + - One valid result matching `references/context-brief.yaml` was returned. + """ + +local CONTEXT_CONTRACT = """ + version: 1 + name: sce-context-load-result + + description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + + output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + + variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. + """ + +local AUTHORING_SKILL = """ + --- + name: sce-plan-authoring + description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. + --- + + # SCE Plan Authoring + + ## Purpose + + Turn exactly one change request into `context/plans/{plan_name}.md` without + inventing material requirements. + + This skill owns: + + - Resolving whether the request targets a new or an existing plan. + - Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. + - Deciding whether the request can be planned safely. + - Normalizing the change summary, acceptance criteria, constraints, and + non-goals. + - Slicing the work into atomic implementation tasks. + - Writing the plan file. + - Returning one structured authoring result. + + Use the document format defined in: + + `references/plan-template.md` + + Return a result matching: + + `references/authoring-contract.yaml` + + The invoking workflow renders that result as the summary defined in: + + `references/plan-summary.md` + + ## Input + + The invoking workflow provides: + + - One change request, in free-form prose. + - The `loaded` context brief from `sce-context-load`. + + The change request may name a plan, describe a change to an existing plan, or + describe entirely new work. Resolving which applies is this skill's + responsibility. + + The context brief is the durable memory this plan starts from. Treat its + `key_facts` as recorded current state, its `gaps` as areas with no durable + context, and its `drift` as context the code has already outrun. + + When no brief is supplied, load the context named by the change request before + authoring, and follow the selection discipline in *Inspect relevant context*. + + Answers the user gave to earlier clarification questions arrive as part of the + change request. Incorporate them into the plan. + + A revision of a plan authored earlier in the session also arrives as the change + request, and it is usually terse: a task boundary the user disagrees with, an + ordering they want changed, work they want added or dropped. Read it against the + existing plan, which supplies the scope, criteria, and terminology it omits. + Terseness is not ambiguity. Do not return `needs_clarification` for detail the + plan already carries; ask only when the revision itself is genuinely undecidable. + + ## Workflow + + ### 1. Resolve the plan target + + Determine whether the request targets a new plan or an existing plan in + `context/plans/`. + + When it targets an existing plan, read that plan before authoring. Preserve its + completed tasks, their recorded evidence, its structure, and its terminology. + + When multiple existing plans match and none can be selected safely, return + `blocked` with the matching candidates. + + When the request targets a new plan, derive `plan_name` as a short kebab-case + slug of the change, and confirm it does not collide with an existing plan. + + Resolve exactly one plan target per invocation. + + ### 2. Challenge the change + + Before planning how to build the change, work out whether it is worth building. + A plan is a commitment of someone's time; authoring one for work that should not + happen is worse than authoring none. + + Interrogate the request: + + - What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. + - What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. + - Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. + - Is there a materially smaller version that gets most of the value? Name it. + - What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? + - Does the stated justification survive contact with the code, or does the code + show the premise is already false? + + Doubt that survives this is not an implementation detail to be tidied away. It + belongs in the plan's `Open questions` and in `open_questions`, in the plain + words you would use to a colleague. "Is this worth doing at all, given X?" is a + legitimate open question. So is "this looks like it duplicates Y". + + Weigh honestly in both directions. A request that is obviously worth building + gets no manufactured doubt: inventing questions to look rigorous is its own + failure, and it teaches the user to ignore the section. Most changes are fine. + Say nothing when there is nothing to say. + + Keep going regardless. Skepticism shapes the plan and the open questions; it + does not withhold the plan. The only value judgment that stops authoring is + `no_actionable_work`, when the change is already implemented. + + ### 3. Run the clarification gate + + Before writing or updating any plan file, check the request for critical + unresolved detail: + + - Scope boundaries and out-of-scope items. + - Acceptance criteria and the checks that prove them. + - Constraints and non-goals. + - Dependency choices, including new libraries or services, versions, and the + integration approach. + - Domain ambiguity, including unclear business rules, terminology, or ownership. + - Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. + - Task ordering assumptions and prerequisite sequencing. + + Return `needs_clarification` with one to three targeted questions when any of + these would materially change the plan. Write no plan file in that case. + + Use repository conventions for ordinary local choices. Do not block on: + + - Naming inferable from surrounding code. + - Established formatting or style. + - Reversible local implementation details. + - Details that do not change scope, acceptance criteria, or task ordering. + + Record those choices under `assumptions`. + + Do not silently invent missing requirements. When the user has explicitly + allowed assumptions, record them in the plan's `Assumptions` section instead of + asking. + + A justification that does not survive inspection is itself a critical unresolved + detail. "For consistency", "to make it cleaner", "we will need it later" name no + outcome and prove nothing; ask what the change is actually for before planning + around it. Do not treat confident phrasing as evidence. + + ### 4. Inspect relevant context + + Start from the context brief. Read code only where the brief leaves the change + underspecified: + + - Existing behavior the change affects. + - Applicable repository conventions. + - Architectural boundaries. + - Relevant tests and available verification commands. + - Decisions or specifications connected to the change. + + Where the brief reports `drift`, the code is the source of truth. Plan against + the code, and schedule the context repair as part of the change when it falls + inside scope. + + Where the brief reports `gaps`, the plan may need to establish durable context + the repository does not yet have. + + Do not explore the entire repository by default. + + ### 5. Author the acceptance criteria + + State how the finished plan is proven, before slicing tasks. + + Each criterion describes observable behavior of the finished system and names + the check that proves it. Record repository-wide checks once under + `Full validation`, and the durable context the change must be reflected in + under `Context sync`. + + `/validate` runs this section after the last task completes. It is the only + place a plan says how it is validated. + + ### 6. Author the task stack + + Slice the work into sequential tasks `T01..T0N` using the task format and the + atomic slicing contract in `references/plan-template.md`. + + Every executable task must be completable and landable as one coherent commit. + Split any task that would require multiple independent commits. Convert broad + wrappers such as `polish` or `finalize` into specific outcomes with concrete + acceptance checks. + + Order tasks so each one's declared dependencies precede it. + + The last task is an ordinary implementation task. Do not author a trailing + validation-and-cleanup task, or any task whose only purpose is running the full + check suite, verifying durable context, or removing scaffolding. + + Confirm every acceptance criterion is satisfied by at least one task. When one + is not, the task stack is incomplete. + + A finished stack always leaves at least one incomplete task, so the invoking + workflow can always hand off to `/next-task`. When the request resolves to a + plan but produces no incomplete task, because the change is already implemented + or already covered by completed tasks, return `blocked` with category + `no_actionable_work` instead of writing the plan. + + ### 7. Write the plan + + Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + + When updating an existing plan, keep completed tasks and their evidence intact, + and append or renumber new tasks without disturbing recorded history. + + ### 8. Return the result + + Return exactly one structured result: + + - `plan_ready` + - `needs_clarification` + - `blocked` + + Return only the structured result. Do not add explanatory prose before or after + it. + + ## Tone + + Every question and open question this skill writes is read by the user. Write + them the way a senior engineer talks in review: direct, specific, and unbothered + by the possibility of being unwelcome. + + - Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. + - State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. + - Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. + - Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. + - Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. + - Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + + When the user overrules a doubt, record it and move on. Do not relitigate a + decision the user has made, and do not smuggle the objection back in as a + constraint, a non-goal, or a task. + + ## Boundaries + + Do not: + + - Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. + - Answer your own clarification questions. + - Write a plan file when returning `needs_clarification` or `blocked`. + - Implement any task in the plan. + - Modify application code or tests. + - Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. + - Mark any task complete. + - Request implementation confirmation. + - Invoke task execution. + - Synchronize context. + - Run final validation. + - Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. + - Return `plan_ready` for a plan with no incomplete task. + - Create a Git commit. + - Author more than one plan. + + ## Completion + + The skill is complete after: + + - One plan target was resolved, or resolution failed and was reported. + - The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. + - One valid result matching `references/authoring-contract.yaml` was returned. + """ + +local AUTHORING_CONTRACT = """ + version: 1 + name: sce-plan-authoring-result + + description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + + output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + + variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. + """ + +local PLAN_TEMPLATE = """ + # SCE Plan Template + + The document format for `context/plans/{plan_name}.md`. This is the plan file + written to disk, not the result returned to the invoking workflow. + + Copy the template below and fill every `{placeholder}`. Omit optional sections + entirely rather than writing them empty. + + --- + + ## Template + + ```markdown + # Plan: {plan-name} + + ## Change summary + + {One or two paragraphs: what changes, where, and why. State whether this + extends existing behavior, replaces it, or preserves work already in progress.} + + ## Acceptance criteria + + How this plan is proven complete. Each criterion is observable and names the + check that proves it. `/validate` runs these checks; no task in the stack + performs final validation. + + - [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` + - [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + + ### Full validation + + Repository-wide checks `/validate` runs after the last task, regardless of + which criterion they map to. + + - `{full check suite command}` + - `{generated-output or parity check command, when applicable}` + + ### Context sync + + - {Durable context files that must describe the change once implemented.} + + ## Constraints and non-goals + + - **In scope:** {files, modules, and surfaces this plan may touch} + - **Out of scope:** {adjacent work explicitly excluded} + - **Constraints:** {dependencies, conventions, compatibility, or policy limits} + - **Non-goal:** {tempting generalization this plan deliberately avoids} + + ## Assumptions + + {Include only when the user allowed assumptions, or ordinary local choices were + recorded. Remove the section otherwise.} + + - {Assumption, and the convention or decision record it rests on.} + + ## Task stack + + - [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + + - [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + + ## Open questions + + {Non-blocking questions only. A question that would change scope, success + criteria, or task ordering blocks authoring instead. Write `None.` with a short + justification when nothing remains.} + + {Unresolved doubt about the change's value belongs here — whether it is worth + building, whether it duplicates behavior the repository already has, whether a + smaller version would do. State it plainly and name the alternative. Do not + invent one: `None.` is the expected answer for a well-specified change.} + ``` + + --- + + ## Filled-in task example + + ```markdown + - [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. + ``` + + ## Acceptance criteria rules + + - Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". + - Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. + - Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. + - List repository-wide checks once under `Full validation` instead of repeating + them per criterion. + - Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. + - The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + + ## Task rules + + - Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. + - Author each executable task as one atomic commit unit by default. + - Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. + - Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. + - Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. + - Order tasks so each one's declared dependencies precede it. + + ## No validation task + + - The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. + - Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. + - Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. + - A task may still create or update durable context when that context is part of + the change itself. + + ## Completion records + + `sce-task-execution` appends evidence to a task when it completes, and flips the + checkbox and status: + + ```markdown + - [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} + ``` + + `/validate` appends a `## Validation Report` section at the end of the plan. + Do not author either while planning. + + ## Updating an existing plan + + - Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. + - Preserve the plan's existing structure and terminology. + - Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. + - Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. + """ + +local PLAN_SUMMARY = """ + # SCE Plan Summary + + The user-facing summary shown after a plan is written. The invoking workflow + renders it from the `plan_ready` result, immediately before the continuation + block. + + This is chat output, not a file. Nothing here is written to the plan. + + ## Layout + + ``` + # Plan: {plan.name} + + Path: {plan.path} + + ## Summary: + {plan summary} + + ## Tasks: + 1. {task.id} — {task.title} + 2. {task.id} — {task.title} + + ## Assumptions: + - {assumption} + + ## Open questions: + - {open question} + ``` + + ## Field mapping + + Every value comes from the `plan_ready` result. Render nothing the result does + not carry. + + - `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. + - `Path:` — `plan.path`, exactly as returned, so it stays runnable. + - `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. + - `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. + - `Assumptions:` — one line per entry in `assumptions`. + - `Open questions:` — one line per entry in `open_questions`. + + ## Empty sections + + Never drop a section heading. An absent section reads as an oversight; an + explicit `None.` confirms nothing is pending. + + When `assumptions` is empty: + + ``` + ## Assumptions: + - None. + ``` + + When `open_questions` is absent: + + ``` + ## Open questions: + - None. + ``` + + ## Rules + + - Render the sections in the order above. + - Keep task titles as authored. Do not reword, expand, or re-scope them. + - Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. + - Do not print the raw result, and do not wrap the summary in a code fence. + - Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + + ## Example + + ``` + # Plan: red-sce-banner + + Path: context/plans/red-sce-banner.md + + ## Summary: + Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + + ## Tasks: + 1. T01 — Render the SCE banner in red + + ## Assumptions: + - "SCE letters" refers to the ASCII-art banner in top-level help. + - Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + + ## Open questions: + - None. + ``` + """ + +workflow = new model.WorkflowPackage { + slug = "change-to-plan" + command = new model.WorkflowCommand { + slug = "change-to-plan" + title = "Change to Plan" + document = makeDocument.apply("change-to-plan.md", COMMAND) + } + skills = new Mapping { + [contextLoadPackage.slug] = contextLoadPackage + [planAuthoringPackage.slug] = planAuthoringPackage + } +} diff --git a/config/pkl/base/workflow-content.pkl b/config/pkl/base/workflow-content.pkl new file mode 100644 index 00000000..3a55aef3 --- /dev/null +++ b/config/pkl/base/workflow-content.pkl @@ -0,0 +1,31 @@ +/// Canonical model for workflow-oriented Markdown generation. +/// +/// A workflow owns commands and self-contained skill packages. Package document +/// paths are relative to the skill root, so nested references can be rendered +/// deterministically for every target without cross-skill dependencies. + +class WorkflowDocument { + path: String + text: String +} + +class WorkflowCommand { + slug: String + title: String + document: WorkflowDocument +} + +class SkillPackage { + slug: String + title: String + documents: Mapping + + skillDocument: WorkflowDocument = documents["SKILL.md"] +} + +class WorkflowPackage { + slug: String + command: WorkflowCommand + skills: Mapping +} + diff --git a/config/pkl/base/workflow-context-sync.pkl b/config/pkl/base/workflow-context-sync.pkl new file mode 100644 index 00000000..166bb915 --- /dev/null +++ b/config/pkl/base/workflow-context-sync.pkl @@ -0,0 +1,1391 @@ +import "workflow-content.pkl" as workflow + +/// One canonical source for both context-sync packages. Exact shared blocks are +/// stored once; SyncRole supplies only lifecycle-specific handoff, workflow, +/// boundary, and report fragments. Each generated package remains +/// self-contained and never references its sibling package. +class SyncRole { + slug: String + title: String + skillFragments: Listing + reportFragments: Listing +} + +local skillCommon0 = """ + --- + """ + +local taskSkillRole0 = """ + name: sce-task-context-sync + """ + +local planSkillRole0 = """ + name: sce-plan-context-sync + """ + +local skillCommon1 = """ + description: > + """ + +local taskSkillRole1 = """ + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + """ + +local planSkillRole1 = """ + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + """ + +local skillCommon2 = """ + repository context, and returns a Markdown synchronization report. Invoke only + """ + +local taskSkillRole2 = """ + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. + """ + +local planSkillRole2 = """ + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. + """ + +local skillCommon3 = """ + --- + + """ + +local taskSkillRole3 = """ + # SCE Task Context Sync + """ + +local planSkillRole3 = """ + # SCE Plan Context Sync + """ + +local skillCommon4 = """ + + ## Purpose + + """ + +local taskSkillRole4 = """ + Reconcile one completed task with the repository's durable context and return a + Markdown report. + """ + +local planSkillRole4 = """ + Reconcile one fully validated plan with the repository's durable context and + return a Markdown report. + """ + +local skillCommon5 = """ + + This skill owns: + + """ + +local taskSkillRole5 = """ + - Validating the execution handoff. + """ + +local planSkillRole5 = """ + - Validating the validation handoff. + """ + +local skillCommon6 = """ + - Confirming the context root exists. + """ + +local taskSkillRole6 = """ + - Discovering the context affected by one completed task. + """ + +local planSkillRole6 = """ + - Discovering the context required by the finished plan. + """ + +local skillCommon7 = """ + - Deciding whether durable context changed. + - Editing and verifying the affected context files. + - Returning one Markdown synchronization report. + + Use the report format in: + + `references/sync-report.md` + + """ + +local planSkillRole7 = """ + Task-level context sync may already have run after individual tasks. This skill + is the plan-level final pass: it starts from the plan's `Context sync` + requirements and the validated implementation, and closes gaps that remain. + + """ + +local skillCommon8 = """ + ## Input + + The invoking workflow provides: + + """ + +local taskSkillRole8 = """ + - The complete result returned by `sce-task-execution`. + """ + +local planSkillRole8 = """ + - The complete Markdown result returned by `sce-validation`. + """ + +local skillCommon9 = """ + + """ + +local taskSkillRole9 = """ + The execution result must have: + """ + +local planSkillRole9 = """ + The validation result must report: + """ + +local skillCommon10 = """ + + """ + +local taskSkillRole10 = """ + ```yaml + status: complete + """ + +local planSkillRole10 = """ + ```markdown + **Status:** validated + **Plan:** {plan path} + """ + +local skillCommon11 = """ + ``` + + """ + +local taskSkillRole11 = """ + Treat the execution result as the authoritative handoff for: + """ + +local planSkillRole11 = """ + Treat that Markdown as the authoritative handoff for: + """ + +local skillCommon12 = """ + + """ + +local taskSkillRole12 = """ + - The resolved plan and completed task. + - Files changed by implementation. + - Implementation summary. + - Verification evidence. + - Done-check evidence. + - Reported context impact. + """ + +local planSkillRole12 = """ + - The resolved plan path. + - Validation commands and outcomes. + - Acceptance-criteria evidence. + - Scaffolding removals. + - Reported context impact, required context paths, and affected areas. + """ + +local skillCommon13 = """ + + """ + +local taskSkillRole13 = """ + This skill must not be invoked for `declined`, `blocked`, or `incomplete` + execution results. + """ + +local planSkillRole13 = """ + This skill must not be invoked for `failed` or `blocked` validation results. + Those are not success states. Same rule as `sce-task-context-sync`: context sync + runs only after a successful prior phase. + """ + +local skillCommon14 = """ + + """ + +local taskSkillRole14 = """ + Do not reconstruct a missing execution result from conversation history. + """ + +local planSkillRole14 = """ + Do not reconstruct a missing validation result from conversation history. + """ + +local skillCommon15 = """ + + ## Workflow + + """ + +local taskSkillRole15 = """ + ### 1. Validate the execution handoff + """ + +local planSkillRole15 = """ + ### 1. Validate the validation handoff + """ + +local skillCommon16 = """ + + Confirm that: + + """ + +local taskSkillRole16 = """ + - `status` is exactly `complete`. + - A `plan` object with a `path` is present. + - Exactly one completed task is identified. + - Changed files and an implementation summary are present. + - Verification evidence is present. + - Done-check evidence is present. + """ + +local planSkillRole16 = """ + - `Status:` is exactly `validated`. + - `Plan:` names an existing plan path. + - Acceptance-criteria evidence is present and every criterion is met. + - Commands run are present. + """ + +local skillCommon17 = """ + - A context-impact classification is present. + + If the handoff is missing required information or is internally contradictory, + do not modify context. Return a `blocked` Markdown report. + + ### 2. Confirm the context root + + When `context/` does not exist, there is no durable memory to synchronize. + Do not create it, and do not write context files outside it. + + Return a `blocked` report whose required action is: + + `sce setup --bootstrap-context` + + """ + +local taskSkillRole17 = """ + State that the task itself is complete and recorded in the plan, and that + synchronization should run again once the context root exists. + """ + +local planSkillRole17 = """ + State that validation itself succeeded and is recorded in the plan, and that + plan context synchronization should run again once the context root exists. + """ + +local skillCommon18 = """ + + Bootstrapping is the user's action, not this skill's. + + ### 3. Discover applicable context + + """ + +local taskSkillRole18 = """ + Start with the execution result: + """ + +local planSkillRole18 = """ + Start with the validated Markdown result: + """ + +local skillCommon19 = """ + + """ + +local taskSkillRole19 = """ + - `context_impact.classification` + - `context_impact.affected_areas` + - Changed files. + - Implementation summary. + - Done-check evidence. + """ + +local planSkillRole19 = """ + - **Context impact** classification, required context, and affected areas. + - Acceptance-criteria evidence. + - Commands run. + """ + +local skillCommon20 = """ + + """ + +local taskSkillRole20 = """ + Then inspect existing repository context in this order when present: + """ + +local planSkillRole20 = """ + Then read the plan's `Context sync` section and inspect existing repository + context in this order when present: + """ + +local skillCommon21 = """ + + """ + +local taskSkillRole21 = """ + 1. `context/context-map.md` + 2. Context files for the affected domain or subsystem + 3. `context/overview.md` + 4. `context/architecture.md` + 5. `context/glossary.md` + 6. `context/patterns.md` + 7. Operational, product, or decision records directly related to the change + """ + +local planSkillRole21 = """ + 1. Paths named by the plan's `Context sync` section + 2. `context/context-map.md` + 3. Context files for the affected domain or subsystem + 4. `context/overview.md` + 5. `context/architecture.md` + 6. `context/glossary.md` + 7. `context/patterns.md` + 8. Operational, product, or decision records directly related to the finished + change + """ + +local skillCommon22 = """ + + Use the context map and existing links to locate authoritative files. + + Do not scan or rewrite the entire `context/` tree by default. + + Do not create a new context file when an existing authoritative file can be + updated coherently. + + #### The mandatory root pass + + Every invocation verifies these five files against code truth, whatever the + reported classification is: + + - `context/overview.md` + - `context/architecture.md` + - `context/glossary.md` + - `context/patterns.md` + - `context/context-map.md` + + Verifying is not editing. A classification that warrants no root edit still + requires reading each of these and confirming it is not contradicted by the + """ + +local taskSkillRole22 = """ + completed implementation. A file that is absent is a gap; record it in the + """ + +local planSkillRole22 = """ + finished implementation. A file that is absent is a gap; record it in the + """ + +local skillCommon23 = """ + report rather than creating it to satisfy the pass. + + Report each of the five as verified or edited. Never declare synchronization + done while one of them is unchecked. + + """ + +local taskSkillRole23 = """ + Do not create a new context file when an existing authoritative file can be + updated coherently. + """ + +local planSkillRole23 = """ + #### Plan context requirements + + Every path or statement listed under the plan's `Context sync` section must be + accounted for in the report as already accurate or updated. A requirement the + finished code still does not satisfy is a blocker, not a note. + """ + +local skillCommon24 = """ + + ### 4. Determine whether durable context changed + + Use the reported context impact as a strong hint, then verify it against the + """ + +local taskSkillRole24 = """ + implementation and existing context. + """ + +local planSkillRole24 = """ + finished implementation and existing context. + """ + +local skillCommon25 = """ + + Durable context includes non-obvious repository knowledge such as: + + - User-visible or externally observable behavior. + - Architecture, boundaries, ownership, and dependency direction. + - Public interfaces, data contracts, and persistence behavior. + - Operational procedures and important failure modes. + - Security or privacy behavior. + - Shared terminology. + - Intentional limitations and meaningful design decisions. + + Do not document: + + - Details already obvious from the implementation. + - Temporary debugging information. + - A file-by-file narration of the change. + """ + +local taskSkillRole25 = """ + - Test output that belongs only in task evidence. + - Speculation or future work not established by the completed implementation. + """ + +local planSkillRole25 = """ + - Test output that belongs only in validation evidence. + - Speculation or future work not established by the finished plan. + """ + +local skillCommon26 = """ + - Generic engineering practices. + + Interpret impact classifications as follows. Each governs which files are + """ + +local taskSkillRole26 = """ + *edited*; none of them waives the mandatory root pass. + """ + +local planSkillRole26 = """ + *edited*; none of them waives the mandatory root pass or the plan's Context + sync requirements. + """ + +local skillCommon27 = """ + + """ + +local taskSkillRole27 = """ + - `none`: Make no edits beyond any correction the root pass turns up. + """ + +local planSkillRole27 = """ + - `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. + """ + +local skillCommon28 = """ + - `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. + - `domain`: Update affected domain context and the context map when its links or + summaries changed. + - `root`: Update the relevant root context and any affected domain context. + """ + +local taskSkillRole28 = """ + + A change is `root` when it introduces cross-cutting behavior, repository-wide + policy or contracts, an architecture or ownership boundary, or a change to + canonical terminology. A change confined to one feature or domain, with no + repository-wide behavior, architecture, or terminology impact, is `domain` or + `local`: capture its detail in domain files and leave the root files unedited. + """ + +local skillCommon29 = """ + + If the reported classification is inconsistent with the actual change, use the + verified classification and explain the difference in the report. + + ### 5. Synchronize context + + Make the smallest coherent documentation change that preserves repository truth. + + When editing context: + + """ + +local taskSkillRole29 = """ + - Describe the resulting behavior, not the implementation session. + """ + +local planSkillRole29 = """ + - Describe the resulting behavior, not the validation session. + """ + +local skillCommon30 = """ + - Preserve repository terminology and document structure. + """ + +local taskSkillRole30 = """ + - Remove or correct statements contradicted by the completed implementation. + """ + +local planSkillRole30 = """ + - Remove or correct statements contradicted by the finished implementation. + """ + +local skillCommon31 = """ + - Update cross-references when files are added, moved, renamed, or superseded. + - Keep one authoritative statement for each durable fact. + """ + +local taskSkillRole31 = """ + - Avoid copying the execution result verbatim into context files. + - Do not change application code, tests, or plan state. + """ + +local planSkillRole31 = """ + - Avoid copying the validation result verbatim into context files. + - Do not change application code, tests, or plan validation evidence. + """ + +local skillCommon32 = """ + + Create a new context file only when: + + - The knowledge is durable and non-obvious. + - No existing file owns it coherently. + - The new file has a clear place in the context map. + + #### Feature existence + + """ + +local taskSkillRole32 = """ + Every feature the completed task implemented must have at least one durable + """ + +local planSkillRole32 = """ + Every feature the finished plan implemented must have at least one durable + """ + +local skillCommon33 = """ + canonical description discoverable from `context/`, in a domain file under + `context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + + """ + +local taskSkillRole33 = """ + When the task implemented a feature no context file describes, add that + description. A feature that fits no existing domain file gets a new focused + file; do not defer it to a later task. Prefer a small, precise domain file over + overloading `overview.md` with detail. + """ + +local planSkillRole33 = """ + When the plan delivered a feature no context file describes, add that + description. Prefer a small, precise domain file over overloading + `overview.md` with detail. + """ + +local skillCommon34 = """ + + """ + +local taskSkillRole34 = """ + This is the one case where documentation is warranted by the change itself + rather than by a gap in durable knowledge. It is not license to narrate the + diff: describe what the feature is and how it behaves, not what was edited. + """ + +local planSkillRole34 = """ + This is not license to narrate the diff: describe what the feature is and how + it behaves, not what was edited during the plan. + """ + +local skillCommon35 = """ + + #### Glossary + + """ + +local taskSkillRole35 = """ + Add a `context/glossary.md` entry for any domain language the task introduced. + New terminology is durable knowledge whatever the classification is: a `domain` + change that names a new concept still earns its glossary entry. + """ + +local planSkillRole35 = """ + Add a `context/glossary.md` entry for any domain language the plan introduced. + New terminology is durable knowledge whatever the classification is. + """ + +local skillCommon36 = """ + + #### File hygiene + + Every context file this skill writes must satisfy: + + - One topic per file. + - At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. + - Relative paths in every link to another context file. + - A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. + - Concrete code examples only where they clarify non-trivial behavior. + + When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a + concise pointer behind, and link the new file from `context/context-map.md`. + + ### 6. Verify synchronization + + After edits, verify: + + """ + +local taskSkillRole36 = """ + - Every changed context file accurately reflects the completed implementation. + - No edited statement contradicts the code, plan, or execution evidence. + """ + +local planSkillRole36 = """ + - Every changed context file accurately reflects the finished implementation. + - No edited statement contradicts the code, plan, or validation evidence. + """ + +local skillCommon37 = """ + - Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. + """ + +local taskSkillRole37 = """ + - Each feature implemented by the task has a durable canonical description + """ + +local planSkillRole37 = """ + - Every plan `Context sync` requirement is met. + - Each feature implemented by the plan has a durable canonical description + """ + +local skillCommon38 = """ + reachable from `context/`. + - Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. + - Diagrams are present where structure, boundaries, or flows are complex. + - Links and referenced paths resolve when practical to check. + - New context files are reachable from the context map or another authoritative + index. + - Root context remains concise and delegates details to domain files. + - Unrelated context was not changed. + + Use focused documentation, link, or formatting checks when available. + + """ + +local taskSkillRole38 = """ + Do not run full application or plan validation. + """ + +local planSkillRole38 = """ + Do not rerun full-plan validation. + """ + +local skillCommon39 = """ + + If synchronization cannot be completed without inventing facts or resolving a + material contradiction, preserve safe edits when appropriate and return a + `blocked` report. + + ### 7. Return the Markdown report + + Return exactly one report status: + + - `synced` + - `no_context_change` + - `blocked` + + `synced` means context files were updated and verified. `no_context_change` + means existing context was checked and no edit was warranted. `blocked` means + context could not be synchronized safely. + + Return only the Markdown report. Do not add explanatory prose before or after + it. + + """ + +local taskSkillRole39 = """ + Do not determine whether the plan is complete. The invoking `/next-task` + workflow owns that decision after context synchronization. + + """ + +local skillCommon40 = """ + ## Boundaries + + Do not: + + """ + +local taskSkillRole40 = """ + - Accept an execution result whose status is not `complete`. + """ + +local planSkillRole40 = """ + - Accept a validation result whose status is not `validated`. + - Accept `failed` or `blocked` validation results. + """ + +local skillCommon41 = """ + - Implement or modify application code. + - Modify tests. + """ + +local taskSkillRole41 = """ + - Change task completion status or plan evidence. + - Determine whether the plan is complete. + - Select or execute another task. + - Run full-plan validation. + - Mark the plan validated, closed, or archived. + """ + +local planSkillRole41 = """ + - Change task completion status, acceptance-criteria marks, or the Validation + Report. + - Rerun full-plan validation. + - Select or execute an implementation task. + """ + +local skillCommon42 = """ + - Create a Git commit or push changes. + - Create the context root. `sce setup --bootstrap-context` owns that. + - Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. + - Delete a context file that has uncommitted changes. + """ + +local taskSkillRole42 = """ + - Return an execution-style YAML result. + """ + +local planSkillRole42 = """ + - Return YAML. + """ + +local skillCommon43 = """ + + ## Completion + + The skill is complete after: + + - The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. + - The mandatory root pass was run. + """ + +local planSkillRole43 = """ + - Plan context requirements were checked. + """ + +local skillCommon44 = """ + - Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. + - One Markdown report matching `references/sync-report.md` was returned. + """ + +local taskReportRole0 = """ + # Context Sync Report + """ + +local planReportRole0 = """ + # Plan Context Sync Report + """ + +local reportCommon0 = """ + + Return only one completed Markdown report using the applicable variant below. + Do not include unused sections, placeholders, YAML, or a fenced code block. + + The `Status` value must be exactly one of: + + - `synced` + - `no_context_change` + - `blocked` + + """ + +local taskReportRole1 = """ + The input execution status is always `complete` and does not need to be repeated + as a separate workflow state. + """ + +local planReportRole1 = """ + The input validation status is always `validated` and does not need to be + repeated as a separate workflow state. This skill is not invoked for `failed` + or `blocked` validation results. + """ + +local reportCommon1 = """ + + ## Synced variant + + """ + +local taskReportRole2 = """ + # Context Sync Report + """ + +local planReportRole2 = """ + # Plan Context Sync Report + """ + +local reportCommon2 = """ + + **Status:** synced\(" ") + """ + +local taskReportRole3 = """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` + """ + +local planReportRole3 = """ + **Plan:** `{plan path}` + """ + +local reportCommon3 = """ + + ## Context impact + + **Classification:** `{local | domain | root}`\(" ") + **Affected areas:** `{comma-separated areas}` + + {Explain which durable behavior, architecture, terminology, operation, or + """ + +local taskReportRole4 = """ + constraint required synchronization.} + """ + +local planReportRole4 = """ + constraint required plan-level synchronization after validation.} + + ## Plan context requirements + + - `{required context path or statement from the plan}` — {met by edit | already accurate} + """ + +local reportCommon4 = """ + + ## Updated context + + - `{context file}` — {concise description of the durable truth updated} + + ## Root pass + + - `context/overview.md` — {verified | edited | absent} + - `context/architecture.md` — {verified | edited | absent} + - `context/glossary.md` — {verified | edited | absent} + - `context/patterns.md` — {verified | edited | absent} + - `context/context-map.md` — {verified | edited | absent} + + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}` + + ## Verification + + """ + +local taskReportRole5 = """ + - {How the edited context was checked against implementation and execution evidence.} + """ + +local planReportRole5 = """ + - {How the edited context was checked against the finished implementation and validation evidence.} + """ + +local reportCommon5 = """ + - {File hygiene: line counts, relative links, diagrams where structure is complex.} + - {Documentation, link, or formatting checks that were run, when applicable.} + + ## Notes + + {Include only non-blocking information the invoking workflow should retain. + Omit this section when unnecessary.} + + --- + + ## No-context-change variant + + """ + +local taskReportRole6 = """ + # Context Sync Report + """ + +local planReportRole6 = """ + # Plan Context Sync Report + """ + +local reportCommon6 = """ + + **Status:** no_context_change\(" ") + """ + +local taskReportRole7 = """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` + """ + +local planReportRole7 = """ + **Plan:** `{plan path}` + """ + +local reportCommon7 = """ + + ## Context impact + + **Classification:** none + + """ + +local taskReportRole8 = """ + {Explain why the completed implementation did not introduce durable, + non-obvious repository knowledge requiring an update.} + """ + +local planReportRole8 = """ + {Explain why the finished plan introduced no durable, non-obvious repository + knowledge requiring an update, or why existing context already matched.} + + ## Plan context requirements + + - `{required context path or statement from the plan}` — already accurate + - None listed by the plan. + """ + +local reportCommon8 = """ + + ## Context reviewed + + - `{context file or area}` — {what was checked and why it remains accurate} + + ## Root pass + + - `context/overview.md` — {verified | absent} + - `context/architecture.md` — {verified | absent} + - `context/glossary.md` — {verified | absent} + - `context/patterns.md` — {verified | absent} + - `context/context-map.md` — {verified | absent} + + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}`, already present. + + ## Verification + + """ + +local taskReportRole9 = """ + - {How existing context was compared with implementation and execution evidence.} + """ + +local planReportRole9 = """ + - {How existing context was compared with the finished implementation and validation evidence.} + """ + +local reportCommon9 = """ + + --- + + ## Blocked variant + + """ + +local taskReportRole10 = """ + # Context Sync Report + """ + +local planReportRole10 = """ + # Plan Context Sync Report + """ + +local reportCommon10 = """ + + **Status:** blocked\(" ") + """ + +local taskReportRole11 = """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` + """ + +local planReportRole11 = """ + **Plan:** `{plan path}` + """ + +local reportCommon11 = """ + + ## Blocker + + **Problem:** {specific synchronization blocker}\(" ") + **Impact:** {why context cannot be made authoritative safely}\(" ") + **Required action:** {decision or correction required} + + ## Context changes + + - {List safe context edits preserved, or state `No context files were changed.`} + + ## Retry condition + + """ + +local taskReportRole12 = """ + {State the concrete condition under which context synchronization should run + again.} + """ + +local planReportRole12 = """ + {State the concrete condition under which plan context synchronization should + run again.} + """ + +local reportCommon12 = """ + + ## Report rules + + - Name exact context files when they were changed or reviewed. + """ + +local taskReportRole13 = """ + - Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. + """ + +local planReportRole13 = """ + - Report every file in the root pass, including any that is absent. + """ + +local reportCommon13 = """ + - Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. + """ + +local taskReportRole14 = """ + - Omit **Feature existence** only when the task implemented no feature. + - Describe durable truth, not implementation-session chronology. + """ + +local planReportRole14 = """ + - Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. + - Omit **Feature existence** only when the plan implemented no feature. + - Describe durable truth, not validation-session chronology. + """ + +local reportCommon14 = """ + - Keep evidence concise and factual. + """ + +local taskReportRole15 = """ + - Do not claim final validation passed. + - Do not determine whether the plan is complete. + - Do not recommend a next implementation task. + """ + +local planReportRole15 = """ + - Do not claim implementation tasks remain open. + - Do not reopen validation checks. + - Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. + """ + +local taskRole = new SyncRole { + slug = "sce-task-context-sync" + title = "SCE Task Context Sync" + skillFragments = new Listing { + skillCommon0 + taskSkillRole0 + skillCommon1 + taskSkillRole1 + skillCommon2 + taskSkillRole2 + skillCommon3 + taskSkillRole3 + skillCommon4 + taskSkillRole4 + skillCommon5 + taskSkillRole5 + skillCommon6 + taskSkillRole6 + skillCommon7 + skillCommon8 + taskSkillRole8 + skillCommon9 + taskSkillRole9 + skillCommon10 + taskSkillRole10 + skillCommon11 + taskSkillRole11 + skillCommon12 + taskSkillRole12 + skillCommon13 + taskSkillRole13 + skillCommon14 + taskSkillRole14 + skillCommon15 + taskSkillRole15 + skillCommon16 + taskSkillRole16 + skillCommon17 + taskSkillRole17 + skillCommon18 + taskSkillRole18 + skillCommon19 + taskSkillRole19 + skillCommon20 + taskSkillRole20 + skillCommon21 + taskSkillRole21 + skillCommon22 + taskSkillRole22 + skillCommon23 + taskSkillRole23 + skillCommon24 + taskSkillRole24 + skillCommon25 + taskSkillRole25 + skillCommon26 + taskSkillRole26 + skillCommon27 + taskSkillRole27 + skillCommon28 + taskSkillRole28 + skillCommon29 + taskSkillRole29 + skillCommon30 + taskSkillRole30 + skillCommon31 + taskSkillRole31 + skillCommon32 + taskSkillRole32 + skillCommon33 + taskSkillRole33 + skillCommon34 + taskSkillRole34 + skillCommon35 + taskSkillRole35 + skillCommon36 + taskSkillRole36 + skillCommon37 + taskSkillRole37 + skillCommon38 + taskSkillRole38 + skillCommon39 + taskSkillRole39 + skillCommon40 + taskSkillRole40 + skillCommon41 + taskSkillRole41 + skillCommon42 + taskSkillRole42 + skillCommon43 + skillCommon44 + } + reportFragments = new Listing { + taskReportRole0 + reportCommon0 + taskReportRole1 + reportCommon1 + taskReportRole2 + reportCommon2 + taskReportRole3 + reportCommon3 + taskReportRole4 + reportCommon4 + taskReportRole5 + reportCommon5 + taskReportRole6 + reportCommon6 + taskReportRole7 + reportCommon7 + taskReportRole8 + reportCommon8 + taskReportRole9 + reportCommon9 + taskReportRole10 + reportCommon10 + taskReportRole11 + reportCommon11 + taskReportRole12 + reportCommon12 + taskReportRole13 + reportCommon13 + taskReportRole14 + reportCommon14 + taskReportRole15 + } +} + +local planRole = new SyncRole { + slug = "sce-plan-context-sync" + title = "SCE Plan Context Sync" + skillFragments = new Listing { + skillCommon0 + planSkillRole0 + skillCommon1 + planSkillRole1 + skillCommon2 + planSkillRole2 + skillCommon3 + planSkillRole3 + skillCommon4 + planSkillRole4 + skillCommon5 + planSkillRole5 + skillCommon6 + planSkillRole6 + skillCommon7 + planSkillRole7 + skillCommon8 + planSkillRole8 + skillCommon9 + planSkillRole9 + skillCommon10 + planSkillRole10 + skillCommon11 + planSkillRole11 + skillCommon12 + planSkillRole12 + skillCommon13 + planSkillRole13 + skillCommon14 + planSkillRole14 + skillCommon15 + planSkillRole15 + skillCommon16 + planSkillRole16 + skillCommon17 + planSkillRole17 + skillCommon18 + planSkillRole18 + skillCommon19 + planSkillRole19 + skillCommon20 + planSkillRole20 + skillCommon21 + planSkillRole21 + skillCommon22 + planSkillRole22 + skillCommon23 + planSkillRole23 + skillCommon24 + planSkillRole24 + skillCommon25 + planSkillRole25 + skillCommon26 + planSkillRole26 + skillCommon27 + planSkillRole27 + skillCommon28 + skillCommon29 + planSkillRole29 + skillCommon30 + planSkillRole30 + skillCommon31 + planSkillRole31 + skillCommon32 + planSkillRole32 + skillCommon33 + planSkillRole33 + skillCommon34 + planSkillRole34 + skillCommon35 + planSkillRole35 + skillCommon36 + planSkillRole36 + skillCommon37 + planSkillRole37 + skillCommon38 + planSkillRole38 + skillCommon39 + skillCommon40 + planSkillRole40 + skillCommon41 + planSkillRole41 + skillCommon42 + planSkillRole42 + skillCommon43 + planSkillRole43 + skillCommon44 + } + reportFragments = new Listing { + planReportRole0 + reportCommon0 + planReportRole1 + reportCommon1 + planReportRole2 + reportCommon2 + planReportRole3 + reportCommon3 + planReportRole4 + reportCommon4 + planReportRole5 + reportCommon5 + planReportRole6 + reportCommon6 + planReportRole7 + reportCommon7 + planReportRole8 + reportCommon8 + planReportRole9 + reportCommon9 + planReportRole10 + reportCommon10 + planReportRole11 + reportCommon11 + planReportRole12 + reportCommon12 + planReportRole13 + reportCommon13 + planReportRole14 + reportCommon14 + planReportRole15 + } +} + +local documentMapping = (documents: Listing) -> new Mapping { + for (document in documents) { + [document.path] = document + } +} + +/// Shared materialization skeleton parameterized by lifecycle role. +local packageFor = (role: SyncRole) -> new workflow.SkillPackage { + slug = role.slug + title = role.title + documents = documentMapping.apply(new Listing { + new workflow.WorkflowDocument { + path = "SKILL.md" + text = role.skillFragments.join("\n") + } + new workflow.WorkflowDocument { + path = "references/sync-report.md" + text = role.reportFragments.join("\n") + } + }) +} + +local taskPackage = packageFor.apply(taskRole) +local planPackage = packageFor.apply(planRole) + +skills = new Mapping { + [taskRole.slug] = taskPackage + [planRole.slug] = planPackage +} diff --git a/config/pkl/base/workflow-next-task.pkl b/config/pkl/base/workflow-next-task.pkl new file mode 100644 index 00000000..e0876701 --- /dev/null +++ b/config/pkl/base/workflow-next-task.pkl @@ -0,0 +1,1274 @@ +import "workflow-content.pkl" as model +import "workflow-context-sync.pkl" as contextSync + +/// Canonical `/next-task` workflow command and its self-contained skill +/// packages. Text mirrors the project-root `.pi/` behavioral baseline; target +/// renderers consume this model in later workflow-rendering tasks. + +local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { + path = documentPath + text = documentText +} + +local packageDocuments = (documents: Listing) -> new Mapping { + for (item in documents) { + [item.path] = item + } +} + +local planReviewPackage = new model.SkillPackage { + slug = "sce-plan-review" + title = "SCE Plan Review" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", REVIEW_SKILL) + makeDocument.apply("references/readiness-contract.yaml", READINESS_CONTRACT) + }) +} + +local taskExecutionPackage = new model.SkillPackage { + slug = "sce-task-execution" + title = "SCE Task Execution" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", EXECUTION_SKILL) + makeDocument.apply("references/execution-contract.yaml", EXECUTION_CONTRACT) + makeDocument.apply("references/implementation-gate.md", IMPLEMENTATION_GATE) + }) +} + +local COMMAND = """ + --- + description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" + argument-hint: " [T0X] [approved]" + --- + + SCE NEXT TASK `$ARGUMENTS` + + ## Input + + Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + + - `plan-name-or-path` is required. + - `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). + - `auto-approve` is optional. It is present only when the token is exactly `approved`. + + Resolve `auto-approve` even when `task-id` is absent. + + A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + + Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + + Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + + ## Workflow + + ### 1. Review the task + + Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + + Do not pass the `auto-approve` token to `sce-plan-review`. + + The skill must return a result matching its readiness contract. + + Branch on `status`: + + `blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + + When `candidates` is present, the plan could not be resolved. Present: + + - The problem reported by the review. + - The candidate plan paths. + - `/next-task {candidate-path}` for the intended plan. + + Otherwise one plan and task were resolved. Present: + + - The task ID and title. + - Each issue in `issues`: its problem, its impact, and the decision it requires. + - When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. + - When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + + `plan_complete` -> Return: + + ``` + + ------------------------------------- + + # Implementation tasks are complete. + + Run the final validation: + + `/validate {plan-path}` + ``` + + Stop. + + `ready` -> Pass the complete readiness result to `sce-task-execution`. + + Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + + ### 2. Execute the task + + Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + + Branch on `auto-approve`: + + `approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + + else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + + `sce-task-execution` exclusively owns: + + - Presenting the implementation summary. + - Requesting implementation confirmation. + - Implementing the task. + - Running task-level verification. + - Updating the task status and evidence. + + Do not present an additional implementation confirmation. + + Branch on the execution result. + + `declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + + `blocked` -> Present: + + - The blocker. + - Work completed before the blocker. + - The decision or action required. + + Do not invoke context synchronization. Stop. + + `incomplete` -> Present: + + - Work completed. + - Verification evidence. + - Remaining work. + - The reason the task is incomplete. + + Do not invoke context synchronization. Do not select another task. Stop. + + `complete` -> continue to the next step. + + ### 3. Synchronize context + + Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + + Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + + Do not restate, summarize, or reconstruct any part of the execution result. + + Branch on the synchronization result. + + `blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + + - That task {completed-task-id} was implemented, verified, and recorded in the plan. + - The context contradiction or synchronization failure. + - Any context edits the report says were preserved. + - The action required to resolve the problem. + - The retry condition stated by the report. + + State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + + Do not select another task. Stop. + + `synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + + ### 4. Determine the continuation + + Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + + Do not execute another task. Return exactly one continuation. + + If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + + Return: + + ``` + + ------------------------------------- + + # Task {completed-task-id} completed. + + {completed-tasks} of {total-tasks} tasks complete. + + Next up: + + {next-task-id} — {next-task-title} + + `/next-task {plan-path} {next-task-id}` + ``` + + If all tasks are completed return: + + ``` + + ------------------------------------- + + # Task {completed-task-id} completed. + + All tasks are complete. + + Run the final validation: + + `/validate {plan-path}` + ``` + + Stop. + + ## Rules + + - Execute at most one plan task per invocation. + - Review at most one task. + - Do not duplicate the internal instructions of invoked skills. + - Do not ask for implementation confirmation outside "sce-task-execution". + - Do not run full-plan validation. + - Do not mark the plan complete. + - Do not execute the continuation returned at the end. + - Do not infer success when an invoked skill returns a non-success status. + - Preserve completed work and evidence when a later phase fails. + """ + +local REVIEW_SKILL = """ + --- + name: sce-plan-review + description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. + --- + + # SCE Plan Review + + ## Purpose + + Resolve exactly one task from an SCE plan (located in `context/plans/`) and + determine whether it can enter the implementation phase without inventing + material requirements. + + This skill owns: + + - Resolving one plan. + - Selecting at most one task. + - Inspecting the context needed to judge readiness. + - Determining readiness. + - Returning one structured readiness result. + + Return a result matching: + + `references/readiness-contract.yaml` + + ## Input + + The invoking workflow provides: + + - A plan name or path. + - An optional task ID. + + ## Workflow + + ### 1. Resolve the plan + + Resolve the supplied plan name or path to exactly one existing plan. + + When no plan can be found, return `blocked`. + + When multiple plans match and none can be selected safely, return `blocked` with + the matching candidates. + + Read the selected plan before exploring the repository. + + ### 2. Resolve one task + + When a task ID is supplied, select that task. + + Otherwise, select the first incomplete task in plan order whose declared + dependencies are complete. + + Return `plan_complete` when no incomplete tasks remain. + + Return `blocked` when incomplete tasks remain but none can currently be + executed. + + Review at most one task per invocation. + + ### 3. Inspect relevant context + + Start with the task and the files it directly references. + + Inspect only what is needed to understand: + + - Existing behavior. + - Applicable repository conventions. + - Architectural boundaries. + - Relevant tests. + - Available verification commands. + - Decisions or specifications connected to the task. + + Load root context only when the task affects repository-wide behavior, + architecture, shared terminology, or cross-domain interfaces. + + Do not explore the entire repository by default. + + ### 4. Determine readiness + + A task is `ready` when: + + - Its goal is clear. + - Its scope is sufficiently bounded. + - Its dependencies are complete. + - Its done checks are observable. + - A credible verification method exists. + - No unresolved decision would materially change the implementation. + + Use repository conventions for ordinary local choices. + + Do not block on: + + - Naming inferable from surrounding code. + - Established formatting or style. + - Reversible local implementation details. + - Details that do not change observable behavior or scope. + + Record these choices under `assumptions`. + + Return `blocked` when a missing decision materially affects: + + - User-visible behavior. + - Public interfaces. + - Architecture or ownership boundaries. + - Data shape or persistence. + - Security or privacy. + - External dependencies. + - Destructive or difficult-to-reverse behavior. + - The evidence needed to prove completion. + + ### 5. Return the result + + Return exactly one structured result: + + - `ready` + - `blocked` + - `plan_complete` + + Return only the structured result. Do not add explanatory prose before or after + it. + + ## Boundaries + + Do not: + + - Modify application code. + - Modify tests. + - Update the plan. + - Mark the task complete. + - Request implementation confirmation. + - Invoke task execution. + - Synchronize context. + - Run final validation. + - Review more than one task. + + ## Completion + + The skill is complete after: + + - One plan was resolved. + - At most one task was resolved. + - One valid readiness result matching `references/readiness-contract.yaml` was + returned. + """ + +local READINESS_CONTRACT = """ + version: 1 + name: sce-plan-review-result + + description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + + output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + + variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 + """ + +local EXECUTION_SKILL = """ + --- + name: sce-task-execution + description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. + --- + + # SCE Task Execution + + ## Purpose + + Execute exactly one reviewed SCE plan task (located in `context/plans/`). + + This skill owns: + + - Showing the implementation gate at the start of every invocation. + - Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. + - Implementing one approved task. + - Running task-level verification. + - Updating that task and its evidence in the plan. + - Returning one terminal YAML result. + + Use the gate defined in: + + `references/implementation-gate.md` + + Return a final result matching: + + `references/execution-contract.yaml` + + ## Input + + The invoking workflow provides: + + - The complete `ready` result from `sce-plan-review`. + - An optional `approve` flag. + + The `approve` flag means the user pre-approved this task when invoking the + workflow. It suppresses the approval question and the wait. It never suppresses + the gate. Only the invoking workflow may set it, and only from an explicit + user-supplied approval token. Never infer it. + + The readiness result must identify: + + - One resolved plan. + - Exactly one incomplete task. + - The task goal and scope boundaries. + - Done checks. + - Verification expectations. + - Relevant files and context. + - Review assumptions. + + If required handoff information is absent or stale, still show the gate using + what is known, clearly identify the handoff problem, and do not edit files. + After the user responds, return `blocked`. + + ## Workflow + + ### 1. Validate the handoff without editing + + Confirm that: + + - The readiness status is `ready`. + - Exactly one task is present. + - The plan file exists. + - The selected task is still incomplete. + - The task has not materially changed since review. + - Declared dependencies remain complete. + + Do not reconstruct missing material requirements. + + ### 2. Always show the implementation gate + + At the start of the skill, before any file modification, present the task using + `references/implementation-gate.md`. + + The gate must be shown even when: + + - The task appears straightforward. + - The invoking workflow believes approval was already implied. + - The handoff is stale or incomplete. + - The user is likely to approve. + + When the `approve` flag is absent, end the gate with exactly one approval + question: + + `Continue with implementation now? (yes/no)` + + Stop and wait for the user's answer. Do not return YAML, and make no file + modifications, until the user has answered. + + When the `approve` flag is supplied, show the gate as a summary, omit the + approval question, do not wait, and continue at *Prepare the implementation*. + + ### 3. Handle the user's decision + + Skip this step when the `approve` flag was supplied. + + When the user rejects or cancels, do not modify files and return `declined`. + + When the user does not clearly approve, do not modify files. Ask the same + approval question once more only when the response is genuinely ambiguous. + Otherwise return `blocked`. + + When the user approves, continue with implementation. + + Treat constraints supplied with approval as part of the approved task boundary. + If those constraints materially contradict the reviewed task, return `blocked` + before editing. + + ### 4. Prepare the implementation + + Before editing: + + - Read the relevant files supplied by plan review. + - Inspect nearby code and tests when needed. + - Identify the smallest coherent change satisfying the task. + - Follow surrounding naming, structure, error handling, and test style. + - Preserve unrelated behavior. + + Do not create a second plan. + + Do not broaden the reviewed task. + + ### 5. Implement one task + + Make the minimum coherent changes required to satisfy the task goal and done + checks. + + Use judgment for ordinary, reversible local implementation choices. + + Stop when implementation requires: + + - Material scope expansion. + - A new external dependency not authorized by the task. + - A public-interface decision not established by the plan. + - A destructive or difficult-to-reverse operation. + - An unresolved security, privacy, or data decision. + - Contradicting the reviewed task or repository architecture. + + When stopped, preserve completed in-scope work unless retaining it would leave + the repository unsafe or invalid. + + ### 6. Verify the task + + Run the narrowest authoritative checks that demonstrate the done checks. + + Start with verification supplied by the readiness result. Add nearby or directly + relevant checks only when needed. + + Verification may include: + + - Targeted tests. + - Type checking for affected code. + - Linting affected files. + - Formatting checks. + - A focused build or compile step. + - Direct behavioral inspection when no automated check exists. + + Do not run final plan validation unless the task itself explicitly requires it. + + When a check fails: + + - Determine whether the task caused the failure. + - Fix it when the correction remains in scope. + - Rerun the relevant check. + - Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + + Never report a check as passed unless it ran successfully. + + ### 7. Update the plan + + Only after successful implementation and task-level verification: + + - Mark only the selected task complete. + - Record concise implementation evidence. + - Record verification commands and outcomes. + - Record material deviations or approved assumptions. + - Preserve the plan's existing structure and terminology. + + Do not mark the task complete when returning `declined`, `blocked`, or + `incomplete`. + + ### 8. Determine the terminal status + + Return `complete` when the task was implemented, verified, and marked complete + in the plan with evidence. + + Return `incomplete` when in-scope work was completed but one or more done checks + remain unsatisfied. + + Return `declined` when the user rejected implementation. + + Return `blocked` for every other non-successful outcome, including: + + - Missing approval. + - Stale or invalid handoff. + - Material blocker. + - A verification failure that cannot be resolved in scope. + + Use a blocker category defined by `references/execution-contract.yaml`. + + Do not determine whether the plan is complete. The invoking `/next-task` + workflow owns that decision after context synchronization. + + ### 9. Return YAML + + After the skill reaches a terminal state, return exactly one YAML document + matching `references/execution-contract.yaml`. + + Return only the YAML document. Do not add explanatory prose before or after it. + + ## Boundaries + + Do not: + + - Edit before approval, whether explicit or pre-supplied. + - Execute more than one task. + - Select or execute the next task. + - Skip the implementation gate. + - Ask for multiple approval gates for the same unchanged task. + - Expand scope without authorization. + - Synchronize durable context. + - Run final plan validation. + - Determine whether the plan is complete. + - Create a Git commit. + - Push changes. + - Modify unrelated files. + - Claim verification that was not performed. + + ## Completion + + The skill is complete after: + + - The implementation gate was shown. + - The user approved or rejected the task, or approval was pre-supplied. + - At most one task was executed. + - One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. + """ + +local EXECUTION_CONTRACT = """ + version: 1 + name: sce-task-execution-result + + description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + + output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + + variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. + """ + +local IMPLEMENTATION_GATE = """ + # Implementation gate + + Always show this gate at the start of `sce-task-execution`, before editing any + file. + + The gate is user-facing prose. It is never serialized into a YAML result. This + file is the only authority for the gate's content and order. + + ## Format + + # `{task.id} - {task.title} - {plan.name}` + + ## Goal + + {task.goal} + + ## In scope + + - {task.in_scope} + + ## Out of scope + + - {task.out_of_scope} + + ## Done when + + - {task.done_checks} + + ## Expected changes + + - List confirmed files or areas expected to change. + - Label uncertain entries as likely rather than confirmed. + + ## Approach + + Describe the smallest coherent implementation approach in 2–5 steps. + + ## Assumptions + + - Include material assumptions returned by plan review. + - Omit this section when there are no assumptions. + + ## Risks or trade-offs + + - Include only risks relevant to approving this task. + - Omit this section when there are no meaningful risks. + + ## Verification + + - {task.verification} + + When the `approve` flag is absent, end with exactly: + + `Continue with implementation now? (yes/no)` + + When the `approve` flag is supplied, omit the question and end after + **Verification**. + + ## Rules + + - Show the gate exactly once for an unchanged task. + - Do not modify files before approval. + - Do not add requirements absent from the reviewed task. + - Do not present multiple competing approaches unless a material decision is + required. + - Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. + - If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. + """ + +workflow = new model.WorkflowPackage { + slug = "next-task" + command = new model.WorkflowCommand { + slug = "next-task" + title = "SCE Next Task" + document = makeDocument.apply("next-task.md", COMMAND) + } + skills = new Mapping { + [planReviewPackage.slug] = planReviewPackage + [taskExecutionPackage.slug] = taskExecutionPackage + ["sce-task-context-sync"] = contextSync.skills["sce-task-context-sync"] + } +} diff --git a/config/pkl/base/workflow-validate.pkl b/config/pkl/base/workflow-validate.pkl new file mode 100644 index 00000000..9bf49011 --- /dev/null +++ b/config/pkl/base/workflow-validate.pkl @@ -0,0 +1,655 @@ +import "workflow-content.pkl" as model +import "workflow-context-sync.pkl" as contextSync + +/// Canonical `/validate` workflow command and its self-contained skill +/// packages. Text mirrors the project-root `.pi/` behavioral baseline; target +/// renderers consume this model in later workflow-rendering tasks. + +local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { + path = documentPath + text = documentText +} + +local packageDocuments = (documents: Listing) -> new Mapping { + for (item in documents) { + [item.path] = item + } +} + +local validationPackage = new model.SkillPackage { + slug = "sce-validation" + title = "SCE Validation" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", VALIDATION_SKILL) + makeDocument.apply("references/validation-report.md", VALIDATION_REPORT) + makeDocument.apply("references/validation-result.md", VALIDATION_RESULT) + }) +} + +local COMMAND = """ + --- + description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" + argument-hint: "" + --- + + SCE VALIDATE `$ARGUMENTS` + + ## Input + + `$ARGUMENTS` is the plan name or plan path. + + - The plan name or path is required. + - Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + + When `$ARGUMENTS` is empty, report that a plan name or path is required, state + the expected argument, and stop. Do not infer the plan from repository state or + the conversation. + + Pass the plan name or path to `sce-validation` unmodified. Do not restate, + summarize, or pre-scope it. + + Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is + the path carried by `sce-validation` in its Markdown result (`Plan:`, or a + candidate path), so every emitted command is directly runnable. + + ## Workflow + + ### 1. Validate the plan + + Invoke `sce-validation` with the plan name or path. + + `sce-validation` exclusively owns: + + - Resolving one plan. + - Confirming every implementation task is complete. + - Running full validation and acceptance-criteria checks. + - Removing temporary scaffolding. + - Writing the Validation Report into the plan. + - Returning one Markdown validation result. + + Do not duplicate any of it. Do not write the Validation Report yourself. + + The skill must return a Markdown result matching its validation-result contract. + Branch on the report's `Status:`. + + `blocked` -> Do not invoke context synchronization. Print the blocked Markdown + report as returned. Do not rephrase it into a different layout. Stop. + + `failed` -> Do not invoke context synchronization. Print the failed Markdown + report as returned. It is already a session handoff: self-contained, actionable, + and ending with `/validate {plan-path}` after repairs. + + Do not rewrite it into a shorter summary. Do not drop the retry command. Do not + add an alternate continuation that replaces `/validate`. + + Stop. Do not mark the plan finished. Do not continue to context synchronization. + Do not start the repair work in this workflow unless the user explicitly asks + to continue here; the default is that the handoff can leave this session. + + `validated` -> Pass the complete validated Markdown result to + `sce-plan-context-sync`. + + Do not reconstruct, summarize, or reinterpret the validation result before + passing it. + + ### 2. Synchronize plan context + + Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result + from `sce-validation`. + + Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not + success states. + + Pass the validated result verbatim. It is the authoritative handoff, and + `sce-plan-context-sync` owns reading the plan path, required context paths, + validation evidence, and reported context impact out of it. + + Do not restate, summarize, or reconstruct any part of the validation result. + + Branch on the synchronization result. + + `blocked` -> Validation itself succeeded and is already recorded in the plan. + Present: + + - That plan `{plan-path}` passed final validation and its Validation Report is + written. + - The context contradiction or synchronization failure. + - Any context edits the report says were preserved. + - The action required to resolve the problem. + - The retry condition stated by the report. + + State that durable context is now out of date relative to the validated + implementation, and that plan context synchronization must be resolved before + treating the plan as fully closed. Nothing records the skipped synchronization, + so it is lost once this session ends. + + Stop. + + `synced` | `no_context_change` -> Print out the report + `sce-plan-context-sync` returned. Continue to the next step. + + ### 3. Report completion + + Return exactly one completion block. Do not start another workflow. + + ``` + + ------------------------------------- + + # Plan {plan-name} validated. + + All implementation tasks were already complete. + Final validation passed. + Durable context is synchronized. + + Validation report: {plan-path} + ``` + + When the synchronization status was `no_context_change`, keep the same + completion block. "Synchronized" here means the final context pass finished + successfully, including the case where no edit was warranted. + + Stop. + + ## Rules + + - Validate at most one plan per invocation. + - Do not duplicate the internal instructions of invoked skills. + - Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. + - Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. + - On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. + - Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. + - Do not create a Git commit or push changes. + - Do not mark the plan archived or delete the plan. + - Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. + - Do not infer success when an invoked skill returns a non-success status. + - Preserve validation evidence already written to the plan when context + synchronization fails. + """ + +local VALIDATION_SKILL = """ + --- + name: sce-validation + description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. + --- + + # SCE Validation + + ## Purpose + + Prove that one finished SCE plan meets its acceptance criteria and repository + validation bar, then record the evidence on the plan and return one Markdown + result. + + This skill owns: + + - Resolving one plan. + - Confirming every implementation task is complete. + - Running the plan's full validation commands and each acceptance criterion + check. + - Removing temporary scaffolding introduced by the change. + - Writing the Validation Report into the plan. + - Marking acceptance criteria against the evidence. + - Returning one Markdown validation result. + + Return a result matching: + + `references/validation-result.md` + + Write plan-file evidence matching: + + `references/validation-report.md` + + Context synchronization is not this skill's job. The invoking `/validate` + workflow runs `sce-plan-context-sync` only after a `validated` result. + + ## Input + + The invoking workflow provides: + + - A plan name or path. + + ## Workflow + + ### 1. Resolve the plan + + Resolve the supplied plan name or path to exactly one existing plan under + `context/plans/`. + + When no plan can be found, return `blocked`. + + When multiple plans match and none can be selected safely, return `blocked` + with the matching candidates. + + Read the selected plan before exploring the repository. + + ### 2. Confirm implementation is finished + + Return `blocked` with incomplete tasks listed when any implementation task + remains incomplete. + + Final validation measures finished work. Do not run the full suite against a + partial stack, and do not complete remaining tasks here. + + ### 3. Read the validation contract from the plan + + From the plan, collect: + + - Every acceptance criterion and its `Validate:` check. + - The `Full validation` command list. + - The `Context sync` requirements, for the context-impact handoff only. + + Return `blocked` when the plan has no usable acceptance criteria, or when no + validation commands can be determined from the plan or repository conventions. + + Prefer the plan's authored checks. Fall back to repository-primary test, lint, + and format commands only when `Full validation` is absent, and record that + fallback under notes on a `validated` or `failed` result. + + ### 4. Remove temporary scaffolding + + Before or while running checks, remove temporary scaffolding introduced during + the change when it is clearly throwaway: + + - Debug-only patches or flags left enabled. + - Temporary files or intermediate artifacts not part of the delivered design. + - Local scaffolding the plan or task notes mark as temporary. + + Do not delete durable product code, tests, configuration, or context files. + + Record every removed path. When nothing temporary remains, report `None.` + + ### 5. Run full validation and acceptance checks + + Run the plan's `Full validation` commands. + + Then verify each acceptance criterion using its `Validate:` line. Prefer a + runnable command. Use a named inspection only when the criterion authorizes it, + and say exactly what was inspected. + + When a check fails, record the failure and continue gathering evidence. Do not + modify tests, application code, or configuration to make a check pass. Final + validation measures the finished work; repair belongs to a later work session, + not this skill. + + Never report a check as passed unless it ran successfully or the authorized + inspection confirmed the criterion. + + Do not run task-by-task implementation work for incomplete tasks. That belongs + to `/next-task`. + + ### 6. Update the plan + + For `validated` and `failed` outcomes: + + - Mark each acceptance criterion checkbox to match the evidence. + - Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. + - When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + + Do not reopen completed tasks, rewrite task evidence, or change the task stack. + + For `blocked`, leave the plan file unchanged. + + ### 7. Determine context impact for the handoff + + On `validated` only, classify the durable context impact of the finished plan + so `sce-plan-context-sync` can start from the plan's own requirements: + + - Start from the plan's `Context sync` section. + - Inspect what the completed implementation actually changed when needed. + - Report required context paths and affected areas. + - Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + + Do not edit context files here. + + On `failed` or `blocked`, omit context impact; context sync will not run. + + ### 8. Return the Markdown result + + Return exactly one Markdown result: + + - `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. + - `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. + - `blocked` when validation cannot proceed safely. + + Return only the Markdown report. Do not add explanatory prose before or after + it. Do not return YAML. + + ## Boundaries + + Do not: + + - Validate more than one plan. + - Complete remaining implementation tasks. + - Modify tests, application code, or configuration to make a failing check pass. + - Apply lint or format auto-fixes that change product or test files as part of + making validation green. + - Synchronize durable context under `context/` outside the plan file. + - Create the context root. + - Mark the plan archived or delete the plan. + - Create a Git commit or push changes. + - Invent acceptance criteria the plan does not state. + - Claim verification that was not performed. + - Return a YAML result. + - Invoke plan context sync. The workflow owns that step. + + ## Completion + + The skill is complete after: + + - One plan was resolved, or resolution failed and was reported. + - Implementation completeness was checked. + - Validation ran to a terminal state, or a blocker prevented it. + - One valid Markdown result matching `references/validation-result.md` was + returned. + """ + +local VALIDATION_REPORT = """ + # Plan-file Validation Report + + The Markdown section `sce-validation` appends to the plan file when returning + `validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` + under exactly one `## Validation Report` heading. + + This is plan-file content. The skill's return value to the workflow is defined + separately in `validation-result.md`. + + Do not author this section while planning. Only `/validate` through + `sce-validation` writes it. + + ## Layout + + ```markdown + ## Validation Report + + **Status:** {validated | failed} + **Date:** {YYYY-MM-DD} + + ### Commands run + + - `{command}` -> exit {code} ({concise outcome summary}) + - `{command}` -> exit {code} ({concise outcome summary}) + + ### Scaffolding removed + + - `{path}` — {why it was temporary} + - None. + + ### Success-criteria verification + + - [x] AC1: {criterion statement} -> {evidence} + - [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + + ### Failed checks and follow-ups + + - {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} + - None. + + ### Residual risks + + - {risk} + - None identified. + + ### Retry + + {Only when Status is failed:} + + After repairs, rerun: + + `/validate {plan path}` + ``` + + ## Rules + + - Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. + - Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. + - List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. + - Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. + - Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. + - Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. + - Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. + - When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. + - Keep evidence concise and factual. Do not narrate the whole implementation + history. + - Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. + - Do not rewrite task evidence or reopen completed tasks. + - When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. + """ + +local VALIDATION_RESULT = """ + # Validation Result + + Return only one completed Markdown report using the applicable variant below. + Do not include unused sections, placeholders, YAML, or a fenced code block. + + The `Status` value must be exactly one of: + + - `validated` + - `failed` + - `blocked` + + The plan-file `## Validation Report` section is written separately using + `validation-report.md`. This file is the skill's return value to the invoking + workflow. + + ## Validated variant + + # Validation Report + + **Status:** validated + **Plan:** `{plan path}` + **Name:** `{plan name}` + **Tasks:** `{completed}/{total} complete` + **Date:** `{YYYY-MM-DD}` + + ## Commands run + + - `{command}` -> {passed} — {concise outcome summary} + + ## Acceptance criteria + + - [x] AC1: {criterion statement} — {evidence} + - [x] AC2: {criterion statement} — {evidence} + + ## Scaffolding removed + + - `{path}` — {why it was temporary} + - None. + + ## Residual risks + + - {risk} + - None identified. + + ## Context impact + + **Classification:** `{none | local | domain | root}` + **Affected areas:** `{comma-separated areas}` + **Required context:** + + - `{path or statement from the plan Context sync section}` + + {One or two sentences on why this classification fits the finished plan.} + + ## Notes + + {Include only non-blocking information the invoking workflow should retain. + Omit this section when unnecessary.} + + --- + + ## Failed variant + + This variant is a session handoff. Another agent or a later session must be + able to act from it alone. Write it as a prompt the user can paste forward, not + as a summary of the validation run. + + # Validation failed — handoff + + **Status:** failed + **Plan:** `{plan path}` + **Name:** `{plan name}` + **Tasks:** `{completed}/{total} complete` + **Date:** `{YYYY-MM-DD}` + **Validation report:** written to `{plan path}` + + ## Goal for the next session + + Repair the unfinished validation so every acceptance criterion and full + validation command passes. Do not modify tests or product code inside a + `/validate` run to force green results; fix the implementation (or the plan) in + a normal work session, then rerun validation. + + ## What failed + + - `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + + ## Acceptance criteria + + - [x] AC1: {criterion} — {evidence} + - [ ] AC2: {criterion} — {why unmet} + + ## Commands run + + - `{command}` -> {passed | failed | not_run} — {concise outcome summary} + + ## Constraints + + - All implementation tasks were already complete when validation ran. + - Validation did not modify tests, application code, or configuration to clear + failures. + - Durable context was not synchronized; plan context sync runs only after + validation succeeds. + - Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + + ## Residual risks + + - {risk} + - None identified. + + ## Recommended work + + 1. {First concrete fix, with files or areas when known} + 2. {Second concrete fix, or decision the user must make} + 3. Rerun final validation after the fixes land: + + `/validate {plan path}` + + Do not stop after the repair. The plan is not finished until `/validate` + returns `validated` and plan context sync completes. + + --- + + ## Blocked variant + + # Validation blocked + + **Status:** blocked + **Plan:** `{plan path when resolved}` + **Name:** `{plan name when resolved}` + + ## Issues + + - **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + + ## Incomplete tasks + + - `{task id}` — {title} + - Omit this section when no incomplete tasks apply. + + ## Candidates + + - `{candidate plan path}` + - Omit this section when plan resolution was not ambiguous. + + ## Next step + + {Exactly one continuation, matching the blocker:} + + - Incomplete tasks: + + `/next-task {plan path}` + + - Ambiguous plan: + + `/validate {candidate path}` + + - Missing plan content or other blocker: state the decision required. Do not + invent a command. + + --- + + ## Report rules + + - Name the exact `Plan:` path so every emitted command is runnable. + - Use **Status:** exactly `validated`, `failed`, or `blocked`. + - Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. + - Do not modify tests or product code to clear a failure; record it under + **What failed**. + - The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. + - The failed variant must be self-contained enough to hand to another session + without the original chat. + - Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. + - Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. + - Do not select or describe an unrelated next implementation task when status is + `validated`. + - Omit empty optional sections rather than writing placeholders. + """ + +workflow = new model.WorkflowPackage { + slug = "validate" + command = new model.WorkflowCommand { + slug = "validate" + title = "SCE Validate" + document = makeDocument.apply("validate.md", COMMAND) + } + skills = new Mapping { + [validationPackage.slug] = validationPackage + ["sce-plan-context-sync"] = contextSync.skills["sce-plan-context-sync"] + } +} diff --git a/config/pkl/check-generated.sh b/config/pkl/check-generated.sh index 39bbab85..a7a44fbd 100755 --- a/config/pkl/check-generated.sh +++ b/config/pkl/check-generated.sh @@ -25,11 +25,11 @@ cleanup() { } trap cleanup EXIT +pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null pkl eval -m "$tmp_dir" config/pkl/generate.pkl >/dev/null -# NOTE: This paths array must stay in sync with the output.files block in -# config/pkl/generate.pkl. Whenever generate.pkl gains or loses outputs, -# update this array to match so parity checks remain accurate. +# Compare complete generated directories so nested skill references and stale +# files are covered without maintaining a separate per-document path list. paths=( "config/.opencode/agent" "config/.opencode/command" @@ -37,23 +37,38 @@ paths=( "config/.opencode/lib" "config/.opencode/plugins" "config/.opencode/opencode.json" - "config/automated/.opencode/agent" - "config/automated/.opencode/command" - "config/automated/.opencode/skills" - "config/automated/.opencode/lib" - "config/automated/.opencode/plugins" - "config/automated/.opencode/opencode.json" - "config/.claude/agents" "config/.claude/commands" "config/.claude/skills" + "config/.claude/hooks" + "config/.claude/settings.json" "config/.pi/prompts" "config/.pi/skills" "config/.pi/extensions" "config/schema/sce-config.schema.json" ) +# These removed surfaces must stay absent from both generated previews and the +# committed tree. Obsolete files inside retained directories are caught by the +# complete-directory comparisons above. +forbidden_paths=( + "config/automated/.opencode" + "config/.claude/agents" +) + stale=0 for path in "${paths[@]}"; do + if [[ ! -e "$tmp_dir/$path" ]]; then + stale=1 + printf 'Generator did not emit required output at %s\n' "$path" + continue + fi + + if [[ ! -e "$path" ]]; then + stale=1 + printf 'Required generated output is missing at %s\n' "$path" + continue + fi + if ! git diff --no-index --exit-code -- "$tmp_dir/$path" "$path" >/dev/null; then stale=1 printf 'Generated output drift detected at %s\n' "$path" @@ -61,6 +76,17 @@ for path in "${paths[@]}"; do fi done +for path in "${forbidden_paths[@]}"; do + if [[ -e "$tmp_dir/$path" ]]; then + stale=1 + printf 'Generator emitted removed output at %s\n' "$path" + fi + if [[ -e "$path" ]]; then + stale=1 + printf 'Removed generated output still exists at %s\n' "$path" + fi +done + if [[ "$stale" -ne 0 ]]; then cat <<'EOF' Generated files are stale. diff --git a/config/pkl/generate.pkl b/config/pkl/generate.pkl index d80f3244..256afae7 100644 --- a/config/pkl/generate.pkl +++ b/config/pkl/generate.pkl @@ -1,5 +1,4 @@ import "renderers/opencode-content.pkl" as opencode -import "renderers/opencode-automated-content.pkl" as opencode_automated import "renderers/claude-content.pkl" as claude import "renderers/pi-content.pkl" as pi import "renderers/common.pkl" as common @@ -17,30 +16,14 @@ output { text = document.rendered } } - for (slug, document in opencode_automated.agents) { - ["config/automated/.opencode/agent/\(document.title).md"] { - text = document.rendered - } - } - for (slug, document in claude.agents) { - ["config/.claude/agents/\(slug).md"] { - text = document.rendered - } - } - for (slug, document in opencode.commands) { ["config/.opencode/command/\(slug).md"] { - text = document.rendered - } - } - for (slug, document in opencode_automated.commands) { - ["config/automated/.opencode/command/\(slug).md"] { - text = document.rendered + text = "\(document.text)\n" } } for (slug, document in claude.commands) { ["config/.claude/commands/\(slug).md"] { - text = document.rendered + text = "\(document.text)\n" } } ["config/.claude/settings.json"] { @@ -50,34 +33,24 @@ output { text = claude.sceHookScript.rendered } - for (slug, document in opencode.skills) { - ["config/.opencode/skills/\(slug)/SKILL.md"] { - text = document.rendered + for (documentPath, document in opencode.skillDocuments) { + ["config/.opencode/skills/\(documentPath)"] { + text = "\(document.text)\n" } } - for (slug, document in opencode_automated.skills) { - ["config/automated/.opencode/skills/\(slug)/SKILL.md"] { - text = document.rendered - } - } - for (slug, document in claude.skills) { - ["config/.claude/skills/\(slug)/SKILL.md"] { - text = document.rendered + for (documentPath, document in claude.skillDocuments) { + ["config/.claude/skills/\(documentPath)"] { + text = "\(document.text)\n" } } for (slug, document in pi.commands) { ["config/.pi/prompts/\(slug).md"] { - text = document.rendered + text = "\(document.text)\n" } } - for (slug, document in pi.agentPrompts) { - ["config/.pi/prompts/agent-\(slug).md"] { - text = document.rendered - } - } - for (slug, document in pi.skills) { - ["config/.pi/skills/\(slug)/SKILL.md"] { - text = document.rendered + for (documentPath, document in pi.skillDocuments) { + ["config/.pi/skills/\(documentPath)"] { + text = "\(document.text)\n" } } ["config/.pi/extensions/sce/index.ts"] { @@ -95,18 +68,6 @@ output { ["config/.opencode/opencode.json"] { text = opencode.opencodeConfig.rendered } - ["config/automated/.opencode/lib/bash-policy-presets.json"] { - text = bashPolicyPresetCatalogSource - } - ["config/automated/.opencode/plugins/sce-bash-policy.ts"] { - text = opencodeBashPolicyPluginSource - } - ["config/automated/.opencode/plugins/sce-agent-trace.ts"] { - text = opencodeAgentTracePluginSource - } - ["config/automated/.opencode/opencode.json"] { - text = opencode_automated.opencodeConfig.rendered - } ["config/schema/sce-config.schema.json"] { text = sce_config_schema.rendered } diff --git a/config/pkl/renderers/claude-content.pkl b/config/pkl/renderers/claude-content.pkl index 403fdad3..c5f22383 100644 --- a/config/pkl/renderers/claude-content.pkl +++ b/config/pkl/renderers/claude-content.pkl @@ -1,4 +1,7 @@ -import "../base/shared-content.pkl" as shared +import "../base/workflow-change-to-plan.pkl" as changeToPlan +import "../base/workflow-next-task.pkl" as nextTask +import "../base/workflow-validate.pkl" as validate +import "../base/workflow-content.pkl" as model import "common.pkl" as common import "claude-metadata.pkl" as metadata @@ -8,52 +11,26 @@ local claudeSceHookScriptPath = "$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-sh local function sceHookCommand(arguments: String): String = "bash \\\"\(claudeSceHookScriptPath)\\\" \(arguments)" -local agentFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.agents) { - [unitSlug] = """ ---- -name: \(unitSlug) -description: \(metadata.agentDescriptions[unitSlug]) -model: inherit -color: \(metadata.agentColors[unitSlug]) -tools: \(metadata.agentTools) ---- -""" - } +local workflows = new Listing { + changeToPlan.workflow + nextTask.workflow + validate.workflow } -local agentBodyBySlug = new Mapping { - for (unitSlug, unit in shared.agents) { - [unitSlug] = if (metadata.agentSystemPreambleBlocks[unitSlug] == "") unit.canonicalBody else """ -\(metadata.agentSystemPreambleBlocks[unitSlug]) - -\(unit.canonicalBody) -""" - } +local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { + path = command.document.path + text = command.document.text.replaceFirst( + "\n---\n", + "\nallowed-tools: \(metadata.commandAllowedTools[command.slug])\n---\n" + ) } -local commandFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.commands) { - [unitSlug] = """ ---- -description: "\(common.commandDescriptions[unitSlug])" -allowed-tools: \(metadata.commandAllowedTools[unitSlug]) ---- -""" - } -} - -local skillFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.skills) { - [unitSlug] = """ ---- -name: \(unitSlug) -description: | - \(metadata.skillDescriptions[unitSlug]) -compatibility: \(metadata.skillCompatibility) ---- -""" - } +local renderSkillDocument = (document: model.WorkflowDocument) -> new model.WorkflowDocument { + path = document.path + text = if (document.path == "SKILL.md") document.text.replaceFirst( + "\n---\n", + "\ncompatibility: \(metadata.skillCompatibility)\n---\n" + ) else document.text } settings = new common.RenderedTextFile { @@ -132,35 +109,21 @@ exec "$@" """ } -agents { - for (unitSlug, unit in shared.agents) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = agentFrontmatterBySlug[unitSlug] - body = agentBodyBySlug[unitSlug] - } - } -} - commands { - for (unitSlug, unit in shared.commands) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = commandFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } + for (workflow in workflows) { + [workflow.command.slug] = renderCommand.apply(workflow.command) } } -skills { - for (unitSlug, unit in shared.skills) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = skillFrontmatterBySlug[unitSlug] - body = unit.canonicalBody +/// Flatten package-relative document paths while retaining each skill's +/// self-contained directory layout and adding only Claude-supported metadata +/// to the package entrypoint. +skillDocuments { + for (workflow in workflows) { + for (skillSlug, skillPackage in workflow.skills) { + for (documentPath, document in skillPackage.documents) { + ["\(skillSlug)/\(documentPath)"] = renderSkillDocument.apply(document) + } } } } diff --git a/config/pkl/renderers/claude-metadata.pkl b/config/pkl/renderers/claude-metadata.pkl index b9e7e5ce..b93653c5 100644 --- a/config/pkl/renderers/claude-metadata.pkl +++ b/config/pkl/renderers/claude-metadata.pkl @@ -1,37 +1,7 @@ -agentDescriptions = new Mapping { - ["shared-context-plan"] = "Use when the user needs to create or update an SCE plan before implementation." - ["shared-context-code"] = "Use when the user wants to execute one approved SCE task and sync context." -} - -agentColors = new Mapping { - ["shared-context-plan"] = "blue" - ["shared-context-code"] = "green" -} - -agentTools = "[\"Read\", \"Glob\", \"Grep\", \"Edit\", \"Write\", \"Skill\", \"AskUserQuestion\", \"Task\", \"Bash\"]" - -agentSystemPreambleBlocks = new Mapping { - ["shared-context-plan"] = "" - ["shared-context-code"] = "" -} - commandAllowedTools = new Mapping { ["next-task"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" ["change-to-plan"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" - ["handover"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" - ["commit"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" ["validate"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" } -skillDescriptions = new Mapping { - ["sce-bootstrap-context"] = "Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent." - ["sce-context-sync"] = "Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth." - ["sce-handover-writer"] = "Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include \"create a handover\", \"hand this off\", \"write handover notes\", \"pass this task on\", or \"document where I'm up to\"." - ["sce-plan-authoring"] = "Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution." - ["sce-plan-review"] = "Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. \"continue the plan\", \"what's next?\", \"resume work on the plan\", \"review my plan and prepare the next task\"." - ["sce-task-execution"] = "Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md." - ["sce-atomic-commit"] = "Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad." - ["sce-validation"] = "Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out." -} - skillCompatibility = "claude" diff --git a/config/pkl/renderers/common.pkl b/config/pkl/renderers/common.pkl index 1147f00e..4d69a02a 100644 --- a/config/pkl/renderers/common.pkl +++ b/config/pkl/renderers/common.pkl @@ -1,5 +1,4 @@ import "../base/opencode.pkl" as opencode -import "../base/shared-content.pkl" as shared class RenderedTargetDocument { slug: String @@ -21,27 +20,3 @@ sceGeneratedOpenCodePlugins = List( sceGeneratedOpenCodePluginPathsJson = sceGeneratedOpenCodePlugins .map((plugin) -> plugin.path_json) .join(", ") - -commandDescriptions = new Mapping { - ["next-task"] = "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" - ["change-to-plan"] = "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" - ["change-to-plan-interactive"] = "Create or update an SCE plan from a change request with interactive clarification" - ["drift-detect"] = "Run `sce-drift-analyzer` to report context-code drift before edits" - ["fix-drift"] = "Run `sce-drift-fixer` to repair context files from current code truth" - ["handover"] = "Run `sce-handover-writer` to capture the current task for handoff" - ["commit"] = "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" - ["validate"] = "Run `sce-validation` to finish an SCE plan with validation and cleanup" -} - -skillDescriptions = new Mapping { - ["sce-bootstrap-context"] = "Use when user wants to Bootstrap SCE baseline context directory when missing." - ["sce-context-sync"] = "Use when user wants to Synchronize context files to match current code behavior after task execution." - ["sce-handover-writer"] = "Use when user wants to create a structured SCE handover for the current task." - ["sce-plan-authoring"] = "Use when user wants to Create or update an SCE implementation plan with scoped atomic tasks." - ["sce-plan-authoring-interactive"] = "Use when user wants to Create or update an SCE implementation plan with interactive clarification." - ["sce-plan-review"] = "Use when user wants to review an existing plan and prepare the next task safely." - ["sce-task-execution"] = "Use when user wants to Execute one approved task with explicit scope, evidence, and status updates." - ["sce-atomic-commit"] = "Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad." - ["sce-validation"] = "Use when user wants to Run final plan validation and cleanup with evidence capture." -} - diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index e0340ca6..d9f93a55 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -1,121 +1,126 @@ -import "../base/shared-content.pkl" as shared -import "../base/shared-content-automated.pkl" as sharedAutomated -import "common.pkl" as common -import "opencode-metadata.pkl" as opencode -import "opencode-automated-metadata.pkl" as opencodeAutomated -import "claude-metadata.pkl" as claude -import "pi-metadata.pkl" as pi +import "opencode-content.pkl" as opencode +import "claude-content.pkl" as claude +import "pi-content.pkl" as pi -opencodeAgentCoverage { - for (unitSlug, _ in shared.agents) { - [unitSlug] = new { - description = opencode.agentDescriptions[unitSlug] - displayName = opencode.agentDisplayNames[unitSlug] - color = opencode.agentColors[unitSlug] - permissionBlock = opencode.agentPermissionBlocks[unitSlug] - } +local expectedCommandSlugs = Set( + "change-to-plan", + "next-task", + "validate" +) + +local expectedAgentSlugs = Set( + "shared-context-plan", + "shared-context-code" +) + +local expectedSkillDocumentPaths = Set( + "sce-context-load/SKILL.md", + "sce-context-load/references/context-brief.yaml", + "sce-plan-authoring/SKILL.md", + "sce-plan-authoring/references/authoring-contract.yaml", + "sce-plan-authoring/references/plan-summary.md", + "sce-plan-authoring/references/plan-template.md", + "sce-plan-context-sync/SKILL.md", + "sce-plan-context-sync/references/sync-report.md", + "sce-plan-review/SKILL.md", + "sce-plan-review/references/readiness-contract.yaml", + "sce-task-context-sync/SKILL.md", + "sce-task-context-sync/references/sync-report.md", + "sce-task-execution/SKILL.md", + "sce-task-execution/references/execution-contract.yaml", + "sce-task-execution/references/implementation-gate.md", + "sce-validation/SKILL.md", + "sce-validation/references/validation-report.md", + "sce-validation/references/validation-result.md" +) + +local opencodeAgents = new Mapping { + for (slug, document in opencode.agents) { + [slug] = document } } - -opencodeCommandCoverage { - for (unitSlug, _ in shared.commands) { - [unitSlug] = new { - description = common.commandDescriptions[unitSlug] - agent = opencode.commandAgents[unitSlug] - } +local opencodeCommands = new Mapping { + for (slug, document in opencode.commands) { + [slug] = document } } - -opencodeSkillCoverage { - for (unitSlug, _ in shared.skills) { - [unitSlug] = new { - description = common.skillDescriptions[unitSlug] - compatibility = opencode.skillCompatibility - } +local opencodeSkillDocuments = new Mapping { + for (path, document in opencode.skillDocuments) { + [path] = document } } - -claudeAgentCoverage { - for (unitSlug, _ in shared.agents) { - [unitSlug] = new { - description = claude.agentDescriptions[unitSlug] - color = claude.agentColors[unitSlug] - tools = claude.agentTools - } +local claudeCommands = new Mapping { + for (slug, document in claude.commands) { + [slug] = document } } - -claudeCommandCoverage { - for (unitSlug, _ in shared.commands) { - [unitSlug] = new { - description = common.commandDescriptions[unitSlug] - allowedTools = claude.commandAllowedTools[unitSlug] - } +local claudeSkillDocuments = new Mapping { + for (path, document in claude.skillDocuments) { + [path] = document } } - -claudeSkillCoverage { - for (unitSlug, _ in shared.skills) { - [unitSlug] = new { - description = common.skillDescriptions[unitSlug] - compatibility = claude.skillCompatibility - } +local piCommands = new Mapping { + for (slug, document in pi.commands) { + [slug] = document } } - -piAgentPromptCoverage { - for (unitSlug, _ in shared.agents) { - [unitSlug] = new { - description = pi.agentDescriptions[unitSlug] - argumentHint = pi.agentArgumentHints[unitSlug] - skillReference = pi.agentSkillReferences[unitSlug] - } +local piSkillDocuments = new Mapping { + for (path, document in pi.skillDocuments) { + [path] = document } } -piCommandCoverage { - for (unitSlug, _ in shared.commands) { - [unitSlug] = new { - description = common.commandDescriptions[unitSlug] - argumentHint = pi.commandArgumentHints[unitSlug] - } - } +local assertExactKeys = (actual: Mapping, expected: Set, label: String) -> + if ( + actual.length == expected.length + && expected.every((key) -> actual.containsKey(key)) + ) "\(label): complete" + else error("\(label) inventory does not match the canonical workflow matrix") + +inventoryChecks { + ["opencode-agents"] = assertExactKeys.apply(opencodeAgents, expectedAgentSlugs, "OpenCode agent") + ["opencode-commands"] = assertExactKeys.apply(opencodeCommands, expectedCommandSlugs, "OpenCode command") + ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedSkillDocumentPaths, "OpenCode skill document") + ["claude-commands"] = assertExactKeys.apply(claudeCommands, expectedCommandSlugs, "Claude command") + ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedSkillDocumentPaths, "Claude skill document") + ["pi-commands"] = assertExactKeys.apply(piCommands, expectedCommandSlugs, "Pi command") + ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedSkillDocumentPaths, "Pi skill document") } -piSkillCoverage { - for (unitSlug, _ in shared.skills) { - [unitSlug] = new { - description = common.skillDescriptions[unitSlug] - } +/// Force rendering after exact inventory checks so target-specific metadata +/// lookups and every nested package document are evaluated. +opencodeAgentCoverage { + for (slug, document in opencodeAgents) { + [slug] = document.rendered } } - -// Automated OpenCode profile coverage checks -opencodeAutomatedAgentCoverage { - for (unitSlug, _ in sharedAutomated.agents) { - [unitSlug] = new { - description = opencodeAutomated.agentDescriptions[unitSlug] - displayName = opencodeAutomated.agentDisplayNames[unitSlug] - color = opencodeAutomated.agentColors[unitSlug] - permissionBlock = opencodeAutomated.agentPermissionBlocks[unitSlug] - } +opencodeCommandCoverage { + for (slug, document in opencodeCommands) { + [slug] = document.text } } - -opencodeAutomatedCommandCoverage { - for (unitSlug, _ in sharedAutomated.commands) { - [unitSlug] = new { - description = common.commandDescriptions[unitSlug] - agent = opencodeAutomated.commandAgents[unitSlug] - } +opencodeSkillDocumentCoverage { + for (path, document in opencodeSkillDocuments) { + [path] = document.text } } - -opencodeAutomatedSkillCoverage { - for (unitSlug, _ in sharedAutomated.skills) { - [unitSlug] = new { - description = common.skillDescriptions[unitSlug] - compatibility = opencodeAutomated.skillCompatibility - } +claudeCommandCoverage { + for (slug, document in claudeCommands) { + [slug] = document.text + } +} +claudeSkillDocumentCoverage { + for (path, document in claudeSkillDocuments) { + [path] = document.text + } +} +piCommandCoverage { + for (slug, document in piCommands) { + [slug] = document.text + } +} +piSkillDocumentCoverage { + for (path, document in piSkillDocuments) { + [path] = document.text } } diff --git a/config/pkl/renderers/opencode-automated-content.pkl b/config/pkl/renderers/opencode-automated-content.pkl deleted file mode 100644 index ffa10366..00000000 --- a/config/pkl/renderers/opencode-automated-content.pkl +++ /dev/null @@ -1,88 +0,0 @@ -import "../base/shared-content-automated.pkl" as shared -import "common.pkl" as common -import "opencode-automated-metadata.pkl" as metadata - -local generatedOpenCodePluginPathsJson = common.sceGeneratedOpenCodePluginPathsJson - -local agentFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.agents) { - [unitSlug] = """ ---- -name: "\(metadata.agentDisplayNames[unitSlug])" -description: \(metadata.agentDescriptions[unitSlug]) -temperature: 0.1 -color: "\(metadata.agentColors[unitSlug])"\(metadata.agentBehaviorBlocks[unitSlug]) -\(metadata.agentPermissionBlocks[unitSlug]) ---- -""" - } -} - -local commandFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.commands) { - [unitSlug] = """ ---- -description: "\(common.commandDescriptions[unitSlug])" -agent: "\(metadata.commandAgents[unitSlug])" ---- -""" - } -} - -local skillFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.skills) { - [unitSlug] = """ ---- -name: \(unitSlug) -description: | - \(metadata.skillDescriptions[unitSlug]) -compatibility: \(metadata.skillCompatibility) ---- -""" - } -} - -agents { - for (unitSlug, unit in shared.agents) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = agentFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } - } -} - -commands { - for (unitSlug, unit in shared.commands) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = commandFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } - } -} - -skills { - for (unitSlug, unit in shared.skills) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = skillFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } - } -} - -opencodeConfig = new common.RenderedTextFile { - slug = "opencode" - rendered = """ -{ - "$schema": "https://opencode.ai/config.json", - "plugin": [ - \(generatedOpenCodePluginPathsJson) - ] -} -""" -} diff --git a/config/pkl/renderers/opencode-automated-metadata.pkl b/config/pkl/renderers/opencode-automated-metadata.pkl deleted file mode 100644 index 23cffe6b..00000000 --- a/config/pkl/renderers/opencode-automated-metadata.pkl +++ /dev/null @@ -1,99 +0,0 @@ -// Automated OpenCode metadata variant with non-interactive permissions -// See context/sce/automated-profile-contract.md for P1 gate policy - -agentDescriptions = new Mapping { - ["shared-context-plan"] = "Plans a change into atomic tasks in context/plans without touching application code." - ["shared-context-code"] = "Executes one approved SCE task, validates behavior, and syncs context." -} - -agentDisplayNames = new Mapping { - ["shared-context-plan"] = "Shared Context Plan" - ["shared-context-code"] = "Shared Context Code" -} - -agentColors = new Mapping { - ["shared-context-plan"] = "#2563eb" - ["shared-context-code"] = "#059669" -} - -agentBehaviorBlocks = new Mapping { - ["shared-context-plan"] = "" - ["shared-context-code"] = "" -} - -agentPermissionBlocks = new Mapping { - ["shared-context-plan"] = """ -permission: - default: allow - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: block - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: block - skill: - "*": allow - "sce-bootstrap-context": allow - "sce-plan-authoring": allow -""" - ["shared-context-code"] = """ -permission: - default: allow - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: block - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: block - skill: - "*": allow - "sce-plan-review": allow - "sce-task-execution": allow - "sce-context-sync": allow - "sce-validation": allow - "sce-atomic-commit": allow -""" -} - -commandAgents = new Mapping { - ["next-task"] = "Shared Context Code" - ["change-to-plan"] = "Shared Context Plan" - ["change-to-plan-interactive"] = "Shared Context Plan" - ["handover"] = "Shared Context Code" - ["commit"] = "Shared Context Code" - ["validate"] = "Shared Context Code" -} - -skillDescriptions = new Mapping { - ["sce-bootstrap-context"] = "Use when user wants to Bootstrap SCE baseline context directory when missing." - ["sce-context-sync"] = "Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth." - ["sce-handover-writer"] = "Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include \"create a handover\", \"hand this off\", \"write handover notes\", \"pass this task on\", or \"document where I'm up to\"." - ["sce-plan-authoring"] = "Transforms a change request into a structured implementation plan saved under context/plans/, breaking work down into atomic, commit-sized tasks with clear goals, scope boundaries, acceptance criteria, and verification steps. Use when a user wants to create or update a project plan, task breakdown, implementation roadmap, or work plan — including requests like \"plan this feature\", \"break this into tasks\", \"write an implementation plan\", or \"scope out this change\". Handles ambiguity resolution through a blocking clarification gate before writing any plan, and produces a machine-friendly task list ready for handoff to the Shared Context Engineering (SCE) implementation agent." - ["sce-plan-authoring-interactive"] = "Use when a user wants to create or update a Shared Context Engineering (SCE) implementation plan with interactive clarification. Triggers on requests like \"write a plan\", \"create an implementation roadmap\", \"draft a rollout plan\", \"plan this change\", or \"break this into tasks\" for a software change. Interactively resolves ambiguity by asking targeted clarifying questions, then produces a structured markdown plan under `context/plans/` with a change summary, success criteria, constraints, atomic task stack, and verification steps — ready to hand off to the Shared Context Code agent for execution." - ["sce-plan-review"] = "Use when the user wants to continue, resume, or pick up the next step from a markdown plan file stored in `context/plans/`. Reads the selected plan file, identifies the first unchecked checkbox as the next task, validates that acceptance criteria are clear and blockers are resolved, then issues an explicit readiness verdict before proceeding to implementation. Use when the user says \"continue the plan\", \"what's the next task\", \"resume work\", \"pick up where we left off\", or references a specific plan file." - ["sce-task-execution"] = "Executes a single scoped coding task with structured implementation logging, test and lint evidence capture, and plan status updates. Use when the user wants to run, implement, or complete one approved task from a plan — such as writing code changes, applying fixes, or executing a defined unit of work — while enforcing strict single-task scope boundaries, logging intent to context/tmp/automated-session-log.md, and updating task status in context/plans/{plan_id}.md. Triggers on phrases like \"execute task\", \"run this task\", \"implement task\", \"do the next task\", or \"apply this change\"." - ["sce-atomic-commit"] = "Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad." - ["sce-validation"] = "Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out." -} - -skillCompatibility = "opencode" diff --git a/config/pkl/renderers/opencode-content.pkl b/config/pkl/renderers/opencode-content.pkl index 5a614444..95011076 100644 --- a/config/pkl/renderers/opencode-content.pkl +++ b/config/pkl/renderers/opencode-content.pkl @@ -1,123 +1,111 @@ -import "../base/shared-content.pkl" as shared +import "../base/workflow-change-to-plan.pkl" as changeToPlan +import "../base/workflow-next-task.pkl" as nextTask +import "../base/workflow-validate.pkl" as validate +import "../base/workflow-content.pkl" as model import "common.pkl" as common import "opencode-metadata.pkl" as metadata local generatedOpenCodePluginPathsJson = common.sceGeneratedOpenCodePluginPathsJson -local agentFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.agents) { - [unitSlug] = """ ---- -name: "\(metadata.agentDisplayNames[unitSlug])" -description: \(metadata.agentDescriptions[unitSlug]) -temperature: 0.1 -color: "\(metadata.agentColors[unitSlug])"\(metadata.agentBehaviorBlocks[unitSlug]) -\(metadata.agentPermissionBlocks[unitSlug]) ---- -""" - } +local workflows = new Listing { + changeToPlan.workflow + nextTask.workflow + validate.workflow } -local commandSkillMetadataBlocks = new Mapping { - ["next-task"] = """ -entry-skill: "sce-plan-review" -skills: - - "sce-plan-review" - - "sce-task-execution" - - "sce-context-sync" - - "sce-validation" -""" +local commandAgentBySlug = new Mapping { + ["change-to-plan"] = "Shared Context Plan" + ["next-task"] = "Shared Context Code" + ["validate"] = "Shared Context Code" +} + +local commandSkillMetadataBySlug = new Mapping { ["change-to-plan"] = """ -entry-skill: "sce-plan-authoring" +entry-skill: "sce-context-load" skills: + - "sce-context-load" - "sce-plan-authoring" """ - ["drift-detect"] = """ -entry-skill: "sce-drift-analyzer" -skills: - - "sce-drift-analyzer" -""" - ["fix-drift"] = """ -entry-skill: "sce-drift-fixer" -skills: - - "sce-drift-fixer" -""" - ["handover"] = """ -entry-skill: "sce-handover-writer" -skills: - - "sce-handover-writer" -""" - ["commit"] = """ -entry-skill: "sce-atomic-commit" + ["next-task"] = """ +entry-skill: "sce-plan-review" skills: - - "sce-atomic-commit" + - "sce-plan-review" + - "sce-task-execution" + - "sce-task-context-sync" """ ["validate"] = """ entry-skill: "sce-validation" skills: - "sce-validation" + - "sce-plan-context-sync" """ } -local commandFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.commands) { - [unitSlug] = if (commandSkillMetadataBlocks[unitSlug] == null) """ ---- -description: "\(common.commandDescriptions[unitSlug])" -agent: "\(metadata.commandAgents[unitSlug])" ---- -""" else """ ---- -description: "\(common.commandDescriptions[unitSlug])" -agent: "\(metadata.commandAgents[unitSlug])" -\(commandSkillMetadataBlocks[unitSlug]) ---- -""" - } +local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { + path = command.document.path + text = command.document.text.replaceFirst( + "\n---\n", + "\nagent: \"\(commandAgentBySlug[command.slug])\"\n\(commandSkillMetadataBySlug[command.slug])\n---\n" + ) +} + +local renderSkillDocument = (document: model.WorkflowDocument) -> new model.WorkflowDocument { + path = document.path + text = if (document.path == "SKILL.md") document.text.replaceFirst( + "\n---\n", + "\ncompatibility: opencode\n---\n" + ) else document.text } -local skillFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.skills) { +local agentFrontmatterBySlug = new Mapping { + for (unitSlug, _ in metadata.agentDisplayNames) { [unitSlug] = """ --- -name: \(unitSlug) -description: | - \(metadata.skillDescriptions[unitSlug]) -compatibility: \(metadata.skillCompatibility) +name: "\(metadata.agentDisplayNames[unitSlug])" +description: \(metadata.agentDescriptions[unitSlug]) +temperature: 0.1 +color: "\(metadata.agentColors[unitSlug])"\(metadata.agentBehaviorBlocks[unitSlug]) +\(metadata.agentPermissionBlocks[unitSlug]) --- """ } } +local agentBodyBySlug = new Mapping { + ["shared-context-plan"] = """ +Route plan creation and revision through `/change-to-plan`. +""" + ["shared-context-code"] = """ +Route implementation work through `/next-task` and final plan validation through `/validate`. +""" +} + agents { - for (unitSlug, unit in shared.agents) { + for (unitSlug, displayName in metadata.agentDisplayNames) { [unitSlug] = new common.RenderedTargetDocument { slug = unitSlug - title = unit.title + title = displayName frontmatter = agentFrontmatterBySlug[unitSlug] - body = unit.canonicalBody + body = agentBodyBySlug[unitSlug] } } } commands { - for (unitSlug, unit in shared.commands) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = commandFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } + for (workflow in workflows) { + [workflow.command.slug] = renderCommand.apply(workflow.command) } } -skills { - for (unitSlug, unit in shared.skills) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = skillFrontmatterBySlug[unitSlug] - body = unit.canonicalBody +/// Flatten package-relative document paths while retaining each skill's +/// self-contained directory layout and adding only OpenCode-supported metadata +/// to the package entrypoint. +skillDocuments { + for (workflow in workflows) { + for (skillSlug, skillPackage in workflow.skills) { + for (documentPath, document in skillPackage.documents) { + ["\(skillSlug)/\(documentPath)"] = renderSkillDocument.apply(document) + } } } } diff --git a/config/pkl/renderers/opencode-metadata.pkl b/config/pkl/renderers/opencode-metadata.pkl index 19ba5161..6af1008b 100644 --- a/config/pkl/renderers/opencode-metadata.pkl +++ b/config/pkl/renderers/opencode-metadata.pkl @@ -40,7 +40,7 @@ permission: doom_loop: ask skill: "*": ask - "sce-bootstrap-context": allow + "sce-context-load": allow "sce-plan-authoring": allow """ ["shared-context-code"] = """ @@ -66,30 +66,10 @@ permission: "*": ask "sce-plan-review": allow "sce-task-execution": allow - "sce-context-sync": allow + "sce-task-context-sync": allow "sce-validation": allow - "sce-atomic-commit": allow + "sce-plan-context-sync": allow """ } -commandAgents = new Mapping { - ["next-task"] = "Shared Context Code" - ["change-to-plan"] = "Shared Context Plan" - ["handover"] = "Shared Context Code" - ["commit"] = "Shared Context Code" - ["validate"] = "Shared Context Code" -} - -skillDescriptions = new Mapping { - ["sce-bootstrap-context"] = "Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent." - ["sce-context-sync"] = "Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth." - ["sce-handover-writer"] = "Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include \"create a handover\", \"hand this off\", \"write handover notes\", \"pass this task on\", or \"document where I'm up to\"." - ["sce-plan-authoring"] = "Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution." - ["sce-plan-authoring-interactive"] = "Use when user wants to Create or update an SCE implementation plan with interactive clarification." - ["sce-plan-review"] = "Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. \"continue the plan\", \"what's next?\", \"resume work on the plan\", \"review my plan and prepare the next task\"." - ["sce-task-execution"] = "Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md." - ["sce-atomic-commit"] = "Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad." - ["sce-validation"] = "Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out." -} - skillCompatibility = "opencode" diff --git a/config/pkl/renderers/pi-content.pkl b/config/pkl/renderers/pi-content.pkl index c6cfbcfe..09874f3f 100644 --- a/config/pkl/renderers/pi-content.pkl +++ b/config/pkl/renderers/pi-content.pkl @@ -1,82 +1,29 @@ -import "../base/shared-content.pkl" as shared -import "common.pkl" as common -import "pi-metadata.pkl" as metadata - -local commandFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.commands) { - [unitSlug] = """ ---- -description: "\(common.commandDescriptions[unitSlug])" -argument-hint: "\(metadata.commandArgumentHints[unitSlug])" ---- -""" - } -} - -local agentPromptFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.agents) { - [unitSlug] = """ ---- -description: "\(metadata.agentDescriptions[unitSlug])" -argument-hint: "\(metadata.agentArgumentHints[unitSlug])" ---- -""" - } -} - -local agentPromptBodyBySlug = new Mapping { - for (unitSlug, unit in shared.agents) { - [unitSlug] = """ -Act as the \(unit.title) agent for the rest of this session. Load and follow the `\(metadata.agentSkillReferences[unitSlug])` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -\(unit.canonicalBody) -""" - } -} - -local skillFrontmatterBySlug = new Mapping { - for (unitSlug, _ in shared.skills) { - [unitSlug] = """ ---- -name: \(unitSlug) -description: \(common.skillDescriptions[unitSlug]) ---- -""" - } -} - -agentPrompts { - for (unitSlug, unit in shared.agents) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = agentPromptFrontmatterBySlug[unitSlug] - body = agentPromptBodyBySlug[unitSlug] - } - } +import "../base/workflow-change-to-plan.pkl" as changeToPlan +import "../base/workflow-next-task.pkl" as nextTask +import "../base/workflow-validate.pkl" as validate + +/// Pi consumes the canonical workflow documents directly because those +/// documents are authored against the project-root `.pi/` baseline. +local workflows = new Listing { + changeToPlan.workflow + nextTask.workflow + validate.workflow } commands { - for (unitSlug, unit in shared.commands) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = commandFrontmatterBySlug[unitSlug] - body = unit.canonicalBody - } + for (workflow in workflows) { + [workflow.command.slug] = workflow.command.document } } -skills { - for (unitSlug, unit in shared.skills) { - [unitSlug] = new common.RenderedTargetDocument { - slug = unitSlug - title = unit.title - frontmatter = skillFrontmatterBySlug[unitSlug] - body = unit.canonicalBody +/// Flatten package-relative document paths for deterministic generation while +/// retaining each skill's self-contained directory layout. +skillDocuments { + for (workflow in workflows) { + for (skillSlug, skillPackage in workflow.skills) { + for (documentPath, document in skillPackage.documents) { + ["\(skillSlug)/\(documentPath)"] = document + } } } } diff --git a/config/pkl/renderers/pi-metadata.pkl b/config/pkl/renderers/pi-metadata.pkl deleted file mode 100644 index c2a3b894..00000000 --- a/config/pkl/renderers/pi-metadata.pkl +++ /dev/null @@ -1,22 +0,0 @@ -agentDescriptions = new Mapping { - ["shared-context-plan"] = "Act in the shared-context-plan role to create or update an SCE plan before implementation." - ["shared-context-code"] = "Act in the shared-context-code role to execute one approved SCE task and sync context." -} - -agentArgumentHints = new Mapping { - ["shared-context-plan"] = "" - ["shared-context-code"] = " [T0X]" -} - -agentSkillReferences = new Mapping { - ["shared-context-plan"] = "sce-plan-authoring" - ["shared-context-code"] = "sce-task-execution" -} - -commandArgumentHints = new Mapping { - ["next-task"] = " [T0X]" - ["change-to-plan"] = "" - ["handover"] = "[task context]" - ["commit"] = "[oneshot|skip]" - ["validate"] = "" -} diff --git a/context/architecture.md b/context/architecture.md index fa0df4fb..0d68af8a 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -10,32 +10,24 @@ The repository keeps three parallel config target trees: For authored config content, generation is standardized around one canonical Pkl source model with target-specific rendering applied later in the pipeline. -Current scaffold location for canonical shared content primitives: - -- `config/pkl/base/shared-content.pkl` (manual profile aggregation surface) -- `config/pkl/base/shared-content-common.pkl` (shared primitives) -- `config/pkl/base/shared-content-plan.pkl` (plan-focused content) -- `config/pkl/base/shared-content-code.pkl` (code-focused content) -- `config/pkl/base/shared-content-commit.pkl` (commit-focused content) -- `config/pkl/base/shared-content-automated.pkl` (automated profile aggregation surface) -- `config/pkl/base/shared-content-automated-common.pkl` -- `config/pkl/base/shared-content-automated-plan.pkl` -- `config/pkl/base/shared-content-automated-code.pkl` -- `config/pkl/base/shared-content-automated-commit.pkl` +Current location for canonical workflow content primitives: + +- `config/pkl/base/workflow-content.pkl` (workflow command and self-contained skill-package document model, including deterministic package-relative nested references) +- `config/pkl/base/workflow-change-to-plan.pkl` (canonical `/change-to-plan` package with the command plus self-contained `sce-context-load` and `sce-plan-authoring` skill/reference documents mirrored from the project-root `.pi/` baseline) +- `config/pkl/base/workflow-next-task.pkl` (canonical `/next-task` package with self-contained `sce-plan-review` and `sce-task-execution` documents plus the task instance from the shared context-sync skeleton) +- `config/pkl/base/workflow-validate.pkl` (canonical `/validate` package with the self-contained `sce-validation` documents plus the plan instance from the shared context-sync skeleton) +- `config/pkl/base/workflow-context-sync.pkl` (one role-parameterized shared-fragment skeleton that emits exact, self-contained task and plan context-sync packages) - `config/pkl/base/opencode.pkl` - `config/pkl/base/sce-config-schema.pkl` Current target renderer helper modules: - `config/pkl/renderers/opencode-content.pkl` -- `config/pkl/renderers/opencode-automated-content.pkl` - `config/pkl/renderers/claude-content.pkl` - `config/pkl/renderers/pi-content.pkl` - `config/pkl/renderers/common.pkl` - `config/pkl/renderers/opencode-metadata.pkl` -- `config/pkl/renderers/opencode-automated-metadata.pkl` - `config/pkl/renderers/claude-metadata.pkl` -- `config/pkl/renderers/pi-metadata.pkl` - `config/pkl/renderers/metadata-coverage-check.pkl` - `config/pkl/generate.pkl` (single multi-file generation entrypoint) - `config/pkl/check-generated.sh` (dev-shell integration stale-output detection against committed generated files) @@ -46,17 +38,17 @@ The scaffold provides stable canonical content-unit identifiers and reusable tar Renderer modules apply target-specific metadata/frontmatter rules while reusing canonical content bodies: -- OpenCode renderer emits frontmatter with `agent`/`permission`/`compatibility: opencode` conventions; targeted SCE commands also emit machine-readable `entry-skill` and ordered `skills` metadata when the renderer explicitly defines that mapping. -- Claude renderer emits frontmatter with `allowed-tools`/`model`/`compatibility: claude` conventions. -- Pi renderer emits prompt-template frontmatter with `description`/`argument-hint` conventions: commands render to `config/.pi/prompts/{slug}.md`, SCE agents render as agent-role prompt templates at `config/.pi/prompts/agent-{slug}.md` (act-as-role preamble + `$ARGUMENTS` input + canonical agent body), and skills render to Agent Skills-format `config/.pi/skills/{slug}/SKILL.md`. Pi has no native sub-agent format and no settings/plugin manifest; runtime integration is provided by a project-local Pi extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). -- Shared renderer contracts (`RenderedTargetDocument`, command descriptions) live in `config/pkl/renderers/common.pkl`. +- The manual OpenCode renderer consumes the three canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. +- Claude renderer consumes the three canonical workflow packages directly, extends command and skill entrypoint frontmatter with `allowed-tools` and `compatibility: claude`, flattens nested package documents, and emits exactly three commands plus seven self-contained skill packages without generated agents. Claude settings and the hook helper remain separate retained outputs. +- Pi renderer consumes the three canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly three prompts to `config/.pi/prompts/{slug}.md` and seven self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). +- Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). -- Target-specific metadata tables, including skill frontmatter descriptions, are isolated in `config/pkl/renderers/opencode-metadata.pkl`, `config/pkl/renderers/opencode-automated-metadata.pkl`, `config/pkl/renderers/claude-metadata.pkl`, and `config/pkl/renderers/pi-metadata.pkl` (Pi agent descriptions, argument hints, skill references, and command argument hints; Pi skill/command descriptions reuse the shared tables in `common.pkl`). -- Metadata key coverage is enforced by `config/pkl/renderers/metadata-coverage-check.pkl`, which resolves all required lookup keys for all targets (OpenCode manual/automated, Claude, Pi) and fails evaluation on missing entries. -- Both renderers expose per-class rendered document objects (`agents`, `commands`, `skills`) consumed by `config/pkl/generate.pkl`. -- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode/Claude agents, commands, skills, Claude project settings, the Claude hook helper script at `config/.claude/hooks/run-sce-or-show-install-guidance.sh`, shared bash-policy preset assets under `lib/`, the OpenCode plugin entrypoints under `plugins/` (currently `sce-bash-policy.ts` and `sce-agent-trace.ts`), generated OpenCode `package.json` and `opencode.json` manifests for manual and automated profiles, the Pi target tree (`config/.pi/prompts/{slug}.md` command prompts, `config/.pi/prompts/agent-{slug}.md` agent-role prompts, `config/.pi/skills/{slug}/SKILL.md`, and the Pi extension at `config/.pi/extensions/sce/index.ts` emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`), and the generated `sce/config.json` schema artifact at `config/schema/sce-config.schema.json`. +- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tool and compatibility fields. Pi workflow documents own their supported frontmatter directly. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts the exact current inventory—three commands, all 18 documents in seven self-contained skill packages, and two OpenCode agents—then forces every rendered document and target metadata lookup to evaluate across OpenCode, Claude, and Pi. +- OpenCode, Claude, and Pi renderers expose canonical command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`. +- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's three workflow commands, seven complete skill packages with nested references, and two thin routing agents; Claude's three workflow commands and seven complete skill packages with nested references but no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (three workflow prompts, seven complete skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. -- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, runs `pkl eval -m config/pkl/generate.pkl`, and fails when generated-owned paths drift. +- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, evaluates exact metadata coverage, regenerates into a temporary tree, and compares complete generated directories plus scalar/schema outputs. Complete-directory comparison covers nested references and extra stale files; explicit forbidden-path checks reject `config/automated/.opencode` and `config/.claude/agents`. The root-flake `pkl-parity` derivation mirrors this inventory from a focused source set containing all retained OpenCode, Claude, and Pi generated trees. Generated authored classes: @@ -75,7 +67,7 @@ Explicitly excluded from generation ownership: - runtime dependency artifacts (for example `node_modules`) - lockfiles and install outputs -See `context/decisions/2026-02-28-pkl-generation-architecture.md` for the full matrix and ownership table used by the plan task implementation. +See `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` for the current target matrix and ownership rationale. The original canonical-source decision in `context/decisions/2026-02-28-pkl-generation-architecture.md` remains historical background; its old paired-output inventory is superseded. ## Placeholder SCE CLI boundary @@ -193,7 +185,8 @@ Shared Context Plan and Shared Context Code remain separate architectural roles. - Shared Context Code owns exactly one approved task execution, validation, and mandatory `context/` synchronization. - `/change-to-plan` and `/next-task` remain separate command entrypoints aligned to those roles. - Reuse is handled through shared canonical guidance blocks and skill-owned phase contracts, not by collapsing both roles into one agent. -- Shared baseline doctrine for both agents is centralized in reusable constants in `config/pkl/base/shared-content-common.pkl` and interpolated into each role body at generation time; the aggregation surfaces `config/pkl/base/shared-content.pkl` (manual) and `config/pkl/base/shared-content-automated.pkl` (automated) import from grouped `plan`, `code`, and `commit` modules for downstream renderers. -- `/next-task` is a thin orchestration wrapper: it owns gate sequencing, while phase-detail contracts stay canonical in `sce-plan-review`, `sce-task-execution`, and `sce-context-sync`. -- `/change-to-plan` is a thin orchestration wrapper: it delegates clarification and plan-shape ownership to `sce-plan-authoring` (including one-task/one-atomic-commit task slicing) while retaining wrapper-level plan creation confirmation and `/next-task` handoff obligations. -- `/commit` is a thin orchestration wrapper: manual generated commands retain staged-changes confirmation and proposal-only behavior, while the automated OpenCode command skips the staging-confirmation gate, generates exactly one commit message through `sce-atomic-commit`, and runs `git commit` for the staged diff; commit grammar and plan-aware body rules stay canonical in `sce-atomic-commit`. +- OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task` and `/validate`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole Markdown behavior owners. +- `/change-to-plan` sequences `sce-context-load` and `sce-plan-authoring`, preserving context loading, clarification, plan output, and `/next-task` handoff ownership. +- `/next-task` owns one-task sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, including its implementation gate and continuation contract. +- `/validate` owns final sequencing across `sce-validation` and validated-only `sce-plan-context-sync`. +- OpenCode, Claude, and Pi expose no generated `/commit` or `/handover` command, and the automated OpenCode profile is removed. diff --git a/context/context-map.md b/context/context-map.md index 04124a0f..0fa9ac00 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -24,10 +24,9 @@ Feature/domain context: - `context/sce/cli-observability-contract.md` (implemented config-backed runtime observability contract for the flat logging config-file shape with env-over-config fallback, concrete logger/telemetry runtime behavior plus logger and object-safe telemetry trait boundaries, AppContext observability wiring, generic `RunOutcome` final rendering, runtime-classified repeated telemetry action protection, operator-facing `sce config show` observability reporting, and the trimmed `sce config validate` status-only validation surface) - `context/sce/shared-context-code-workflow.md` - `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, and one-task/one-atomic-commit task-slicing policy) -- `context/sce/plan-code-overlap-map.md` (T01 overlap matrix for Shared Context Plan/Code, related commands, and core skill ownership/dedup targets) -- `context/sce/dedup-ownership-table.md` (current-state canonical owner-vs-consumer matrix for shared SCE behavior domains and thin-command ownership boundaries) +- `context/sce/plan-code-overlap-map.md` (current overlap matrix for thin OpenCode Plan/Code routing agents, the three workflow commands, and their phase-skill ownership boundaries) +- `context/sce/dedup-ownership-table.md` (current canonical owner-vs-consumer matrix for the three workflow packages, seven phase skills, shared sync skeleton, and thin OpenCode agents) -- `context/sce/atomic-commit-workflow.md` (canonical manual-vs-automated `/commit` contract, including the single-message rule, the staged-plan commit-body requirement to cite affected plan slug(s) + updated task ID(s), automated single-commit execution behavior, and the manual-profile `/commit oneshot`/`/commit skip` argument-based bypass mode that skips staging confirmation, context-guidance gate, split guidance, and plan-citation ambiguity stops to produce one message and auto-execute `git commit`) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) - `context/sce/agent-trace-schema-adapter.md` (historical Agent Trace adapter reference for the removed `cli/src/services/agent_trace.rs` surface) @@ -55,7 +54,6 @@ Feature/domain context: - `context/sce/agent-trace-local-hooks-mvp-contract-gap-matrix.md` (T01 Local Hooks MVP production contract freeze and deterministic gap matrix for `agent-trace-local-hooks-production-mvp`) - `context/sce/agent-trace-minimal-generator.md` (implemented a library minimal Agent Trace generator seam at `cli/src/services/agent_trace.rs`, used by the active post-commit hook flow to produce strict `0.1.0` JSON payloads with top-level `version`, UUIDv7 `id` derived from commit-time metadata, caller-provided commit-time `timestamp`, optional top-level `vcs` metadata emitted when present (`type` from enum `git|jj|hg|svn`, `revision` from metadata input; current post-commit flow provides `git`), optional top-level `tool` metadata (`name`/`version`) sourced from builder metadata inputs when overlapping AI content exists, and always-emitted `metadata.sce.version` sourced from the compiled `sce` CLI package version, plus per-file trace data from patch inputs via `intersect_patches(constructed_patch, post_commit_patch)` then `post_commit_patch`-anchored hunk classification into `ai`/`mixed`/`unknown` contributor categories, serialized per conversation with a required lookup `url` derived from top-level `AgentTrace.id`, nested `contributor.type` with optional `contributor.model_id` omitted when provenance is missing, one derived `ranges[{start_line,end_line,content_hash}]` entry per post-commit or embedded-patch hunk, and range `content_hash` values that hash touched-line kind/content independent of positions and metadata) - `context/sce/agent-trace-hooks-command-routing.md` (implemented `sce hooks` command routing plus current runtime behavior: enabled-by-default commit-msg attribution with explicit opt-out controls, no-op `pre-commit`/`post-rewrite` entrypoints, active `post-commit` intersection and Agent Trace DB persistence, DB-only `diff-trace` STDIN intake with OpenCode normalized payloads and Claude structured `PostToolUse` payload classification, tool-prefixed stored `diff_traces.session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), direct nullable `model_id`/`tool_version` persistence without session fallback, Claude direct model metadata extraction from top-level or nested `model` fields with `claude/` prefix normalization, no parsed-payload artifact persistence under `context/tmp`, `session-model` removed from the supported hook surface, and `conversation-trace` STDIN intake for normalized batches plus supported raw Claude events; this document also owns the current `diff-trace` and `conversation-trace` fail-open intake contracts.) -- `context/sce/automated-profile-contract.md` (deterministic gate policy for automated OpenCode profile, including 10 gate categories, permission mappings, automated `/commit` single-commit execution behavior, and automated profile constraints) - `context/sce/bash-tool-policy-enforcement-contract.md` (approved bash-tool blocking contract plus current Rust evaluator seam and OpenCode/Claude delegation references, including config schema, argv-prefix matching, shell/nix unwrapping, custom-policy `satisfied_by` wrapper exemption, fixed preset catalog/messages, and precedence rules) - `context/sce/bash-policy-satisfied-by-wrapper-exemption.md` (custom-policy `satisfied_by` field: optional list of wrapper argv prefixes that exempt a policy from firing when the matched command was unwrapped from one of them; `NormalizedSegment` wrapper-chain tracking, matching model, examples, and scope) - `context/sce/generated-opencode-plugin-registration.md` (current generated OpenCode plugin-registration contract, canonical Pkl ownership, generated manifest/plugin paths including `sce-bash-policy` + `sce-agent-trace`, TypeScript source ownership, and Claude generated settings boundary including Agent Trace hooks plus `PreToolUse` Bash policy hook registration through the missing-CLI install-guidance helper) @@ -83,6 +81,7 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` +- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (current workflow-oriented generated target matrix; supersedes the 2026-02-28 paired-output inventory while retaining canonical Pkl ownership) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) - `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md` (retire the checkout-scoped Agent Trace DB surface; `RepositoryAgentTraceDb` is the sole adapter, no `sce trace --legacy`, no global/checkout fallback path; pre-migration on-disk files are never touched and no longer inspectable via the CLI) diff --git a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md new file mode 100644 index 00000000..c31909a6 --- /dev/null +++ b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md @@ -0,0 +1,34 @@ +# Decision: Use Workflow-Oriented Pkl Generation + +Date: 2026-07-27 +Status: Accepted +Plan: `context/plans/rebuild-pkl-workflow-markdown.md` + +## Decision + +- Model generated SCE Markdown as three canonical workflow packages: `/change-to-plan`, `/next-task`, and `/validate`. +- Use the project-root `.pi/` prompts, skills, and package-local references as the behavioral baseline. +- Generate the same seven self-contained skill packages for Pi, OpenCode, and Claude. A generated skill may share Pkl source with another skill, but it must not depend on a sibling generated package. +- Instantiate `sce-task-context-sync` and `sce-plan-context-sync` from one role-parameterized Pkl skeleton while preserving their distinct handoff gates, lifecycle boundaries, and reports. +- Keep only two generated agents, both for OpenCode and both routing-only: Plan routes to `/change-to-plan`; Code routes to `/next-task` and `/validate`. Claude and Pi receive no generated agents. +- Remove the automated OpenCode profile and obsolete generated commit, handover, bootstrap, atomic-commit, and legacy context-sync Markdown surfaces. +- Preserve retained non-Markdown generation for OpenCode plugins/config, Claude settings/hooks, the Pi extension, and the SCE config schema. + +## Rationale + +Workflow packages align generated ownership with the actual planning, task-execution, and final-validation lifecycles. Self-contained package references keep each target installable without cross-skill coupling, while one Pkl sync skeleton prevents task/plan policy drift. Thin agents avoid duplicating behavior already owned by commands and skills. + +The automated profile and obsolete Markdown catalog represented a second behavior surface with no required compatibility contract. Removing them reduces drift and makes the generated target inventory exact and parity-checkable. + +## Consequences + +- Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`. +- Generated inventory is three commands and seven skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. +- `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/check-generated.sh`, and the root flake parity check enforce exact inventories, nested package references, and forbidden removed trees. +- `config/automated/.opencode` and `config/.claude/agents` are forbidden outputs rather than compatibility surfaces. + +## Superseded scope + +This decision supersedes the generated path matrix, paired-output counts, and target inventory in `2026-02-28-pkl-generation-architecture.md`. That decision's canonical-Pkl-source, deterministic-rendering, and generated-vs-runtime ownership principles remain in force. + +The separate Plan/Code role decision in `2026-03-03-plan-code-agent-separation.md` remains in force, with agents now explicitly limited to routing. diff --git a/context/glossary.md b/context/glossary.md index 49b9d82e..03eb624c 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -1,19 +1,19 @@ # Glossary -- `pkl-check-generated`: Flake app command exposed as `nix run .#pkl-check-generated`; canonical lightweight parity test entrypoint that runs the generated-output drift check inside the Nix dev shell. +- `pkl-check-generated`: Flake app command exposed as `nix run .#pkl-check-generated`; canonical lightweight parity entrypoint that evaluates the exact workflow-document inventory, compares complete generated OpenCode/Claude/Pi directories plus retained scalar/schema outputs, and rejects explicitly removed generated trees inside the Nix dev shell. - `repo-level verification preference`: Current repository guidance that contributor-facing validation/check flows should prefer `nix flake check`; direct Cargo verification commands are secondary and used only when explicitly requested or for narrow targeted debugging, while `cargo fmt` remains the explicit autofix path. - lightweight post-task verification baseline: Required quick checks after each completed task in this repo: `nix run .#pkl-check-generated` and `nix flake check`. - disposable plan lifecycle: Policy where `context/plans/` holds active execution artifacts only; completed plans are disposable and durable outcomes must be reflected in current-state context files and/or `context/decisions/`. - important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. -- generated-owned outputs: Files materialized by `config/pkl/generate.pkl` under `config/.opencode/**`, `config/automated/.opencode/**`, `config/.claude/**`, and `config/.pi/**`, including OpenCode plugin entrypoints, generated OpenCode `package.json` manifests, generated OpenCode `opencode.json` manifests, generated Claude plugin entrypoints, Claude settings assets, Pi prompt/skill assets, and the Pi extension entrypoint at `config/.pi/extensions/sce/index.ts`. -- `Pi agent-role prompt template`: Generated Pi prompt at `config/.pi/prompts/agent-{slug}.md` that adapts an SCE agent (shared-context-plan, shared-context-code) to Pi, which has no native sub-agent format: frontmatter carries `description`/`argument-hint`, and the body prepends an act-as-role preamble plus `$ARGUMENTS` input before the canonical agent body. Rendered by `config/pkl/renderers/pi-content.pkl` with metadata from `config/pkl/renderers/pi-metadata.pkl`. +- generated-owned outputs: Files materialized by `config/pkl/generate.pkl` under `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**`, including OpenCode plugin entrypoints and `opencode.json`, Claude hook/settings assets, Pi prompt/skill assets, and the Pi extension entrypoint at `config/.pi/extensions/sce/index.ts`; `config/automated/.opencode/**` is explicitly removed from generation ownership. +- `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, and `/validate` this way and has no generated agent-role prompts. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. - `repository identity`: Stable identity of a logical Git repository used to select the active repository-scoped Agent Trace DB path `/sce/repos//agent-trace.db` through the `agent_trace_storage` resolver. Resolved by `cli/src/services/repository_identity/` with precedence: explicit `agent_trace.repository_id` config value, then the URL of the configured Git remote (`agent_trace.repository_remote`, default `origin`), otherwise an actionable `.sce/config.json` error. Remote URLs canonicalize to a scheme-neutral, credential-free `host[:port]/path` form so equivalent SSH/SCP/HTTPS remotes converge, and the repository ID is `sha256("sce-repository-id-v1\0" + canonical_identity)` hex. Distinct from `checkout identity`, which stays per clone/worktree for diagnostics. See `context/cli/repository-identity.md`. - `repository-scoped Agent Trace DB`: Active Agent Trace storage shape where one logical Git repository maps to `/sce/repos//agent-trace.db`. The current seam is `RepositoryAgentTraceDb = TursoDb` in `cli/src/services/agent_trace_db/repository.rs`, backed by one fresh multi-statement schema file with `repository_metadata` plus repository-level trace tables, no `checkout_id` columns, and typed repository-level insert helpers for diff traces, post-commit intersections, Agent Trace rows, messages, and parts. Hook runtime, Agent Trace setup/lifecycle, and `sce trace` status/list/shell flows resolve repository-scoped storage through `agent_trace_storage`. This is the sole Agent Trace DB adapter; the checkout-scoped adapter and the `sce trace --legacy` inspection surface were removed by the `retire-legacy-agent-trace-db` plan. - `checkout registry` (removed): The central JSON registry at `/sce/checkout-registry.json` was removed in the `remove-checkout-registry` plan. `sce trace db list` now discovers checkouts by scanning `/sce/agent-trace-*.db` files on disk. `checkout_id`, `database_path`, and `last_seen` (from file mtime) are derived from the filesystem; `path` and `remote_url` are no longer rendered. See `context/cli/checkout-identity.md`. -- `generated OpenCode plugin registration contract`: Current generated-config contract where `config/.opencode/opencode.json` and `config/automated/.opencode/opencode.json` serialize the OpenCode `plugin` field from canonical Pkl sources for SCE-managed plugins only; the current registered paths are `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts`. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`. +- `generated OpenCode plugin registration contract`: Current generated-config contract where `config/.opencode/opencode.json` serializes the OpenCode `plugin` field from canonical Pkl sources for SCE-managed plugins only; the current registered paths are `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts`. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`. - `root Biome contract`: Repository-root formatting/linting contract owned by `biome.json`, currently scoped only to `npm/**` and the shared `config/lib/**` plugin package root with package-local `node_modules/**` excluded; the canonical execution path is the root Nix dev shell (`nix develop -c biome ...`). - `cli flake checks`: Check derivations in root `flake.nix` (`checks..cli-tests`, `cli-clippy`, `cli-fmt`), plus `pkl-parity`, `workflow-actionlint`, split `npm/` JS checks (`npm-bun-tests`, `npm-biome-check`, `npm-biome-format`), split shared `config/lib/` JS checks (`config-lib-bun-tests`, `config-lib-biome-check`, `config-lib-biome-format`), and Linux-only Flatpak checks; invoked via `nix flake check` at repo root. - `npm JS flake checks`: The current `npm/` validation slice exposed by root `flake.nix`: `npm-bun-tests` runs only `bun test ./test/*.test.js`, `npm-biome-check` runs only Biome lint/check with formatter verification disabled, and `npm-biome-format` runs only Biome format verification with linter checks disabled. @@ -123,7 +123,7 @@ - `StagedDiffAiOverlapResult`: Three-valued enum in `cli/src/services/hooks/mod.rs` returned by the staged-diff AI-overlap evidence check: `Overlap` (staged diff overlaps with at least one recent AI/editor diff trace), `NoOverlap` (no overlap found; staged diff and recent traces were both available but share no touched lines, or staged patch has no touched lines), `Error` (DB open failure, schema not ready, query error, staged diff read failure, or clock failure). Both `NoOverlap` and `Error` map to `ai_contribution_present = false` at the commit-msg policy seam; `Error` additionally triggers `sce.hooks.commit_msg.ai_overlap_error` logging. - `sce.hooks.commit_msg.ai_overlap_error`: Logger event ID emitted by `staged_diff_has_ai_overlap` when the staged-diff AI-overlap preflight encounters an error (DB open failure, schema not ready, query error, staged diff read failure, or clock failure). - `bash policy preset catalog`: Canonical authored preset source at `config/pkl/base/bash-policy-presets.pkl`, rendered to JSON by `config/pkl/generate.pkl` and embedded by the CLI from `config/.opencode/lib/bash-policy-presets.json` so CLI validation and OpenCode enforcement share the same preset IDs, argv-prefix matchers, fixed messages, and conflict metadata. -- `OpenCode bash policy plugin`: Generated OpenCode pre-execution hook at `config/.opencode/plugins/sce-bash-policy.ts` (also emitted under `config/automated/.opencode/**`) that intercepts `bash` tool calls and delegates to the Rust `sce policy bash --input normalized --output json` command via `spawnSync`. The plugin is a thin wrapper that throws a stable `Blocked by SCE bash-tool policy '': ` denial on deny decisions and fails open (allows commands) when `sce` is unavailable or returns errors. The former TypeScript runtime (`bash-policy/runtime.ts`) has been removed; all policy evaluation is now owned by the Rust evaluator in `cli/src/services/bash_policy.rs`. +- `OpenCode bash policy plugin`: Generated OpenCode pre-execution hook at `config/.opencode/plugins/sce-bash-policy.ts` that intercepts `bash` tool calls and delegates to the Rust `sce policy bash --input normalized --output json` command via `spawnSync`. The plugin is a thin wrapper that throws a stable `Blocked by SCE bash-tool policy '': ` denial on deny decisions and fails open (allows commands) when `sce` is unavailable or returns errors. The former TypeScript runtime (`bash-policy/runtime.ts`) has been removed; all policy evaluation is now owned by the Rust evaluator in `cli/src/services/bash_policy.rs`. - `Rust bash-policy evaluator seam`: CLI-agnostic evaluator in `cli/src/services/bash_policy.rs` for the active Claude/OpenCode Rust-hook migration. It reuses the embedded preset catalog exposed by `cli/src/services/config/policy.rs`, parses shell segments, unwraps supported env/shell/nix wrappers, applies longest-prefix/custom-over-preset precedence, and formats the canonical SCE denial message. The evaluator is exposed through the hidden `sce policy bash` command adapter for hook callers. - `sce policy command adapter`: Hidden/internal `sce policy bash` command in `cli/src/services/bash_policy.rs` that exposes the Rust bash-policy evaluator to hook callers. It reads JSON from STDIN, resolves bash-policy config from the project root (git root with current-directory fallback), evaluates the command against active policies, and emits hook-safe output: Claude Code deny JSON (`hookSpecificOutput` with `permissionDecision: "deny"`) or empty string for allowed commands in `--output claude-hook` mode (default), and structured `{"status","decision","command","normalized_argv","reason","policy_id"}` JSON in `--output json` mode. Input modes are `--input claude-pre-tool-use` (default, parses Claude `PreToolUse` event JSON with `tool_name`/`tool_input.command`) and `--input normalized` (parses `{"command":...}` for OpenCode delegation). The command uses explicit `--input`/`--output` flags rather than auto-detection; Claude Code hooks invoke `sce policy bash` with defaults, while OpenCode plugin delegation passes `--input normalized --output json`. Invalid invocation/input returns deterministic validation diagnostics without executing target commands. - `bash policy redundancy warning`: Non-fatal config validation output emitted when `forbid-git-all` and `forbid-git-commit` are enabled together; the config remains valid, but `sce config show|validate` reports the overlap deterministically as a warning instead of an error. @@ -134,32 +134,24 @@ - `Claude raw hook capture (removed)`: Former hidden/internal `sce hooks claude-capture ` intake path removed in T05 of the `claude-typescript-model-cache-remove-rust-capture` plan. Rust now exposes `diff-trace` and `conversation-trace` intakes for active Claude/OpenCode editor runtimes; `session-model` is also removed from the supported hook command surface. The removed route previously wrote pretty-printed JSON artifacts under `context/tmp/claude/` without AgentTraceDb writes. See `context/sce/claude-raw-hook-capture.md`. - `cloud sync gateway placeholder`: Abstraction in `cli/src/services/sync.rs` (`CloudSyncGateway`) that returns deferred cloud-sync checkpoints while `sync` remains non-production. - `sce CLI onboarding guide`: Crate-local documentation at `cli/README.md` that defines runnable placeholder commands, non-goals/safety limits, and roadmap mapping to service modules. -- `plan/code overlap map`: Context artifact at `context/sce/plan-code-overlap-map.md` that classifies Shared Context Plan/Code, `/change-to-plan`, `/next-task`, `/commit`, and core skills into role-specific vs shared-reusable instruction blocks with explicit dedup targets. +- `plan/code overlap map`: Context artifact at `context/sce/plan-code-overlap-map.md` that classifies the thin OpenCode Plan/Code agents, `/change-to-plan`, `/next-task`, `/validate`, and their phase skills into routing, orchestration, and behavior ownership boundaries. - `SCE dedup ownership table`: Context artifact at `context/sce/dedup-ownership-table.md` that assigns one canonical owner per shared behavior domain, lists reference-only consumers, and labels each overlap as `intentional/keep` or `dedup/remove`. - `shared context plan workflow`: Canonical workflow document at `context/sce/shared-context-plan-workflow.md` defining `/change-to-plan` planning flow, clarification gate semantics, readiness contract, and `/next-task` handoff format. -- `commit` command (SCE): Canonical generated command slug for staged-change commit workflows; the manual command remains proposal-only from `config/pkl/base/shared-content-commit.pkl`, while the automated OpenCode variant in `config/pkl/base/shared-content-automated-commit.pkl` generates exactly one commit message and runs `git commit` for the staged diff. When staged changes include `context/plans/*.md`, the shared commit workflow also requires the commit body to cite the affected plan slug(s) and updated task ID(s) rather than inventing them. -- `sce-atomic-commit`: Canonical generated skill slug for atomic commit planning/message authoring; `atomic-commits` is treated as legacy wording and not the canonical generated skill name. -- `SCE Plan/Code role separation`: Architecture decision recorded in `context/decisions/2026-03-03-plan-code-agent-separation.md` that keeps Shared Context Plan (`/change-to-plan`) and Shared Context Code (`/next-task`) as separate roles; dedup is handled through shared canonical guidance and skill-owned contracts rather than agent merge. -- `shared SCE baseline snippets`: Reusable canonical blocks in `config/pkl/base/shared-content-common.pkl` (`sharedSceCorePrinciplesSection`, `sharedSceContextAuthoritySection`, `sharedSceQualityPosturePrefixBullets`, `sharedSceLongTermQualityBullet`) composed into both Shared Context Plan and Shared Context Code agent bodies to remove duplicated baseline doctrine text while preserving role-specific sections; aggregated through `config/pkl/base/shared-content.pkl` for downstream renderers. -- `next-task thin orchestration contract`: `/next-task` command-body pattern where the command keeps sequencing/readiness gates and delegates detailed behavior ownership to `sce-plan-review`, `sce-task-execution`, and `sce-context-sync`. -- `change-to-plan thin orchestration contract`: `/change-to-plan` command-body pattern where the command stays wrapper-level and delegates clarification/ambiguity handling plus plan-shape contracts (including one-task/one-atomic-commit task slicing) to `sce-plan-authoring`, while keeping plan creation confirmation and `/next-task` handoff explicit. -- `OpenCode command skill metadata`: machine-readable frontmatter emitted for targeted generated OpenCode commands in `config/.opencode/command/*.md`, using `entry-skill` for the initial skill and `skills` for the ordered skill chain defined by `config/pkl/renderers/opencode-content.pkl`. +- `SCE Plan/Code role separation`: Architecture decision recorded in `context/decisions/2026-03-03-plan-code-agent-separation.md` that keeps Shared Context Plan and Shared Context Code as separate OpenCode routing roles. The thin Plan agent routes to `/change-to-plan`; the thin Code agent routes to `/next-task` and `/validate`; canonical commands and skills own behavior. +- `next-task thin orchestration contract`: `/next-task` command pattern where the command keeps one-task sequencing/readiness gates and delegates phase behavior to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. +- `change-to-plan thin orchestration contract`: `/change-to-plan` command pattern that sequences `sce-context-load` before `sce-plan-authoring`, preserving clarification, plan output, and `/next-task` handoff contracts in their declared owners. +- `validate thin orchestration contract`: `/validate` command pattern that delegates final checks to `sce-validation` and invokes `sce-plan-context-sync` only after a validated result. +- `OpenCode command skill metadata`: Machine-readable frontmatter on the three generated OpenCode workflow commands, using `entry-skill` for the initial phase and `skills` for the complete ordered chain defined by `config/pkl/renderers/opencode-content.pkl`. - `one-task/one-atomic-commit planning contract`: `sce-plan-authoring` requirement that each executable plan task represents one coherent commit unit; broad multi-commit tasks must be split into sequential atomic tasks before execution handoff. -- `commit thin orchestration contract`: `/commit` command-body pattern where the command stays wrapper-level while `sce-atomic-commit` owns commit-message grammar, the profile-specific proposal contract (manual allows split guidance when staged changes mix unrelated goals; automated enforces single-message), and staged-plan body citation rules (affected plan slug(s) plus updated task ID(s) for staged `context/plans/*.md` edits); manual generated commands remain proposal-only with staging confirmation, while the automated OpenCode command skips staging confirmation and executes one staged `git commit`. - `agent trace historical reference docs`: Retained `context/sce/agent-trace-*.md` artifacts that describe the removed pre-v0.3 Agent Trace design and task slices; they are reference-only and do not describe the active local-hook runtime. - `agent trace commit-msg co-author policy`: Current contract in `cli/src/services/hooks/mod.rs` (`apply_commit_msg_coauthor_policy`) that applies exactly one canonical trailer (`Co-authored-by: SCE `) only when attribution hooks are enabled, SCE is not disabled, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); `NoOverlap` and `Error` both suppress the trailer, with `Error` logged via `sce.hooks.commit_msg.ai_overlap_error`; duplicate canonical trailers are deduped idempotently. - `local DB migration contract`: `cli/src/services/local_db/mod.rs` delegates migration execution to `TursoDb` through the `DbSpec::migrations()` contract. The current `LocalDbSpec` migration list is empty, so `LocalDb::new()` opens/creates the canonical local DB without creating local tables. - `hook no-op baseline`: Current `cli/src/services/hooks/mod.rs` runtime posture where `pre-commit` and `post-rewrite` return deterministic no-op status text, `commit-msg` is a gated mutating path, `post-commit` persists intersections and built Agent Trace payloads without post-commit file artifacts, `diff-trace` validates STDIN payloads, uses only direct payload `model_id` and `tool_version` (session-model fallback removed), applies stored `session_id` prefixes (`oc_`/`cc_`/`pi_`), and inserts DB-only AgentTraceDb rows, and `conversation-trace` is the active message/part intake path. `session-model` is no longer a supported hook route. -- `sce doctor` operator-health contract: `cli/src/services/doctor/mod.rs` is the stable doctor entrypoint, with focused `doctor/{inspect,render,fixes,types}.rs` submodules implementing the current approved operator-health surface in `context/sce/agent-trace-hook-doctor.md`: `sce doctor --fix` selects repair intent, Agent Trace DB discovery is repository-scoped only (the checkout-scoped `sce trace --legacy` surface was removed by the `retire-legacy-agent-trace-db` plan), and output exposes deterministic doctor mode, readiness, stable problem taxonomy/fixability fields, checkout/database records, and fix-result records. The runtime validates state-root resolution, global and repo-local `sce/config.json` readability/schema health, local DB and repository-scoped Agent Trace DB path/health, DB-parent readiness barriers, git availability, non-repo vs bare-repo targeting failures, effective hook-path source resolution, required hook presence/executable/content drift against canonical embedded hook assets, and repo-root installed OpenCode, Claude, plus Pi integration content health. Human text mode uses the approved sectioned layout (`Environment`, `Configuration` with checkout identity plus repository-scoped Agent Trace DB rows when available, `Repository`, `Git Hooks`, `Integrations`), `SCE doctor diagnose` / `SCE doctor fix` headers, bracketed `[PASS]`/`[FAIL]`/`[MISS]` status tokens with shared-style green/red colorization when enabled, simplified `label (path)` row formatting, top-level-only hook rows, and integration parent/child rows where missing files surface as `[MISS]`, mismatches/read failures as `[FAIL]`, and affected parent groups as `[FAIL]`. Agent Trace DB rows include repository ID, identity source, safe canonical identity, configured remote name, and never raw remote URLs. Current integration groups include `OpenCode plugins`, `OpenCode agents`, `OpenCode commands`, `OpenCode skills`, `ClaudeCode plugins`, `ClaudeCode agents`, `ClaudeCode commands`, `ClaudeCode skills`, `Pi prompts`, and `Pi skills`; Claude `settings.json` plus `hooks/**` belong to `ClaudeCode plugins`, including `.claude/hooks/run-sce-or-show-install-guidance.sh`, while Pi `prompts/**` and `skills/**` map to the Pi groups. Fix mode reuses canonical setup hook installation for missing/stale/non-executable required hooks and missing hooks directories and can bootstrap canonical missing SCE-owned DB parent directories. +- `sce doctor` operator-health contract: `cli/src/services/doctor/mod.rs` is the stable doctor entrypoint, with focused `doctor/{inspect,render,fixes,types}.rs` submodules implementing the current approved operator-health surface in `context/sce/agent-trace-hook-doctor.md`: `sce doctor --fix` selects repair intent, Agent Trace DB discovery is repository-scoped only (the checkout-scoped `sce trace --legacy` surface was removed by the `retire-legacy-agent-trace-db` plan), and output exposes deterministic doctor mode, readiness, stable problem taxonomy/fixability fields, checkout/database records, and fix-result records. The runtime validates state-root resolution, global and repo-local `sce/config.json` readability/schema health, local DB and repository-scoped Agent Trace DB path/health, DB-parent readiness barriers, git availability, non-repo vs bare-repo targeting failures, effective hook-path source resolution, required hook presence/executable/content drift against canonical embedded hook assets, and repo-root installed OpenCode, Claude, plus Pi integration content health. Human text mode uses the approved sectioned layout (`Environment`, `Configuration` with checkout identity plus repository-scoped Agent Trace DB rows when available, `Repository`, `Git Hooks`, `Integrations`), `SCE doctor diagnose` / `SCE doctor fix` headers, bracketed `[PASS]`/`[FAIL]`/`[MISS]` status tokens with shared-style green/red colorization when enabled, simplified `label (path)` row formatting, top-level-only hook rows, and integration parent/child rows where missing files surface as `[MISS]`, mismatches/read failures as `[FAIL]`, and affected parent groups as `[FAIL]`. Agent Trace DB rows include repository ID, identity source, safe canonical identity, configured remote name, and never raw remote URLs. Current integration groups include `OpenCode plugins`, `OpenCode agents`, `OpenCode commands`, `OpenCode skills`, `ClaudeCode plugins`, `ClaudeCode commands`, `ClaudeCode skills`, `Pi prompts`, and `Pi skills`; Claude `settings.json` plus `hooks/**` belong to `ClaudeCode plugins`, including `.claude/hooks/run-sce-or-show-install-guidance.sh`, while Pi `prompts/**` and `skills/**` map to the Pi groups. Fix mode reuses canonical setup hook installation for missing/stale/non-executable required hooks and missing hooks directories and can bootstrap canonical missing SCE-owned DB parent directories. - `cli warnings-denied lint policy`: `cli/Cargo.toml` sets `warnings = "deny"`, so plain `cargo clippy --manifest-path cli/Cargo.toml` already fails on warnings without needing an extra `-- -D warnings` tail. - `agent trace local DB schema migration contract`: Retired `apply_core_schema_migrations` behavior removed from the current runtime during `agent-trace-removal-and-hook-noop-reset` T01; the local DB baseline is now file open/create only. - `agent trace removed local-hook paths`: Current-state shorthand for the removed local-hook runtime behaviors that are no longer active: staged-checkpoint persistence, post-commit dual-write, post-rewrite remap ingestion, rewrite trace transformation, and retry replay. - `agent trace local hooks MVP contract and gap matrix`: T01 context artifact at `context/sce/agent-trace-local-hooks-mvp-contract-gap-matrix.md` that freezes local production boundaries/decisions for `agent-trace-local-hooks-production-mvp` and maps current seam-level code truth to required runtime completion tasks (`T02`..`T10`). -- `automated profile`: Non-interactive OpenCode configuration variant generated at `config/automated/.opencode/**` that removes ask/confirm gates and applies deterministic behavior policies defined in `context/sce/automated-profile-contract.md`. -- `automated profile contract`: Context artifact at `context/sce/automated-profile-contract.md` defining deterministic gate policies (10 categories: P1-P10), permission mappings, and automated profile constraints for non-interactive SCE workflows. -- `auto-block`: Automated profile gate action that stops execution with structured error when conditions are not met; used for safety-critical gates like scope expansion, multi-task execution, and missing context. -- `auto-allow`: Automated profile gate action that proceeds without confirmation; used for safe operations like file reads, skill loading, and context-only edits. -- `auto-proceed`: Automated profile gate action that continues execution with logging but without waiting for confirmation; used for implementation stop and commit staging gates. - `sce install channel contract`: Current `sce` install/distribution scope captured in `context/sce/cli-first-install-channels-contract.md`: supported channels are repo-flake Nix, Cargo, npm, and source-built Flatpak with application ID `dev.crocoder.sce`; `Homebrew` is deferred from the active implementation stage. - `Flatpak source-built channel`: Official `sce` distribution channel for application ID `dev.crocoder.sce` where `packaging/flatpak/dev.crocoder.sce.yml` builds the Rust CLI from source inside Flatpak rather than consuming Nix-built, GitHub Release, npm native, or other prebuilt `sce` artifacts. Both `packaging/flatpak/dev.crocoder.sce.yml` and `packaging/flatpak/cargo-sources.json` are checked-in generated artifacts: the manifest YAML is rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`, alpha-sorted block-style YAML produced via remarshal), and `cargo-sources.json` is produced from `cli/Cargo.lock` by a Nix derivation wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py`; both are guarded by `flatpak-manifest-parity` and `cargo-sources-parity` flake checks. The Nix manifest function exposes release-pin, local-checkout-override (Flatpak `type: dir`), and commit-pinned-for-release-package flavors; `packaging/flatpak/sce-flatpak.sh` is a thin imperative orchestrator around `flatpak-builder` and `flatpak build-bundle`, with no manifest text rewriting and no embedded Python. - `Flatpak host-git bridge`: Runtime Git access decision for the `sce` Flatpak package: `packaging/flatpak/git-host-bridge` is installed as `/app/bin/git` and delegates to `flatpak-spawn --host git`, with the Flatpak permission for `org.freedesktop.Flatpak` explicitly present in the manifest. diff --git a/context/overview.md b/context/overview.md index 73f10d28..c2f05ff4 100644 --- a/context/overview.md +++ b/context/overview.md @@ -1,6 +1,6 @@ # Overview -This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. It validates that generated outputs stay deterministic and in sync via `nix run .#pkl-check-generated` and `nix flake check`. It supports both manual and automated profile variants; the automated profile applies deterministic non-interactive behavior for CI/automation workflows. +This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. It validates that generated outputs stay deterministic and in sync via `nix run .#pkl-check-generated` and `nix flake check`. The generated target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. It also includes a Rust CLI (`sce`) for Shared Context Engineering workflows: auth, config inspection, setup, doctor, agent-trace hooks, bash-policy evaluation, and trace database inspection. See `context/architecture.md` for module-level boundaries and `context/context-map.md` for the full domain file index. @@ -34,7 +34,7 @@ The shared default path service in `cli/src/services/default_paths.rs` is now th The Rust CLI also centralizes SCE-owned web URI construction in `cli/src/services/agent_trace.rs`, with `SCE_WEB_BASE_URL` as the single Rust owner for `https://sce.crocoder.dev` and helpers consumed by Agent Trace conversation URLs, Agent Trace persisted trace URLs, Agent Trace session URLs, and setup-created repo-local config schema URLs. The same config resolver now also owns the attribution-hooks gate used by local hook runtime: opt-out env `SCE_ATTRIBUTION_HOOKS_DISABLED` overrides `policies.attribution_hooks.enabled` with inverted semantics, and the gate defaults to enabled unless explicitly disabled. The config service split now includes `cli/src/services/config/resolver.rs` as the focused owner for config-file discovery, file-layer merging, env/flag/default precedence, auth-key resolution, observability resolution, attribution-hooks resolution, and default-discovered invalid-file degradation; `cli/src/services/config/mod.rs` remains the facade/rendering orchestration surface while preserving existing `services::config` imports. -Generated config now includes repo-local plugin assets for both profiles: `sce-bash-policy.ts` plus `sce-agent-trace.ts` are emitted under `config/.opencode/plugins/` and `config/automated/.opencode/plugins/`; the OpenCode agent-trace plugin extracts `{ sessionID, diff, time, model_id }` from user `message.updated` events with diffs, tracks per-session OpenCode client version from `session.created`/`session.updated`, and sends payloads to `sce hooks diff-trace` with `tool_name="opencode"` plus optional `tool_version`. Claude generated config now routes supported `PostToolUse Write|Edit|MultiEdit|NotebookEdit` events directly to `sce hooks diff-trace`; it no longer registers a `SessionStart` hook or calls `sce hooks session-model`. Rust handles extraction, validation, and persistence without a TypeScript intermediary; the former `config/.claude/plugins/sce-agent-trace.ts` Bun runtime was removed in T07 of the `claude-rust-diff-trace` plan. The Rust hook validates required fields, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and persists tool-prefixed `session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), `model_id`, `tool_name`, and nullable `tool_version` into `diff_traces` through AgentTraceDb. Bash-policy now delegates OpenCode enforcement to the Rust `sce policy bash` command: the generated OpenCode plugin at `config/.opencode/plugins/sce-bash-policy.ts` (and `config/automated/.opencode/plugins/sce-bash-policy.ts`) is a thin wrapper that calls `sce policy bash --input normalized --output json` via `spawnSync` and throws on deny decisions; it no longer contains independent TypeScript policy logic. The former `bash-policy/runtime.ts` TypeScript runtime has been removed. Preset... +Generated config now includes repo-local OpenCode plugin assets: `sce-bash-policy.ts` plus `sce-agent-trace.ts` are emitted under `config/.opencode/plugins/`; the OpenCode agent-trace plugin extracts `{ sessionID, diff, time, model_id }` from user `message.updated` events with diffs, tracks per-session OpenCode client version from `session.created`/`session.updated`, and sends payloads to `sce hooks diff-trace` with `tool_name="opencode"` plus optional `tool_version`. Claude generated config now routes supported `PostToolUse Write|Edit|MultiEdit|NotebookEdit` events directly to `sce hooks diff-trace`; it no longer registers a `SessionStart` hook or calls `sce hooks session-model`. Rust handles extraction, validation, and persistence without a TypeScript intermediary; the former `config/.claude/plugins/sce-agent-trace.ts` Bun runtime was removed in T07 of the `claude-rust-diff-trace` plan. The Rust hook validates required fields, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and persists tool-prefixed `session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), `model_id`, `tool_name`, and nullable `tool_version` into `diff_traces` through AgentTraceDb. Bash-policy now delegates OpenCode enforcement to the Rust `sce policy bash` command: the generated OpenCode plugin at `config/.opencode/plugins/sce-bash-policy.ts` is a thin wrapper that calls `sce policy bash --input normalized --output json` via `spawnSync` and throws on deny decisions; it no longer contains independent TypeScript policy logic. The former `bash-policy/runtime.ts` TypeScript runtime has been removed. Preset... Claude bash-policy enforcement is also generated through `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`, so Claude and OpenCode both delegate to the Rust policy evaluator without a Claude TypeScript runtime. Pi bash-policy enforcement is delegated the same way through a project-local Pi extension (`config/lib/pi-plugin/sce-pi-extension.ts`, emitted to `config/.pi/extensions/sce/index.ts`) whose `tool_call` handler blocks denied bash commands via `sce policy bash` and fails open when the policy check cannot run (see `context/sce/pi-extension-runtime.md`). Local database bootstrap is now owned by `LocalDbLifecycle::setup` and `AgentTraceDbLifecycle::setup` aggregated by the setup command. Agent Trace setup creates/reuses the current checkout ID for diagnostics and initializes the repository-scoped `/sce/repos//agent-trace.db` with the repository schema; hook runtime lazily creates or upgrades that repository DB when setup has not run or schema metadata is incomplete. Doctor validates the repository-scoped DB path/health and can bootstrap missing parent directories; outside a Git repository it reports an actionable "requires a Git repository" diagnostic instead of probing a sentinel path. The `sce trace` group operates only on repository-scoped DBs for list/status/status-all/shell UX; the checkout-scoped `--legacy` surface was removed by the `retire-legacy-agent-trace-db` plan (see `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md`). Wiring a user-invocable `sce sync` command is deferred to `0.4.0`. The repository-root flake (`flake.nix`) now applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline with filtered package sources for the Cargo tree plus required embedded config/assets, and runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed check derivations (`cargoTest`, `cargoClippy`, `cargoFmt`) that reuse the same filtered source/toolchain setup. @@ -45,7 +45,7 @@ The CLI Cargo package metadata now includes crates.io publication-ready fields w The repository-root flake is now the single Nix entrypoint for both repo tooling and CLI packaging/checks, so root-level `nix flake check` evaluates the Crane-backed CLI checks (`cli-tests`, `cli-clippy`, `cli-fmt`), Linux-only `flatpak-static-validation`, `workflow-actionlint` (runs `actionlint` on all `.github/workflows/*.yml`), plus six split JavaScript check derivations: `npm-bun-tests`, `npm-biome-check`, `npm-biome-format`, `config-lib-bun-tests`, `config-lib-biome-check`, and `config-lib-biome-format`, without nested-flake indirection. The config-lib checks now consume `config/lib/` as the shared Bun/TypeScript package root for both `agent-trace-plugin/` and `bash-policy-plugin`, with dependencies resolved from `config/lib/package.json` and `config/lib/bun.lock`. For Cargo packaging/builds, the crate now compiles against a temporary `cli/assets/generated/` mirror prepared from canonical `config/` outputs during Nix builds and crates.io publish runs rather than from a committed crate-local snapshot. Config-lib JS flake checks execute from `config/lib/`, but the copied Nix check source is repo-shaped when tests require shared repo fixtures; the current Claude agent-trace golden tests are fully Rust-owned in `cli/src/services/structured_patch/fixtures` (Claude TypeScript plugin test removed in T07). Local developer Nix tuning guidance now lives in `AGENTS.md`, including optional user-level `~/.config/nix/nix.conf` recommendations for `max-jobs` and `cores` plus an explicit system-level-only note for `auto-optimise-store`. -The Pkl authoring layer owns generated OpenCode plugin registration for SCE-managed plugins: `config/pkl/base/opencode.pkl` defines the canonical plugin entries, `config/pkl/renderers/common.pkl` re-exports the shared plugin list for renderer use, and generated `config/.opencode/opencode.json` plus `config/automated/.opencode/opencode.json` register `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts` through OpenCode's `plugin` field. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook routed through `.claude/hooks/run-sce-or-show-install-guidance.sh` before running `sce policy bash`. +The Pkl authoring layer owns generated OpenCode plugin registration for SCE-managed plugins: `config/pkl/base/opencode.pkl` defines the canonical plugin entries, `config/pkl/renderers/common.pkl` re-exports the shared plugin list for renderer use, and generated `config/.opencode/opencode.json` registers `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts` through OpenCode's `plugin` field. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook routed through `.claude/hooks/run-sce-or-show-install-guidance.sh` before running `sce policy bash`. The current CLI install/distribution contract for `sce` includes repo-flake Nix, Cargo, npm, and source-built Flatpak (`dev.crocoder.sce`) as supported channels, while `Homebrew` remains deferred from the current implementation stage. Nix-managed build/release entrypoints are the source of truth for existing binary rollout surfaces, npm consumes Nix-produced release artifacts, and repo-root `.version` is the canonical checked-in release version source that release packaging and downstream Cargo/npm publication must match. Flatpak is the approved source-built exception to binary artifact reuse: its package must build the Rust CLI from source inside Flatpak, use a Flathub-style release-source manifest plus a Nix-generated local checkout override for local builds, prepare generated CLI assets from checked-in `config/` inputs, and provide Git access through a `/app/bin/git` wrapper delegating to `flatpak-spawn --host git` with the required `org.freedesktop.Flatpak` permission. The active Flatpak release contract approves GitHub Release source-manifest assets (manifest tarball, checksum, and JSON metadata) and source-built `.flatpak` bundle assets (`sce-v-x86_64.flatpak` / `sce-v-aarch64.flatpak` plus `.sha256` / `.json`), with `.github/workflows/release-sce.yml` building/uploading those assets alongside CLI/npm assets, while still excluding automatic Flathub submission, prebuilt (non-source-built) Flatpak binaries/bundles, OSTree repositories, and release-version bumping. The shared release artifact foundation is now implemented through root-flake apps `release-artifacts` and `release-manifest`, which emit canonical `sce-v-.tar.gz` archives, SHA-256 checksum files, merged manifest outputs, and a detached `sce-v-release-manifest.json.sig` produced from a non-repo private signing key; the npm distribution surface is now implemented as a checked-in `npm/` launcher package plus root-flake `release-npm-package`, which packs `sce-v-npm.tgz`, refuses mismatched checked-in package metadata, and installs the native CLI by downloading the release manifest plus detached signature, verifying the manifest with the bundled npm public key, and only then checksum-verifying the matching GitHub release archive at npm `postinstall` time. GitHub Releases remain the canonical publication surface for binary release artifacts and approved Flatpak source-manifest package assets, while crates.io and npm registry publication are separate non-bumping publish stages under the approved release topology. GitHub CLI release automation now lives in dedicated `release-sce*.yml` workflows split by Linux, Linux ARM, and macOS ARM, and `.github/workflows/release-sce.yml` now orchestrates those three reusable platform lanes before assembling the signed release manifest, npm tarball, and GitHub release payload. The orchestrator tags/releases the checked-in `.version` directly and rejects version mismatches instead of generating a new semver during workflow execution; `.github/workflows/publish-crates.yml` and `.github/workflows/publish-npm.yml` own registry publication after release assets exist. The Linux root flake now also exposes `nix run .#release-flatpak-package -- --version --out-dir `, delegating to `packaging/flatpak/sce-flatpak.sh release-package` to emit deterministic Flatpak source-manifest tarball/checksum/JSON release assets from checked-in packaging source while running the Nix-built version-parity validator script across `.version`, `cli/Cargo.toml`, `npm/package.json`, and AppStream release metadata; `.github/workflows/release-sce.yml` runs that app into `dist/flatpak` and uploads `*.tar.gz`, `*.sha256`, and `*.json` Flatpak assets to the GitHub Release. Linux root flake also exposes `nix run .#release-flatpak-bundle -- --version --arch --out-dir `, delegating to `sce-flatpak.sh release-bundle` to build a source-built `.flatpak` bundle from the checkout using imperative `flatpak-builder` + `flatpak build-bundle` (network + bubblewrap, kept out of pure Nix), emitting per-architecture `.flatpak`/`.sha256`/`.json` files; `.github/workflows/release-sce-linux.yml` and `.github/workflows/release-sce-linux-arm.yml` build and upload x86_64/aarch64 bundles respectively, assembled by `.github/workflows/release-sce.yml`. The checked-in Flatpak packaging surface lives under `packaging/flatpak/` with Nix-owned generation: `dev.crocoder.sce.yml` is rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`) and regenerated by `nix run .#regenerate-flatpak-manifest`; `cargo-sources.json` is generated from `cli/Cargo.lock` by a Nix derivation wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py` and regenerated by `nix run .#regenerate-cargo-sources`; both are guarded by `flatpak-manifest-parity` and `cargo-sources-parity` flake checks. Static manifest validation is Bash-owned (`nix/flatpak/static-validate.sh`), and release-version parity validation is Bash-owned (`nix/flatpak/version-parity.sh`). AppStream metadata and the host-git wrapper source remain checked in, and `sce-flatpak.sh` is a thin imperative orchestrator (no manifest text rewriting, no embedded Python) around `flatpak-builder` and `flatpak build-bundle`, consumed by the reduced flake app surface and by Flatpak source-manifest release packaging. @@ -54,12 +54,10 @@ The current supported automated release target matrix is `x86_64-unknown-linux-m The downstream publish-stage implementation is now complete for both registries: `.github/workflows/publish-crates.yml` publishes the checked-in crate version after `.version`/tag/Cargo parity checks, and `.github/workflows/publish-npm.yml` publishes the checked-in npm package after `.version`/tag/npm parity checks plus verification of the canonical `sce-v-npm.tgz` GitHub release asset. The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. -Shared Context Plan and Shared Context Code remain separate agent roles by design; planning (`/change-to-plan`) and implementation (`/next-task`) stay split while shared baseline guidance is deduplicated via canonical skill-owned contracts. -Their shared baseline doctrine (core principles, `context/` authority, and quality posture) is defined once as canonical snippets in `config/pkl/base/shared-content-common.pkl` and composed into both agent bodies during generation; the aggregation surfaces `config/pkl/base/shared-content.pkl` (manual) and `config/pkl/base/shared-content-automated.pkl` (automated) import from grouped `plan`, `code`, and `commit` modules for downstream renderers. -The `/next-task` command body is intentionally thin orchestration: readiness gating + phase sequencing are command-owned, while detailed implementation/context-sync contracts are skill-owned (`sce-plan-review`, `sce-task-execution`, `sce-context-sync`). The generated OpenCode command doc now also emits machine-readable frontmatter for this chain via `entry-skill: sce-plan-review` and an ordered `skills` list. -Context sync now uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. -The `/change-to-plan` command body is also intentionally thin orchestration: it delegates clarification and plan-shape contracts to `sce-plan-authoring` (including one-task/one-atomic-commit task slicing) while keeping wrapper-level plan output and handoff obligations explicit. The generated OpenCode command doc now also emits `entry-skill: sce-plan-authoring` plus an ordered `skills` list. -The targeted support commands (`handover`, `commit`, `validate`) keep their thin-wrapper behavior and now also emit machine-readable OpenCode command frontmatter describing their entry skill and ordered skill chain. `/commit` is now split by profile: manual generated commands remain proposal-only and allow split guidance when staged changes mix unrelated goals, while the automated OpenCode `/commit` command generates exactly one commit message and runs `git commit` against the staged diff. The shared `sce-atomic-commit` contract also requires commit bodies to cite affected plan slug(s) and updated task ID(s) when staged changes include `context/plans/*.md`, and to stop for clarification instead of inventing those references when the staged plan diff is ambiguous. +Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes only to `/next-task` and `/validate`. Workflow behavior lives in the canonical commands and seven self-contained skill packages rather than in agent bodies. +The `/change-to-plan` command sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. +Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. +OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. The prior no-git-wrapper Agent Trace design artifacts under `context/sce/agent-trace-*.md` are retained only as historical reference; the current CLI runtime no longer wires the removed Agent Trace schema adaptation, payload building, retry replay, or rewrite handling paths into local hook execution. The hooks service now uses a minimal attribution-only runtime: `commit-msg` is the only hook that mutates behavior, conditionally injecting exactly one canonical SCE trailer when the attribution-hooks gate is enabled, `SCE_DISABLED` is false, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); when the preflight returns `NoOverlap` or `Error` (including DB open failure, schema not ready, query error, staged diff read failure, or zero overlap), the trailer is not appended and errors are logged via `sce.hooks.commit_msg.ai_overlap_error`; `pre-commit` and `post-rewrite` remain deterministic no-op entrypoints; `post-commit` requires validated `--remote-url`, threads that URL through the Agent Trace flow, prints it to stderr, captures current commit patch, queries recent `diff_traces` from past 7 days (dispatching `patch` rows through existing unified-diff parsing and `structured` rows through `structured_patch::derive_claude_structured_patch` at read time), combines/intersects patches, persists intersection metadata to `post_commit_patch_intersections`, and persists the schema-validated built Agent Trace payload, including optional top-level `tool` metadata from recent diff-trace rows, top-level `metadata.sce.version` from the compiled `sce` CLI package version, and range-level `content_hash` values, to AgentTraceDb `agent_traces` (DB-only, no post-commit Agent Trace file artifact); `diff-trace` currently validates/persists required non-empty `sessionID`/`diff`/`tool_name`, optional `model_id` (absent or `null` → `None`, present+non-empty → `Some`, present+empty → error), required nullable/non-empty `tool_version`, plus required `u64` millisecond `time`, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and continues with `None` for missing attribution, with same-tool-idempotent stored `session_id` prefixing (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), non-lossy AgentTraceDb `time_ms` conversion, and no parsed-payload artifact fallback. Claude structured `PostToolUse` diff-trace intake extracts direct model metadata from top-level or nested `model` fields and normalizes it with the `claude/` prefix when present. The CLI now also includes an approved operator-environment doctor contract documented in `context/sce/agent-trace-hook-doctor.md`; the runtime now matches the implemented T06 slice for `sce doctor --fix` parsing/help, stable problem/fix-result reporting, canonical hook-repair reuse, and bounded doctor-owned local-DB directory bootstrap for the missing SCE-owned DB parent path. @@ -71,14 +69,14 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author once in canonical Pkl content organized by concern: `config/pkl/base/shared-content-{common,plan,code,commit}.pkl` for manual profile and `config/pkl/base/shared-content-automated-{common,plan,code,commit}.pkl` for automated profile; aggregation surfaces `config/pkl/base/shared-content.pkl` and `config/pkl/base/shared-content-automated.pkl` import from these grouped modules for downstream renderers. +- Author the three SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi, OpenCode, and Claude consume this model directly. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. -- Generate derived artifacts into `config/.opencode/**` (manual profile), `config/automated/.opencode/**` (automated profile), `config/.claude/**`, and `config/.pi/**` (Pi prompts/skills plus the Pi extension at `config/.pi/extensions/sce/index.ts`, manual profile only) via `config/pkl/generate.pkl`. +- Generate derived artifacts into `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**` (Pi prompts/skills plus the Pi extension at `config/.pi/extensions/sce/index.ts`) via `config/pkl/generate.pkl`. - Treat generated outputs as build artifacts, not primary editing surfaces. ## Ownership boundaries -- Generation-owned paths are authored config artifacts under `config/.opencode/**`, `config/automated/.opencode/**`, `config/.claude/**`, and `config/.pi/**` (agents, commands, skills, shared runtime libraries, OpenCode plugin files, generated OpenCode package manifests, generated OpenCode `opencode.json` manifests including SCE plugin registration, Claude hook/settings assets, Pi prompt/skill assets, and the Pi extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts`). +- Generation-owned paths are authored config artifacts under `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**` (agents, commands, skills, shared runtime libraries, OpenCode plugin files, generated OpenCode `opencode.json`, Claude hook/settings assets, Pi prompt/skill assets, and the Pi extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts`). - Runtime/install artifacts are not generation-owned (for example `node_modules`, lockfiles, install outputs). - Code and behavior changes must be made in canonical sources and renderer metadata, then regenerated. @@ -103,7 +101,7 @@ Lightweight post-task verification baseline (required after each completed task) ## Cross-target parity -- OpenCode, Claude, and Pi are generated from the same canonical content with per-target capability mapping (Pi renders SCE agents as agent-role prompt templates because it has no native sub-agent format). +- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly three rebuilt prompts and seven self-contained skill packages with no agent-role prompts. Manual OpenCode consumes the same workflow packages as exactly three commands, seven self-contained skill packages, and two thin routing agents. Claude consumes exactly three commands and seven self-contained skill packages with no generated agents, while retaining its generated settings and hook helper. - When capabilities differ, parity is implemented by supported target-specific behavior rather than forcing unsupported fields. ## Context navigation @@ -117,7 +115,6 @@ Lightweight post-task verification baseline (required after each completed task) - Use `context/sce/shared-context-plan-workflow.md` for the canonical planning-session workflow (`/change-to-plan`) including clarification gating and `/next-task` handoff contract. - Use `context/sce/plan-code-overlap-map.md` for the current overlap/dedup inventory across Shared Context Plan/Code agents, related commands, and core skills. - Use `context/sce/dedup-ownership-table.md` for canonical owner-vs-consumer boundaries and keep-vs-dedup labels used by the dedup implementation plan. -- Use `context/sce/atomic-commit-workflow.md` for canonical `/commit` behavior, `sce-atomic-commit` naming, the profile-specific proposal contract (manual allows split guidance; automated enforces single-message), and staged-plan commit-body citation rules. - Use `context/sce/agent-trace-implementation-contract.md` only as historical reference for the removed Agent Trace design baseline; it does not describe active runtime behavior. - Use `context/sce/agent-trace-schema-adapter.md` only as historical reference for the removed Agent Trace adapter/builder surface. - Use `context/sce/agent-trace-payload-builder-validation.md` only as historical reference for the removed Agent Trace payload-builder validation slice. @@ -135,4 +132,3 @@ Lightweight post-task verification baseline (required after each completed task) - Use `context/sce/setup-githooks-hook-asset-packaging.md` for the implemented `sce-setup-githooks-any-repo` T02 compile-time hook-template packaging contract and setup-service required-hook embedded accessor surface. - Use `context/sce/setup-githooks-install-flow.md` for the implemented `sce-setup-githooks-any-repo` T03 required-hook install orchestration contract (git-truth hooks-path resolution, per-hook installed/updated/skipped outcomes, and remove-and-replace behavior). - Use `context/sce/setup-githooks-cli-ux.md` for the implemented `sce-setup-githooks-any-repo` T04 setup command-surface contract (`--hooks`, optional `--repo`), compatibility validation rules, and deterministic hook setup messaging. -- Use `context/sce/automated-profile-contract.md` for the automated OpenCode profile deterministic gate policy (10 gate categories, permission mappings, and automated profile constraints for non-interactive SCE workflows). diff --git a/context/patterns.md b/context/patterns.md index b95bb681..82d8713b 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -49,44 +49,45 @@ ## Pkl renderer layering -- Keep target-agnostic canonical content organized by concern in `config/pkl/base/shared-content-{common,plan,code,commit}.pkl` (manual) and `config/pkl/base/shared-content-automated-{common,plan,code,commit}.pkl` (automated); the aggregation surfaces `config/pkl/base/shared-content.pkl` and `config/pkl/base/shared-content-automated.pkl` import from these grouped modules for downstream renderers. +- Keep the three target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`, with package primitives in `workflow-content.pkl` and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. - Keep cross-target generated-config primitives in focused base modules under `config/pkl/base/` and re-export them through `config/pkl/renderers/common.pkl` when multiple renderers need the same contract. -- Keep the grouped shared-content modules synchronized with canonical authored instruction bodies (currently mirrored from the OpenCode source tree under `config/{opencode_root}` for `agent`, `command`, and `skills`, with frontmatter removed) before regenerating targets. -- When two or more generated agent bodies share baseline doctrine, extract that doctrine into reusable canonical constants in `config/pkl/base/shared-content-common.pkl` and compose via interpolation instead of duplicating prose per agent. +- Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. +- Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. +- Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. - Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`. - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. -- Keep per-target metadata tables in dedicated modules (`opencode-metadata.pkl`, `opencode-automated-metadata.pkl`, `claude-metadata.pkl`), including target-specific skill descriptions, and import them into target renderer modules. -- When OpenCode commands need machine-readable orchestration metadata, add it in `config/pkl/renderers/opencode-content.pkl` as frontmatter fields that are explicitly scoped to the targeted commands, and keep non-target commands unchanged unless the contract expands deliberately. -- Add and run `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast metadata completeness guard whenever shared slugs or metadata tables change. -- In renderer modules, produce per-item document objects with explicit `frontmatter`, `body`, and combined `rendered` fields to keep formatting deterministic and easy to map in a later output stage. +- Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi-compatible metadata remains in canonical workflow documents. +- Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. +- Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path; run it whenever workflow documents or target metadata change. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve the workflow body, and append only the required final newline at the output mapping. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. - Validate each renderer module directly with `nix develop -c pkl eval ` before wiring output emission. ## Thin command orchestration - Keep SCE command bodies thin when phase skills already define detailed contracts. -- For `/next-task`, retain only sequencing and confirmation gates in the command body and delegate phase details to `sce-plan-review`, `sce-task-execution`, and `sce-context-sync`. -- For `/change-to-plan`, retain wrapper-level plan output/handoff obligations in the command body and delegate clarification and plan-shape contracts (including one-task/one-atomic-commit task slicing) to `sce-plan-authoring`. -- For `/commit`, keep the command body thin and profile-aware: manual generated commands retain staging-confirmation and proposal-only gates, while the automated OpenCode command skips staging confirmation, generates exactly one staged commit message, and executes one staged `git commit`; delegate commit-message grammar, the single-message contract, and the staged-plan rule (cite affected plan slug(s) and updated task ID(s) when `context/plans/*.md` is staged, otherwise stop for clarification) to `sce-atomic-commit`. -- Preserve mandatory gates (readiness confirmation, implementation stop, final-task validation trigger) while removing duplicated procedural prose from command text. +- For `/change-to-plan`, sequence `sce-context-load` before `sce-plan-authoring`; keep context loading, clarification, plan output, and `/next-task` handoff in their declared owners. +- For `/next-task`, retain one-task sequencing and confirmation gates while delegating phase details to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. +- For `/validate`, run `sce-validation` first and invoke `sce-plan-context-sync` only for a validated result. +- Preserve mandatory gates and authoritative handoffs while removing duplicated phase instructions from agents or sibling skills. ## Multi-file generation entrypoint -- Use `config/pkl/generate.pkl` as the single generation module for authored config outputs. +- Use `config/pkl/generate.pkl` as the single generation module for authored config outputs. Flatten self-contained workflow skill documents as `{skill slug}/{package-relative path}` so nested references are emitted deterministically without sibling-package dependencies. - Use `config/pkl/README.md` as the contributor-facing runbook for prerequisites, ownership boundaries, regeneration steps, and troubleshooting. - Run multi-file generation with `nix develop -c pkl eval -m . config/pkl/generate.pkl` to emit to repository-root mapped paths. -- Run stale-output detection through the flake app entrypoint `nix run .#pkl-check-generated`; it wraps `nix develop -c ./config/pkl/check-generated.sh`, regenerates into a temporary directory, and fails if generated-owned paths differ from committed outputs. -- Keep generated-output parity anchored to `nix run .#pkl-check-generated` and the root `nix flake check` `pkl-parity` derivation; no dedicated generated-parity workflow is currently checked in. +- Run stale-output detection through the flake app entrypoint `nix run .#pkl-check-generated`; it wraps `nix develop -c ./config/pkl/check-generated.sh`, evaluates exact inventory coverage, regenerates into a temporary directory, compares complete generated directories plus scalar outputs, and fails on missing, changed, extra, or explicitly forbidden removed paths. +- Keep generated-output parity anchored to `nix run .#pkl-check-generated` and the root `nix flake check` `pkl-parity` derivation; removed target paths must be treated as forbidden stale outputs rather than generated inventory. - Treat `nix run .#pkl-check-generated` and `nix flake check` as the lightweight post-task verification baseline and run both after each completed task. - For non-destructive verification during development, run `nix develop -c pkl eval -m context/tmp/t04-generated config/pkl/generate.pkl` and inspect emitted paths under `context/tmp/`. -- Keep `output.files` limited to generated-owned paths only (`config/{opencode_root}/{agent,command,skills,lib,plugins}`, generated `config/{opencode_root}/package.json`, `config/{claude_root}/{agents,commands,skills,hooks,settings.json}`, and `config/{pi_root}/{prompts,skills,extensions}`, where roots map to `.opencode`, `.claude`, and `.pi`). +- Keep `output.files` limited to generated-owned paths only (`config/.opencode/{agent,command,skills,lib,plugins,opencode.json}`, `config/.claude/{commands,skills,hooks,settings.json}` with no Claude agents, `config/.pi/{prompts,skills,extensions}`, and the generated schema). Do not emit `config/automated/.opencode`. - For OpenCode pre-execution bash-policy hooks, keep the generated plugin entrypoint thin (`plugins/sce-bash-policy.ts`) and delegate policy evaluation to the Rust `sce policy bash --input normalized --output json` command so OpenCode and Claude share one evaluator. ## Internal subagent parity mapping - Encode internal-agent parity by target capability, not by forcing unsupported frontmatter keys. -- For OpenCode agents that must be internal, set behavior flags in `config/pkl/renderers/opencode-metadata.pkl` (`agentBehaviorBlocks`) and render those directly into frontmatter. -- For Claude agents, represent equivalent intent using supported metadata and body guidance in `config/pkl/renderers/claude-metadata.pkl` (for example description + preamble blocks for delegated command/task routing). +- Keep manual OpenCode Plan and Code agent bodies limited to routing to their approved commands; keep target permissions and presentation metadata in `config/pkl/renderers/opencode-metadata.pkl`. +- Do not generate Claude agents; Claude receives the canonical workflow commands and self-contained skill packages directly, with only supported command/skill metadata added by `config/pkl/renderers/claude-content.pkl`. - Keep parity decisions reproducible by validating generated outputs directly. ## Placeholder CLI scaffolding diff --git a/context/plans/rebuild-pkl-workflow-markdown.md b/context/plans/rebuild-pkl-workflow-markdown.md new file mode 100644 index 00000000..cac67ba7 --- /dev/null +++ b/context/plans/rebuild-pkl-workflow-markdown.md @@ -0,0 +1,202 @@ +# Plan: rebuild-pkl-workflow-markdown + +## Change summary + +Replace the existing Pkl-authored Markdown catalog with a workflow-oriented model that reproduces the project-root `.pi/` commands, skills, and references for the three SCE workflows: `/change-to-plan`, `/next-task`, and `/validate`. Generate those workflows for Pi, OpenCode, and Claude; retain only two thin OpenCode agents that route Plan work to `/change-to-plan` and Code work to `/next-task` or `/validate`. + +Remove the automated OpenCode profile and obsolete generated Markdown commands, skills, and agents. Derive `sce-task-context-sync` and `sce-plan-context-sync` from one canonical Pkl skeleton while emitting self-contained skill packages for every target. Preserve retained non-Markdown generation, including OpenCode plugins/config, Claude settings/hooks, the Pi extension, and the SCE config schema. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: `config/.pi/` contains the same three workflow prompts and seven self-contained skill packages, including reference files, as the project-root `.pi/` baseline; it contains no generated agent-role prompts and retains the Pi extension. + - Validate: `diff -ru .pi/prompts config/.pi/prompts && diff -ru .pi/skills config/.pi/skills && test ! -e config/.pi/prompts/agent-shared-context-plan.md && test ! -e config/.pi/prompts/agent-shared-context-code.md && test -e config/.pi/extensions/sce/index.ts` +- [x] AC2: generated OpenCode Markdown contains exactly the three workflow commands, seven corresponding self-contained skill packages with references, and two thin agents whose only workflow routing is Plan to `/change-to-plan` and Code to `/next-task` plus `/validate`. + - Validate: inspect `config/.opencode/{agent,command,skills}/`; assert three command Markdown files, seven `SKILL.md` files, two agent Markdown files, complete local skill references, and command-to-skill metadata matching the three workflows. +- [x] AC3: generated Claude Markdown contains exactly the three workflow commands and seven corresponding self-contained skill packages with references, without generated Claude agents. + - Validate: inspect `config/.claude/{commands,skills}/`; assert three command Markdown files and seven `SKILL.md` files with complete local references, and run `test ! -e config/.claude/agents`. +- [x] AC4: `sce-task-context-sync` and `sce-plan-context-sync` are instantiated from one canonical Pkl skeleton while retaining distinct handoff gates, lifecycle boundaries, and report formats, with no generated dependency on a sibling skill package. + - Validate: inspect the canonical Pkl sync model for one shared policy/workflow skeleton plus task/plan parameters; inspect every generated sync skill package and resolve all of its referenced files within that package. +- [x] AC5: the automated OpenCode profile and obsolete generated Markdown commands, skills, and agents are absent from generation ownership and committed generated trees. + - Validate: run `test ! -e config/automated/.opencode`; inspect `config/pkl/generate.pkl`, renderer imports, metadata coverage, `config/pkl/check-generated.sh`, and Pkl-related flake inputs for stale automated-profile or obsolete Markdown mappings. +- [x] AC6: retained non-Markdown outputs preserve their existing contracts, and the rebuilt Markdown generator remains deterministic and parity-checked. + - Validate: inspect changes to `config/.opencode/{plugins,lib,opencode.json}`, `config/.claude/{settings.json,hooks}`, `config/.pi/extensions`, and `config/schema/sce-config.schema.json`; run the full validation commands below. + +### Full validation + +- `nix run .#pkl-check-generated` +- `nix flake check` +- `diff -ru .pi/prompts config/.pi/prompts` +- `diff -ru .pi/skills config/.pi/skills` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, and `context/patterns.md` to describe the three-workflow Pkl model, removed automated profile, target inventory, self-contained generated skill references, and thin OpenCode agents. +- Update `context/context-map.md` and focused SCE workflow/ownership documents, including `context/sce/shared-context-plan-workflow.md`, `context/sce/shared-context-code-workflow.md`, and `context/sce/dedup-ownership-table.md`, so skill names and phase ownership match the generated workflows. +- Update `context/glossary.md` only if implementation establishes new canonical terminology. +- Record the removal of the automated profile and workflow-oriented generation boundary in a decision record if the resulting architecture needs rationale beyond current-state context. + +## Constraints and non-goals + +- **In scope:** Pkl sources and renderers that own Markdown content; generated Pi, OpenCode, and Claude commands, skills, skill references, and OpenCode agents; removal of Claude/Pi agents and the automated OpenCode profile; generated-output parity tooling and generation documentation. +- **Out of scope:** Application CLI behavior; changes to plugin, hook, extension, settings, bash-policy, agent-trace, or config-schema behavior; replacement workflows for commit or handover. +- **Constraints:** Treat project-root `.pi/` prompts, skills, and references as the behavioral baseline; preserve target-supported frontmatter and metadata; retain manual OpenCode plugins/config, Claude settings/hooks, the Pi extension, and SCE config-schema generation; emit self-contained sync skill packages despite shared Pkl source; run Pkl and repository checks through Nix. +- **Non-goal:** Preserve compatibility with the removed automated profile, obsolete generated Markdown, Claude agents, or Pi agent-role prompts. + +## Assumptions + +- The project-root `.pi/` tree remains the reference baseline; `config/.pi/` remains the Pkl-generated install tree rather than becoming the canonical authoring source. +- Target-specific frontmatter may differ for OpenCode and Claude, but workflow bodies, phase ordering, result contracts, and local reference content remain behaviorally equivalent to `.pi/`. +- Removing the automated profile removes its complete generated tree; preservation of non-Markdown behavior applies to retained manual OpenCode, Claude, and Pi targets. +- Existing unrelated working-tree files, including `context-rules.md`, `rebuild-pkl-workflow-markdown.md`, and `sync-skeleton.md`, are not generation outputs and must not be overwritten or removed. + +## Task stack + +- [x] T01: `Introduce the workflow document model and shared sync skeleton` (status:complete) + - Task ID: T01 + - Goal: Establish a clean Pkl model for workflow commands, self-contained skill packages, nested reference documents, and parameterized task/plan context-sync generation without changing emitted targets. + - Boundaries (in/out of scope): In — new canonical content types, deterministic nested reference mappings, one shared sync policy/workflow/report skeleton, and task/plan role parameters based on `sync-skeleton.md` and current `.pi` contracts. Out — target renderer rewiring, generated output replacement, and non-sync workflow bodies. + - Dependencies: none + - Done when: The new model evaluates directly; one source owns the shared context-sync skeleton; task and plan instances expose distinct complete `SKILL.md` and `references/sync-report.md` documents; no generated skill requires a cross-skill reference. + - Verification notes (commands or checks): `nix develop -c pkl eval `; inspect both sync instances against `.pi/skills/sce-{task,plan}-context-sync/` and `sync-skeleton.md`. + - Implementation evidence: Added `config/pkl/base/workflow-content.pkl` with workflow command, package, and package-relative document types. Added `config/pkl/base/workflow-context-sync.pkl` with one parameterized task/plan sync policy, workflow, and report skeleton that materializes complete local `SKILL.md` and `references/sync-report.md` documents for both lifecycle roles without changing generated targets. + - Verification evidence: `nix develop -c pkl eval config/pkl/base/workflow-content.pkl` passed. `nix develop -c pkl eval -f json config/pkl/base/workflow-context-sync.pkl` passed; focused `jq` assertions confirmed both role packages, deterministic package-relative document inventories, distinct success gates, all three report statuses, plan-only context requirements, and no sibling-skill references. `git diff --check -- config/pkl/base/workflow-content.pkl config/pkl/base/workflow-context-sync.pkl` passed, and retained generated target trees had no tracked diff. + - Deviations or assumptions: Local Pkl type and module names follow the existing `shared-content` conventions. Exact target rendering and byte-for-byte `.pi` parity remain owned by T03–T05; this task establishes the canonical complete package model and lifecycle contracts without renderer wiring. + +- [x] T02: `Model the change-to-plan workflow package` (status:complete) + - Task ID: T02 + - Goal: Author the `/change-to-plan` command plus `sce-context-load` and `sce-plan-authoring` skill packages and references in the new Pkl workflow model. + - Boundaries (in/out of scope): In — command orchestration, context brief contract, authoring contract, plan template, and plan summary represented by current `.pi` files. Out — next-task, validation, target rendering, and generated output changes. + - Dependencies: T01 + - Done when: The canonical package exposes one change-to-plan command and two self-contained skills whose bodies and references match `.pi` behavior and evaluate deterministically. + - Verification notes (commands or checks): Evaluate the focused Pkl module; compare its command, skill, and reference text with `.pi/prompts/change-to-plan.md` and `.pi/skills/{sce-context-load,sce-plan-authoring}/`. + - Implementation evidence: Added `config/pkl/base/workflow-change-to-plan.pkl`, exposing one `WorkflowPackage` for `/change-to-plan` with deterministic package-relative mappings for the `sce-context-load` and `sce-plan-authoring` skill documents and all four local references. The canonical command, skills, and references mirror the project-root `.pi/` baseline without wiring target renderers or changing generated trees. + - Verification evidence: `nix develop -c pkl eval -f json config/pkl/base/workflow-change-to-plan.pkl` passed. Focused `jq` extraction plus `cmp` matched all seven exposed documents byte-for-byte with `.pi/prompts/change-to-plan.md` and `.pi/skills/{sce-context-load,sce-plan-authoring}/`. Two direct focused evaluations produced identical JSON; `git diff --check -- config/pkl/base/workflow-change-to-plan.pkl` passed; and `git status --short -- config/.pi config/.opencode config/.claude` confirmed no generated target changes. + - Deviations or assumptions: The module follows T01's workflow model and exposes the package as `workflow`; exact baseline text remains canonical Pkl content while target-specific rendering stays deferred to T05–T07. + +- [x] T03: `Model the next-task workflow package` (status:complete) + - Task ID: T03 + - Goal: Author the `/next-task` command plus `sce-plan-review`, `sce-task-execution`, and the task context-sync instance in the new Pkl workflow model. + - Boundaries (in/out of scope): In — readiness, implementation gate, execution result, task-sync handoff, and continuation contracts from `.pi`. Out — final validation, plan context sync, target rendering, and generated output changes. + - Dependencies: T01 + - Done when: The canonical package exposes one next-task command and three self-contained skills with all local references, preserving one-task execution and task-level synchronization sequencing. + - Verification notes (commands or checks): Evaluate the focused Pkl module; compare output with `.pi/prompts/next-task.md` and `.pi/skills/{sce-plan-review,sce-task-execution,sce-task-context-sync}/`. + - Implementation evidence: Added `config/pkl/base/workflow-next-task.pkl`, exposing one `WorkflowPackage` for `/next-task` with deterministic package-relative mappings for `sce-plan-review`, `sce-task-execution`, and the canonical task instance from `workflow-context-sync.pkl`. The package owns all seven skill documents and local references without renderer wiring or generated-tree changes. + - Verification evidence: `nix develop -c pkl eval -f json config/pkl/base/workflow-next-task.pkl` passed twice with identical JSON. Focused `jq` assertions confirmed the command, three-skill inventory, complete package-local document paths, and absence of sibling sync-package references. `jq` extraction plus `cmp` matched the command, plan-review package, and task-execution package byte-for-byte with the project-root `.pi/` baseline; the task context-sync package was compared against `.pi` and retains the shared T01 skeleton's equivalent lifecycle contract. `git diff --check -- config/pkl/base/workflow-next-task.pkl` passed, and `git status --short -- config/.pi config/.opencode config/.claude` confirmed no generated target changes. + - Deviations or assumptions: Reused T01's canonical task context-sync instance rather than duplicating its text in this workflow module. Exact rendered target parity remains deferred to the renderer tasks, as established by T01; this task preserves the canonical shared-skeleton ownership boundary. + +- [x] T04: `Model the validate workflow package` (status:complete) + - Task ID: T04 + - Goal: Author the `/validate` command plus `sce-validation` and the plan context-sync instance in the new Pkl workflow model. + - Boundaries (in/out of scope): In — final validation result/report contracts, validated-only plan-sync gate, plan context requirements, and completion reporting from `.pi`. Out — implementation repair behavior, target rendering, and generated output changes. + - Dependencies: T01 + - Done when: The canonical package exposes one validate command and two self-contained skills with all local references, preserving failed-validation handoff behavior and validated-only plan context synchronization. + - Verification notes (commands or checks): Evaluate the focused Pkl module; compare output with `.pi/prompts/validate.md` and `.pi/skills/{sce-validation,sce-plan-context-sync}/`. + - Implementation evidence: Added `config/pkl/base/workflow-validate.pkl`, exposing one `WorkflowPackage` for `/validate` with deterministic package-relative mappings for `sce-validation` and the canonical plan instance from `workflow-context-sync.pkl`. The package owns all five skill documents and local references without renderer wiring or generated-tree changes. + - Verification evidence: `nix develop -c pkl eval -f json config/pkl/base/workflow-validate.pkl` passed twice with identical JSON. Focused `jq` assertions confirmed the command, two-skill inventory, complete package-local document paths, validated-only plan-sync gate, plan context requirements, and absence of sibling sync-package references. `jq` extraction plus `cmp` matched the command and complete validation package byte-for-byte with the project-root `.pi/` baseline; `git diff --check -- config/pkl/base/workflow-validate.pkl` passed, and `git status --short -- config/.pi config/.opencode config/.claude` confirmed no generated target changes. + - Deviations or assumptions: Reused T01's canonical plan context-sync instance rather than duplicating its text in this workflow module. Exact rendered target parity remains deferred to the renderer tasks, as established by T01; this task preserves failed-validation handoff behavior and the validated-only synchronization boundary. + +- [x] T05: `Render the rebuilt Pi workflows` (status:complete) + - Task ID: T05 + - Goal: Replace Pi's old Markdown rendering with exact generated copies of the three `.pi` workflow prompts and seven self-contained skill packages, while removing Pi agent-role prompts and preserving the extension. + - Boundaries (in/out of scope): In — Pi renderer metadata, nested skill references, Pi output mappings, generated Pi Markdown replacement, and stale Pi agent-prompt deletion. Out — OpenCode/Claude rendering and Pi extension behavior changes. + - Dependencies: T02, T03, T04 + - Done when: `config/.pi/prompts` and `config/.pi/skills` match the root `.pi` baseline, no agent-role prompts remain, and `config/.pi/extensions/sce/index.ts` remains generated without behavioral change. + - Verification notes (commands or checks): Preview generation under `context/tmp/`; `diff -ru .pi/prompts /config/.pi/prompts`; `diff -ru .pi/skills /config/.pi/skills`; inspect the extension diff. + - Implementation evidence: Rewired `config/pkl/renderers/pi-content.pkl` to aggregate the three canonical workflow packages and flatten every package-relative skill document for deterministic self-contained output. Updated `config/pkl/generate.pkl` to emit exact workflow text, including trailing newlines and nested references, without Pi agent-prompt mappings. Refined the canonical task/plan context-sync source into one role-parameterized shared-fragment skeleton that reproduces both distinct baseline packages exactly. Regenerated `config/.pi/{prompts,skills}` with three prompts and seven skill packages, removing obsolete agent, commit, handover, bootstrap, atomic-commit, and legacy context-sync Markdown while preserving the Pi extension. + - Verification evidence: `nix develop -c pkl eval config/pkl/renderers/pi-content.pkl` passed. A clean preview from `nix develop -c pkl eval -m context/tmp/pkl-t05-preview config/pkl/generate.pkl` matched `.pi/prompts` and `.pi/skills` via `diff -ru`; the preview extension matched `config/.pi/extensions/sce/index.ts` via `cmp`. After regeneration, direct `diff -ru .pi/prompts config/.pi/prompts` and `diff -ru .pi/skills config/.pi/skills` passed; inventory checks confirmed exactly three prompts and seven `SKILL.md` files; both stale agent prompts were absent; and `git diff -- config/.pi/extensions/sce/index.ts` was empty. `git diff --check` passed for the changed Pkl sources. + - Deviations or assumptions: Canonical workflow documents include Pi-compatible frontmatter, so the Pi renderer emits them directly rather than reconstructing metadata. Legacy Pi metadata remains temporarily available to the old cross-target coverage check until the legacy model and coverage tooling are removed in T08–T09. No OpenCode, Claude, or Pi extension behavior was changed. + +- [x] T06: `Render the rebuilt OpenCode workflows and thin agents` (status:complete) + - Task ID: T06 + - Goal: Replace manual OpenCode Markdown with the three workflows, seven self-contained skill packages, and two thin routing agents. + - Boundaries (in/out of scope): In — OpenCode command/skill rendering, nested references, command skill-chain metadata, thin Plan/Code agent bodies, generated manual Markdown replacement, and stale manual Markdown deletion. Out — automated-profile removal, Claude rendering, and OpenCode plugin/config behavior changes. + - Dependencies: T02, T03, T04 + - Done when: Manual OpenCode has exactly three workflow commands, seven complete skill packages, and two thin agents with the requested routing; retained plugins, libraries, and `opencode.json` remain behaviorally unchanged. + - Verification notes (commands or checks): Preview generation; inventory `config/.opencode/{agent,command,skills}` in the preview; inspect agent bodies and command metadata; compare retained non-Markdown outputs. + - Implementation evidence: Rewired `config/pkl/renderers/opencode-content.pkl` to aggregate the three canonical workflow packages, add OpenCode command routing and ordered skill-chain metadata, flatten self-contained package documents including nested references, and retain OpenCode-compatible skill metadata. Replaced the two legacy agent bodies with thin routing-only Plan and Code agents, updated their skill permissions to the seven-workflow inventory, regenerated manual OpenCode Markdown, and removed stale commit, handover, bootstrap, atomic-commit, and legacy context-sync outputs without changing retained OpenCode plugins, libraries, or config. + - Verification evidence: `nix develop -c pkl eval config/pkl/renderers/opencode-content.pkl` and `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` passed. A clean preview from `nix develop -c pkl eval -m context/tmp/pkl-t06-preview config/pkl/generate.pkl` contained exactly three commands, seven `SKILL.md` packages, two agents, and all referenced package-local files; focused checks confirmed the command entry skills and ordered chains plus Plan routing to `/change-to-plan` and Code routing to `/next-task` and `/validate`. Direct `diff -ru` matched the regenerated manual Markdown to the preview; `cmp`/`diff -ru` confirmed retained `opencode.json`, plugins, and libraries were unchanged; stale manual Markdown absence checks passed; and changed Pkl sources passed `git diff --check`. + - Deviations or assumptions: Canonical Pi-compatible frontmatter is extended in-place with OpenCode-supported command routing and skill compatibility metadata, leaving workflow bodies unchanged. Generated workflow Markdown retains intentional Markdown hard-break whitespace from the canonical baseline. Automated-profile and legacy source cleanup remains deferred to T08. + +- [x] T07: `Render the rebuilt Claude workflows without agents` (status:complete) + - Task ID: T07 + - Goal: Replace Claude Markdown with the three workflows and seven self-contained skill packages while removing generated Claude agents. + - Boundaries (in/out of scope): In — Claude command/skill rendering, nested references, generated Markdown replacement, and stale Claude agent/Markdown deletion. Out — Claude settings/hook behavior changes, OpenCode/Pi rendering, and automated-profile removal. + - Dependencies: T02, T03, T04 + - Done when: Claude has exactly three commands and seven complete skill packages, `config/.claude/agents` is absent, and generated settings/hooks remain behaviorally unchanged. + - Verification notes (commands or checks): Preview generation; inventory Claude commands and skills; assert the preview has no Claude agents; compare generated settings and hook outputs. + - Implementation evidence: Rewired `config/pkl/renderers/claude-content.pkl` to aggregate the three canonical workflow packages, retain Claude command tool metadata, add Claude skill compatibility metadata, and flatten every package-relative document for self-contained nested references. Removed Claude agent output ownership from `config/pkl/generate.pkl`, regenerated exactly three Claude commands and seven complete skill packages, and deleted stale Claude agents plus obsolete commit, handover, bootstrap, atomic-commit, and legacy context-sync Markdown without changing settings or hooks. + - Verification evidence: `nix develop -c pkl eval config/pkl/renderers/claude-content.pkl` passed. A clean preview from `nix develop -c pkl eval -m context/tmp/pkl-t07-preview config/pkl/generate.pkl` contained exactly three commands, seven `SKILL.md` packages, 18 total skill-package documents, no agents directory, and no unresolved package-local references. Direct `diff -ru` matched regenerated Claude commands and skills to the preview; `cmp` confirmed preview settings and hook outputs matched the retained generated files; `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` passed; and changed Pkl sources passed `git diff --check`. + - Deviations or assumptions: Canonical Pi-compatible frontmatter is extended in-place only with Claude-supported `allowed-tools` and `compatibility` metadata, leaving workflow bodies and local references unchanged. Existing intentional Markdown hard-break whitespace is retained from the canonical baseline. Automated-profile and legacy source/metadata cleanup remains deferred to T08–T09. + +- [x] T08: `Remove the legacy Markdown model and automated profile` (status:complete) + - Task ID: T08 + - Goal: Delete superseded Pkl Markdown modules and all automated OpenCode generation ownership after every retained target consumes the rebuilt workflow model. + - Boundaries (in/out of scope): In — obsolete shared-content modules and metadata, automated renderer/base imports, automated output mappings, committed `config/automated/.opencode`, and stale legacy Markdown mappings. Out — retained manual OpenCode, Claude, Pi non-Markdown behavior and new workflow semantics. + - Dependencies: T05, T06, T07 + - Done when: No active Pkl import or output mapping references the superseded Markdown catalog or automated profile; obsolete generated Markdown and `config/automated/.opencode` are absent; the generator evaluates successfully. + - Verification notes (commands or checks): Evaluate `config/pkl/generate.pkl`; inspect Pkl imports and mappings for stale automated/legacy identifiers; `test ! -e config/automated/.opencode` after regeneration. + - Implementation evidence: Removed automated OpenCode imports and output mappings from `config/pkl/generate.pkl`, deleted the committed `config/automated/.opencode` profile, and deleted the superseded manual/automated `shared-content*.pkl` catalogs plus automated and Pi legacy renderer metadata. Detached shared renderer helpers and metadata coverage from the legacy catalog, trimmed stale command/skill/agent metadata, and made coverage evaluate the rebuilt Pi, OpenCode, and Claude documents directly. + - Verification evidence: `nix develop -c sh -c 'pkl eval config/pkl/generate.pkl >/dev/null && pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null'` passed. A clean `pkl eval -m context/tmp/pkl-t08-preview config/pkl/generate.pkl` preview matched all retained generated OpenCode, Claude, Pi, and schema outputs; it emitted no automated profile. Focused active-Pkl searches found no `shared-content`, `opencode-automated`, automated output path, or obsolete Markdown identifiers; `test ! -e config/automated/.opencode` and `git diff --check -- config/pkl config/automated` passed. + - Deviations or assumptions: T09 retains ownership of removing automated-profile paths and claims from `check-generated.sh`, `flake.nix`, and the Pkl runbook, and of strengthening final metadata/parity coverage. Existing unrelated worktree changes were preserved; retained non-Markdown outputs were not modified. + +- [x] T09: `Align parity tooling and generation documentation` (status:complete) + - Task ID: T09 + - Goal: Make stale-output checks, flake parity inputs, metadata coverage, and the Pkl runbook enforce the rebuilt target matrix and nested reference ownership. + - Boundaries (in/out of scope): In — `config/pkl/check-generated.sh`, Pkl metadata coverage, Pkl-related `flake.nix` source selection, `config/pkl/README.md`, and deterministic checks for removed targets and generated references. Out — workflow behavior changes and durable context synchronization. + - Dependencies: T08 + - Done when: Parity compares every generated workflow package including references; removed outputs are detected rather than ignored; no tooling or documentation claims the automated profile or obsolete Markdown exists; focused generated-output parity passes. + - Verification notes (commands or checks): Direct metadata-coverage Pkl evaluation; `nix run .#pkl-check-generated`; inspect parity source/path lists for complete Pi/OpenCode/Claude workflow and retained non-Markdown coverage. + - Implementation evidence: Strengthened `metadata-coverage-check.pkl` with exact inventories for three commands, seven self-contained skill packages and all 18 package documents, plus the two OpenCode agents, while forcing every rendered document and target metadata lookup to evaluate. Reworked local and flake parity to compare complete OpenCode, Claude, and Pi generated directories plus retained scalar/schema outputs, and to reject the removed automated OpenCode and Claude-agent trees explicitly. Expanded `pklParitySrc` to include every retained generated target tree and rewrote the Pkl runbook around the rebuilt workflow matrix, package-local references, forbidden outputs, and current verification commands. + - Verification evidence: `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` passed. `nix run .#pkl-check-generated` passed after cleanup, and `nix build .#checks.x86_64-linux.pkl-parity --no-link` built successfully. Focused negative checks confirmed the parity script rejects both a temporary `config/.claude/agents` removed-output directory and an extra nested Pi skill reference, then cleanup checks confirmed both temporary paths were absent. `git diff --check -- config/pkl flake.nix` passed, and focused searches found no stale automated-profile, legacy renderer/catalog, or obsolete metadata claims in active Pkl tooling and documentation. + - Deviations or assumptions: Complete-directory comparisons intentionally cover nested references and any future extra stale files without duplicating every path in shell/Nix lists; exact canonical document names remain asserted in Pkl. The removed automated path stays in parity source selection only as a forbidden-output sentinel so reintroduction is detectable. Full repository and acceptance-criteria validation remains owned by `/validate`. + +## Open questions + +None. The user fixed the target matrix, removal of old Markdown, agent ownership, and automated-profile removal before authoring. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-27 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (generated outputs are up to date) +- `nix flake check` -> exit 0 (all applicable x86_64-linux checks passed) +- `diff -ru .pi/prompts config/.pi/prompts` -> exit 0 (Pi workflow prompts match the baseline) +- `diff -ru .pi/skills config/.pi/skills` -> exit 0 (Pi skill packages and references match the baseline) +- `test ! -e config/.pi/prompts/agent-shared-context-plan.md && test ! -e config/.pi/prompts/agent-shared-context-code.md && test -e config/.pi/extensions/sce/index.ts` -> exit 0 (Pi agent prompts are absent and the extension remains) +- `test ! -e config/.claude/agents && test ! -e config/automated/.opencode` -> exit 0 (removed target trees are absent) +- OpenCode, Claude, and Pi `find` inventory assertions -> exit 0 (target counts are 3 workflow commands, 7 skill packages, 18 package documents, and OpenCode alone has 2 agents) +- Generated skill-local reference resolution assertions across Pi, OpenCode, and Claude -> exit 0 (every referenced package-local file exists) +- `nix develop -c sh -c 'pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null'` -> exit 0 (workflow metadata and exact inventory coverage passed) +- Canonical sync-role and package-independence inspection assertions -> exit 0 (`SyncRole` supplies task/plan instances and generated sync packages have no sibling dependency) +- Legacy model and output-mapping inspection assertions -> exit 0 (legacy catalogs and automated generation ownership are absent; remaining automated-path mentions are forbidden-output sentinels) +- `git diff --exit-code -- config/.opencode/plugins config/.opencode/lib config/.opencode/opencode.json config/.claude/settings.json config/.claude/hooks config/.pi/extensions config/schema/sce-config.schema.json` -> exit 0 (retained non-Markdown outputs are unchanged) +- OpenCode command metadata and thin-agent body inspection -> exit 0 (commands route through the expected skill chains; agents route only to the three workflows) +- `git diff --check` -> exit 0 (no whitespace errors) +- `.workflows` provenance and parity inspection -> exit 0 (untracked tree was a same-day duplicate of the Pi baseline with no generation ownership) +- `rm -rf .workflows && test ! -e .workflows` -> exit 0 (temporary duplicate generation tree removed) + +### Scaffolding removed + +- `.workflows/` — untracked same-day duplicate generation tree matching the root Pi workflow baseline and owned by no active generator mapping. + +### Success-criteria verification + +- [x] AC1: Pi generated workflows match the root baseline, agent-role prompts are absent, and the extension remains -> both recursive diffs and focused path assertions passed. +- [x] AC2: OpenCode has exactly three commands, seven self-contained skill packages, and two thin routing agents -> inventory, local-reference, metadata, and agent-body inspections passed. +- [x] AC3: Claude has exactly three commands and seven self-contained skill packages without agents -> inventory, local-reference, and absence assertions passed. +- [x] AC4: both sync packages derive from one canonical role-parameterized Pkl skeleton while remaining self-contained -> source and generated-package inspections passed. +- [x] AC5: automated and legacy Markdown generation surfaces are removed -> path absence, active-source inspection, parity, and metadata coverage passed; remaining path mentions enforce forbidden outputs. +- [x] AC6: retained non-Markdown contracts are unchanged and generation is deterministic -> focused Git diff, generated parity, metadata coverage, and full flake validation passed. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- `nix flake check` validated the applicable x86_64-linux checks; the command reported that incompatible aarch64-darwin, aarch64-linux, and x86_64-darwin systems were omitted. diff --git a/context/sce/atomic-commit-workflow.md b/context/sce/atomic-commit-workflow.md deleted file mode 100644 index 1e9cec78..00000000 --- a/context/sce/atomic-commit-workflow.md +++ /dev/null @@ -1,58 +0,0 @@ -# Atomic Commit Command + Skill (`/commit`) - -## Purpose - -Define the canonical commit workflow used by generated manual and automated command surfaces. - -## Canonical contract - -- Command slug: `commit` -- Command behavior source: `config/pkl/base/shared-content-commit.pkl` (aggregated through `config/pkl/base/shared-content.pkl`) -- Canonical skill slug: `sce-atomic-commit` -- Skill behavior source: `config/pkl/base/shared-content-commit.pkl` (aggregated through `config/pkl/base/shared-content.pkl`) - -Naming decision: -- Canonical skill name is `sce-atomic-commit`. -- `atomic-commits` is treated as legacy wording and is not the canonical generated skill slug. - -## Behavior requirements - -- Empty command arguments are supported; the command infers intent from staged changes. -- Before any proposal, the command must prompt for explicit staging confirmation (`git add ` guidance). -- After staging confirmation, commit guidance must classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`). -- Context-file-focused commit reminders are allowed only for `context/`-only staged diffs; mixed staged diffs must not receive default context-file reminders. -- Command text stays thin and gate-focused; commit grammar and split-aware proposal rules are skill-owned in `sce-atomic-commit`. -- The manual `sce-atomic-commit` skill body now includes bypass-mode awareness (see the skill's `## Bypass mode` section); when invoked in bypass mode, it relaxes proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules. In regular mode, it analyzes staged changes for coherent units and proposes one or more commit messages when staged changes mix unrelated goals; it stays proposal-only and does not create commits automatically. -- Automated `sce-atomic-commit` produces exactly one commit message for the staged diff and does not branch into multi-commit or split guidance. -- When staged changes include `context/plans/*.md`, each proposed commit body must cite the affected plan slug(s) and updated task ID(s) (`T0X`); if the staged plan diff is ambiguous, the workflow must stop for clarification rather than inventing references. -- Output is proposal-only in the manual profile: commit message proposals with optional split guidance, not automatic commits. -- Output is execute-once in the automated OpenCode profile: generate exactly one commit message, then run `git commit` against the staged diff. - -## Oneshot / skip bypass mode - -The manual OpenCode `/commit` command supports an argument-based bypass mode triggered by `/commit oneshot` or `/commit skip` (case-insensitive, first token). This mode is a behavior branch within the existing `commit` command body — it does not add a separate command or alter the automated profile. - -When invoked with `oneshot` or `skip`: - -- **Staging confirmation skipped:** The command does not prompt for or wait on explicit staging confirmation. -- **Context-guidance gate skipped:** No `context/`-only vs mixed diff classification is applied, and no context-file reminders are emitted. -- **Split guidance skipped:** The command does not branch into multi-commit or split guidance, even when staged changes mix unrelated goals. -- **Plan-citation ambiguity stops skipped:** If staged plan file context is ambiguous, the command makes a best-effort inference or omits the plan citation rather than stopping for clarification. -- **Single message + auto-commit:** The command produces exactly one commit message via `sce-atomic-commit`, then immediately executes `git commit` with that message. -- **Empty-stage guard:** If no staged changes exist, the command stops with a clear error and does not attempt a commit. -- **Commit-failure guard:** If `git commit` fails, the command stops and reports the failure without inventing fallback commits. - -The `sce-atomic-commit` skill body now includes a dedicated `## Bypass mode` section that aligns with these command-body overrides, ensuring the skill does not conflict with auto-commit, single-message, or best-effort citation behavior in bypass mode. - -The regular `/commit` path (no arguments, or non-bypass arguments) is unchanged: it retains the staging confirmation prompt, context-guidance gate, optional split guidance, and plan-citation ambiguity stops per the behavior requirements above. - -The bypass mode is scoped to the manual OpenCode profile only. The automated OpenCode `/commit` command already produces a single message and auto-executes `git commit` without these guardrails; the bypass argument is not relevant to it. - -## Generated targets - -- OpenCode command: `config/.opencode/command/commit.md` -- Automated OpenCode command: `config/automated/.opencode/command/commit.md` -- Claude command: `config/.claude/commands/commit.md` -- OpenCode skill: `config/.opencode/skills/sce-atomic-commit/SKILL.md` -- Automated OpenCode skill: `config/automated/.opencode/skills/sce-atomic-commit/SKILL.md` -- Claude skill: `config/.claude/skills/sce-atomic-commit/SKILL.md` diff --git a/context/sce/automated-profile-contract.md b/context/sce/automated-profile-contract.md deleted file mode 100644 index 8f9af0ef..00000000 --- a/context/sce/automated-profile-contract.md +++ /dev/null @@ -1,220 +0,0 @@ -# Automated Profile Contract - -## Purpose - -Defines deterministic behavior for the automated OpenCode profile at `config/automated/.opencode/**`, removing interactive approval/confirmation gates while preserving SCE safety constraints. - -## Scope - -- Applies to automated profile generation targets only -- Manual profile at `config/.opencode/**` remains unchanged with interactive gates -- Policy governs agent frontmatter permissions, command/skill bodies, and workflow behavior - -## Gate Categories and Deterministic Policy - -### P1. Permission Gates (Agent Frontmatter) - -| Permission | Manual | Automated | -|------------|--------|-----------| -| `default` | `ask` | `allow` | -| `read` | `allow` | `allow` | -| `edit` | `allow` | `allow` | -| `glob` | `allow` | `allow` | -| `grep` | `allow` | `allow` | -| `list` | `allow` | `allow` | -| `bash` | `allow` | `allow` | -| `task` | `allow` | `allow` | -| `external_directory` | `ask` | `block` | -| `todowrite` | `allow` | `allow` | -| `todoread` | `allow` | `allow` | -| `question` | `allow` | `allow` | -| `webfetch` | `allow` | `allow` | -| `websearch` | `allow` | `allow` | -| `codesearch` | `allow` | `allow` | -| `lsp` | `allow` | `allow` | -| `doom_loop` | `ask` | `block` | -| `skill["*"]` | `ask` | `allow` | -| `skill["sce-*"]` | `allow` | `allow` | - -**Rationale:** -- `external_directory: block` prevents automated profile from touching paths outside repository -- `doom_loop: block` prevents runaway execution -- `skill["*"]: allow` enables skill loading without per-skill prompts - -### P2. Bootstrap Approval (Missing Context) - -**Manual:** Ask once for approval to bootstrap `context/` if missing -**Automated:** `auto-block` - -**Behavior:** -- If `context/` is missing, stop with error: "Automated profile requires existing context/. Run manual bootstrap first." -- Do not auto-create context structure - -**Rationale:** Bootstrap is a one-time setup action requiring human oversight - -### P3. Clarification Gate (Plan Authoring) - -**Manual:** If critical detail unclear, ask 1-3 targeted questions and stop -**Automated:** `auto-block` - -**Behavior:** -- If any critical detail is unclear (scope, success criteria, constraints, dependencies, domain ambiguity, architecture concerns, task ordering), stop with structured error -- Error must list all unresolved items with category labels -- Do not invent assumptions silently - -**Missing-detail handling:** -- Emit structured blocker report: `BLOCKER: clarification_required` -- Include specific unresolved items -- Require human session to resolve before automated planning can proceed - -**Rationale:** Automated planning must not invent requirements; unclear requests require human clarification - -### P4. Implementation Stop (Task Execution) - -**Manual:** Before writing code, pause and prompt user with scope/approach/risks -**Automated:** `auto-proceed` with logging - -**Behavior:** -- Log implementation intent (task goal, scope, approach) to `context/tmp/automated-session-log.md` -- Proceed without waiting for confirmation -- Preserve all safety constraints (one-task, no scope expansion, no plan reordering) - -**Log format:** -``` -## [timestamp] T0X: {task_title} -- Goal: {goal} -- In scope: {in_scope} -- Out of scope: {out_of_scope} -- Expected files: {file_list} -- Approach: {approach_summary} -- Status: proceeding -``` - -**Rationale:** Implementation stop is a safety review gate; automated profile skips the pause but keeps constraints - -### P5. Readiness Confirmation (Plan Review) - -**Manual:** Ask explicit confirmation that reviewed task is ready for implementation -**Automated:** `auto-pass` when conditions met, `auto-block` otherwise - -**Auto-pass conditions:** -1. Plan path and task ID both provided -2. Review reports no blockers -3. Review reports no ambiguity -4. Review reports no missing acceptance criteria - -**Auto-block conditions:** -- Any blocker, ambiguity, or missing acceptance criteria → stop with structured error -- Missing task ID → use first unchecked task; if multiple plans exist, `auto-block` (see P10) - -**Rationale:** Automated execution requires complete, unambiguous task specifications - -### P6. Multi-Task Approval - -**Manual:** If multi-task execution requested, confirm explicit human approval -**Automated:** `auto-block` - -**Behavior:** -- Multi-task execution is not supported in automated profile -- If requested, stop with error: "Automated profile does not support multi-task execution. Use single-task handoffs." -- Require explicit task-by-task execution - -**Rationale:** One-task-per-session is a core SCE safety constraint; automated profile enforces strictly - -### P7. Scope Expansion - -**Manual:** If out-of-scope edits needed, stop and ask for approval -**Automated:** `auto-block` - -**Behavior:** -- If implementation requires edits outside declared task scope, stop immediately -- Emit structured error: `BLOCKER: scope_expansion_required` -- List specific out-of-scope items detected -- Require human session to approve scope change or split task - -**Rationale:** Scope expansion requires architectural judgment; automated profile does not auto-approve - -### P8. Commit Staging Confirmation - -**Manual:** Prompt user to confirm staging complete before commit proposal -**Automated:** `auto-proceed` with staged-content validation - -**Behavior:** -- Skip staging confirmation prompt -- Validate staged content exists; if empty, emit error: "No staged changes. Stage changes before commit." -- Run `sce-atomic-commit` to produce exactly one commit message for the staged diff -- Preserve the shared staged-plan citation rule: when staged changes include `context/plans/*.md`, the generated commit body must cite the affected plan slug(s) and updated task ID(s); if those references are ambiguous in the staged diff, stop instead of inventing them -- Run `git commit` with that one message against the staged changes -- Do not branch into multi-commit or split guidance - -**Rationale:** Automated profile assumes caller has staged correct changes; validation catches empty staging and the automated `/commit` flow performs the single staged commit directly. - -### P9. Drift Fix Application - -**Manual:** Ask whether to apply fixes or keep report-only -**Automated:** `auto-apply` with constraints - -**Behavior:** -- Auto-apply drift fixes without confirmation -- Constraint: only apply fixes to `context/` files -- If code changes would be required, emit report-only with blocker: "Drift requires code changes. Manual intervention required." -- Log all applied fixes to `context/tmp/automated-drift-fixes.md` - -**Rationale:** Context-only drift fixes are safe; code-requiring drift needs human judgment - -### P10. Plan Selection (Multiple Plans) - -**Manual:** If multiple plans exist and no explicit path provided, ask user to choose -**Automated:** `auto-block` - -**Behavior:** -- If no plan path specified and multiple plans exist, stop with error -- Error must list available plans with paths -- Require explicit plan path in command - -**Plan selection default:** -- Single plan + no path → auto-select the single plan -- Multiple plans + no path → `auto-block` -- Explicit path → use specified plan - -**Rationale:** Automated profile requires deterministic plan resolution; guessing is unsafe - -## Deterministic Defaults Summary - -| Scenario | Manual | Automated | -|----------|--------|-----------| -| Plan selection (single) | Auto-select | Auto-select | -| Plan selection (multiple) | Ask user | Block: require explicit path | -| Missing context/ | Ask to bootstrap | Block: requires manual bootstrap | -| Unclear requirements | Ask clarifying questions | Block: emit structured unresolved items | -| Ready to implement | Ask confirmation | Auto-proceed if conditions met | -| Scope expansion needed | Ask approval | Block: require human session | -| Multi-task requested | Ask approval | Block: not supported | -| Drift fixes (context-only) | Ask to apply | Auto-apply with logging | -| Drift fixes (code required) | Ask to apply | Report-only with blocker | -| Empty staging | Prompt to stage | Block: no staged changes | - -## Automated Profile Constraints - -These constraints apply to automated profile behavior regardless of gate policies: - -1. **One-task execution:** Always enforce single-task-per-session -2. **No plan mutation:** Do not reorder tasks or change plan structure -3. **No code invention:** Do not invent requirements, assumptions, or specifications -4. **Context authority:** Code is source of truth; context sync is required -5. **External isolation:** `external_directory: block` prevents repository escape -6. **Doom loop prevention:** `doom_loop: block` prevents runaway execution -7. **Logging:** All automated decisions logged to `context/tmp/automated-session-log.md` - -## Implementation Notes - -- Permission changes go in automated metadata variant (`opencode-automated-metadata.pkl`) -- Behavior changes go in automated content variants for affected agents/commands/skills -- Generator must emit both manual and automated trees -- Parity checks must validate both profiles - -## Related Context - -- `context/plans/sce-automated-opencode-profile.md` - Implementation plan -- `context/sce/shared-context-plan-workflow.md` - Plan workflow reference -- `context/sce/shared-context-code-workflow.md` - Code workflow reference diff --git a/context/sce/dedup-ownership-table.md b/context/sce/dedup-ownership-table.md index 565990d5..03512f5a 100644 --- a/context/sce/dedup-ownership-table.md +++ b/context/sce/dedup-ownership-table.md @@ -1,26 +1,29 @@ -# SCE Dedup Ownership Table +# SCE Workflow Ownership Table ## Scope and method -- Canonical source of truth: `config/pkl/base/shared-content.pkl`. -- Generated consumers reviewed: `config/.opencode/{agent,command,skills}/**` and `config/.claude/{agents,commands,skills}/**`. -- Context references reviewed: `context/sce/plan-code-overlap-map.md` and `context/decisions/2026-03-03-plan-code-agent-separation.md`. -- Assignment rule: each behavior domain has one canonical owner and one or more reference-only consumers. +- Canonical workflow sources: `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`. +- Shared package model: `config/pkl/base/workflow-content.pkl`. +- Shared synchronization source: `config/pkl/base/workflow-context-sync.pkl`. +- Generated consumers: `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**`. +- Assignment rule: each workflow phase has one canonical skill owner; commands and agents only orchestrate or route. ## Ownership matrix | Behavior domain | Canonical owner | Reference-only consumers | Label | | --- | --- | --- | --- | -| Shared baseline doctrine for both SCE roles (core principles, `context/` authority, quality posture) | Shared snippet constants in `config/pkl/base/shared-content.pkl` (`sharedSceCorePrinciplesSection`, `sharedSceContextAuthoritySection`, `sharedSceQualityPosturePrefixBullets`, `sharedSceLongTermQualityBullet`) | `agents["shared-context-plan"].canonicalBody`, `agents["shared-context-code"].canonicalBody`, generated Plan/Code agent files in OpenCode and Claude | dedup/complete | -| Plan role mission, hard boundaries, startup, and planning procedure | `agents["shared-context-plan"].canonicalBody` in `config/pkl/base/shared-content.pkl` | `config/.opencode/agent/Shared Context Plan.md`, `config/.claude/agents/shared-context-plan.md` | intentional/keep | -| Code role mission, hard boundaries, one-task execution flow, and feedback loop | `agents["shared-context-code"].canonicalBody` in `config/pkl/base/shared-content.pkl` | `config/.opencode/agent/Shared Context Code.md`, `config/.claude/agents/shared-context-code.md` | intentional/keep | -| `/next-task` detailed phase contracts | `skills["sce-plan-review"]`, `skills["sce-task-execution"]`, and `skills["sce-context-sync"]` in `config/pkl/base/shared-content.pkl` | `commands["next-task"].canonicalBody`, `config/.opencode/command/next-task.md`, `config/.claude/commands/next-task.md` | dedup/complete | -| `/change-to-plan` clarification and plan-shape contracts | `skills["sce-plan-authoring"]` in `config/pkl/base/shared-content.pkl` | `commands["change-to-plan"].canonicalBody`, `config/.opencode/command/change-to-plan.md`, `config/.claude/commands/change-to-plan.md` | dedup/complete | -| `/commit` commit grammar and atomic split guidance | `skills["sce-atomic-commit"]` in `config/pkl/base/shared-content.pkl` | `commands["commit"].canonicalBody`, `config/.opencode/command/commit.md`, `config/.claude/commands/commit.md` | dedup/complete | -| Skill phase contracts with command-level invocation overlap | Per-skill canonical bodies in `config/pkl/base/shared-content.pkl` | Related command wrappers (`/next-task`, `/change-to-plan`, `/commit`) and generated command docs | intentional/keep (layered ownership) | +| Context discovery before planning | `sce-context-load` in `workflow-change-to-plan.pkl` | `/change-to-plan`; generated target packages | intentional/keep | +| Plan authoring, clarification, and task slicing | `sce-plan-authoring` in `workflow-change-to-plan.pkl` | `/change-to-plan`; thin OpenCode Plan agent | intentional/keep | +| Task resolution and readiness | `sce-plan-review` in `workflow-next-task.pkl` | `/next-task`; thin OpenCode Code agent | intentional/keep | +| Approval-gated one-task implementation | `sce-task-execution` in `workflow-next-task.pkl` | `/next-task`; thin OpenCode Code agent | intentional/keep | +| Post-task durable context synchronization | Task instance from `workflow-context-sync.pkl` | `/next-task`; generated `sce-task-context-sync` packages | dedup/shared skeleton | +| Final validation and validation report | `sce-validation` in `workflow-validate.pkl` | `/validate`; thin OpenCode Code agent | intentional/keep | +| Validated-plan durable context synchronization | Plan instance from `workflow-context-sync.pkl` | `/validate`; generated `sce-plan-context-sync` packages | dedup/shared skeleton | +| Workflow routing | Three command documents in the workflow modules | Thin OpenCode Plan/Code agents | intentional/keep | -## Guardrails for follow-up tasks +## Guardrails -- Keep Plan/Code role separation unchanged; dedup is shared-baseline extraction plus thin-command delegation, not role merge. -- Keep `/next-task`, `/change-to-plan`, and `/commit` command bodies at orchestration/gating scope. -- Keep detailed acceptance and behavior contracts in skill-owned canonical bodies. +- Keep Plan and Code routing roles separate without placing workflow doctrine in agent bodies. +- Keep commands at sequencing, branching, and handoff scope; phase behavior remains skill-owned. +- Keep task and plan synchronization packages self-contained even though one Pkl skeleton owns their shared policy. +- Do not reintroduce removed `/commit`, `/handover`, legacy context-sync, or automated-profile Markdown ownership. diff --git a/context/sce/generated-opencode-plugin-registration.md b/context/sce/generated-opencode-plugin-registration.md index 88feab50..470445c6 100644 --- a/context/sce/generated-opencode-plugin-registration.md +++ b/context/sce/generated-opencode-plugin-registration.md @@ -16,10 +16,10 @@ The generated-config pipeline now has one canonical Pkl-authored source for Open ## OpenCode generated outputs -- `config/pkl/renderers/opencode-content.pkl` and `config/pkl/renderers/opencode-automated-content.pkl` render `opencodeConfig` artifacts that include the shared plugin registration. -- `config/pkl/generate.pkl` writes those artifacts to `config/.opencode/opencode.json` and `config/automated/.opencode/opencode.json`. -- Both generated OpenCode profiles currently serialize `plugin: ["./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts"]`. -- The generated plugin files currently registered by those manifests are `config/.opencode/plugins/sce-bash-policy.ts`, `config/.opencode/plugins/sce-agent-trace.ts`, `config/automated/.opencode/plugins/sce-bash-policy.ts`, and `config/automated/.opencode/plugins/sce-agent-trace.ts`. +- `config/pkl/renderers/opencode-content.pkl` renders the `opencodeConfig` artifact with the shared plugin registration. +- `config/pkl/generate.pkl` writes that artifact to `config/.opencode/opencode.json`. +- The generated OpenCode profile serializes `plugin: ["./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts"]`. +- The registered generated plugin files are `config/.opencode/plugins/sce-bash-policy.ts` and `config/.opencode/plugins/sce-agent-trace.ts`. The removed `config/automated/.opencode` profile has no plugin manifest or generated plugin copies. ## Claude boundary @@ -32,14 +32,15 @@ The generated-config pipeline now has one canonical Pkl-authored source for Open ## Ownership and edit policy -- Treat `config/.opencode/opencode.json`, `config/automated/.opencode/opencode.json`, and the corresponding generated plugin files under `config/.opencode/plugins/` and `config/automated/.opencode/plugins/` as generated-owned artifacts. +- Treat `config/.opencode/opencode.json` and the corresponding generated plugin files under `config/.opencode/plugins/` as generated-owned artifacts. - When OpenCode plugin registration changes, edit canonical sources under `config/pkl/` (`config/pkl/base/opencode.pkl`, `config/pkl/renderers/common.pkl`, the OpenCode renderer modules, and `config/pkl/generate.pkl` when ownership wiring changes) instead of patching generated manifests directly. - Do not broaden this contract to third-party or user-supplied plugins without an explicit plan/task that defines new ownership and scope rules. ## Verification -- Inspect `config/.opencode/opencode.json` and `config/automated/.opencode/opencode.json` for the generated `plugin` field. -- Inspect `config/.opencode/plugins/sce-bash-policy.ts`, `config/.opencode/plugins/sce-agent-trace.ts`, `config/automated/.opencode/plugins/sce-bash-policy.ts`, and `config/automated/.opencode/plugins/sce-agent-trace.ts` for the generated plugin implementations. +- Inspect `config/.opencode/opencode.json` for the generated `plugin` field. +- Inspect `config/.opencode/plugins/sce-bash-policy.ts` and `config/.opencode/plugins/sce-agent-trace.ts` for the generated plugin implementations. +- Assert `config/automated/.opencode` is absent. - Verify `config/.claude/settings.json` contains the generated `PreToolUse` `Bash` policy hook, verify `config/.claude/hooks/run-sce-or-show-install-guidance.sh` contains the missing-CLI guidance path, and verify `config/.claude/` still contains no Claude bash-policy TypeScript runtime files. See also: [../overview.md](../overview.md), [../architecture.md](../architecture.md), [../glossary.md](../glossary.md) diff --git a/context/sce/plan-code-overlap-map.md b/context/sce/plan-code-overlap-map.md index 101bda68..4e401649 100644 --- a/context/sce/plan-code-overlap-map.md +++ b/context/sce/plan-code-overlap-map.md @@ -1,37 +1,28 @@ -# Shared Context Plan/Code Overlap Map (T01) +# Shared Context Plan/Code Overlap Map ## Scope reviewed -- Canonical source: `config/pkl/base/shared-content.pkl` -- Workflow context: `context/sce/shared-context-code-workflow.md` -- Generated OpenCode artifacts: `.opencode/agent/Shared Context Plan.md`, `.opencode/agent/Shared Context Code.md`, `.opencode/command/change-to-plan.md`, `.opencode/command/next-task.md`, `.opencode/command/commit.md` -- Core skills: `.opencode/skills/sce-plan-review/SKILL.md`, `.opencode/skills/sce-task-execution/SKILL.md`, `.opencode/skills/sce-context-sync/SKILL.md`, `.opencode/skills/sce-atomic-commit/SKILL.md` +- Canonical packages: `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` +- Shared synchronization skeleton: `config/pkl/base/workflow-context-sync.pkl` +- Generated OpenCode routing agents and workflow commands under `config/.opencode/` +- Seven canonical phase skills rendered for OpenCode, Claude, and Pi ## Overlap matrix -| Surface | Shared reusable content | Role-specific content | Overlap type | Dedup target | -| --- | --- | --- | --- | --- | -| Shared Context Plan agent | Core principles, `context/` authority, quality posture | Planning-only boundaries (no app code, no shell), plan-authoring procedure, handoff to `/next-task` | Intentional structural overlap with Code agent | Extract shared baseline block for both agents; keep mission/procedure separate | -| Shared Context Code agent | Core principles, `context/` authority, quality posture | One-task execution boundary, implementation + validation flow, context sync + feedback loop | Intentional structural overlap with Plan agent | Same shared baseline block; keep execution gates role-local | -| `/change-to-plan` command | Clarification gate and plan write contract mirror `sce-plan-authoring` | Plan-session-only handoff behavior | Functional overlap with `sce-plan-authoring` | Define command as thin wrapper; source gate text from skill-owned canonical section | -| `/next-task` command | End-to-end orchestration text mirrors `sce-plan-review`, `sce-task-execution`, and `sce-context-sync` | Auto-pass condition and implementation-stop wording | Functional overlap with three skills | Keep command orchestration short; reference skill contracts instead of repeating long behavior block | -| `/commit` command | Atomic-commit workflow intent overlaps atomic commit skill | Staged-changes confirmation gate and no-auto-commit policy | Duplication + naming mismatch risk | Align command to `sce-atomic-commit` slug and move detailed commit-style contract ownership to skill | -| `sce-plan-review` + `sce-task-execution` + `sce-context-sync` skills | Readiness, stop-before-edit, context-sync rules reused by `/next-task` and Code agent | Each skill owns one phase boundary | Expected layering overlap (command invokes skills) | Keep phase contracts skill-owned; command/agent should summarize, not duplicate | - -## Role-specific vs shared-reusable split - -Role-specific (should remain separate): -- Agent mission and hard boundaries (Plan never edits app code; Code executes one approved task). -- Procedure sequencing tied to the agent role (plan authoring vs implementation execution). - -Shared reusable (dedup candidates): -- Core principles block (`human owns decisions`, `context is durable memory`, `code truth wins`). -- Repeated context authority block (create/update/move/delete rules in `context/`). -- Repeated quality posture language (current-state docs, avoid prose-heavy changelogs). - -## Candidate dedup targets for follow-up tasks - -- Create reusable canonical snippets in `config/pkl/base/shared-content.pkl` for shared principles/authority blocks consumed by both agents. -- Reduce `/next-task` behavior verbosity by delegating to skill contracts while preserving required gates. -- Resolve `/commit` command skill slug mismatch (`atomic-commits` vs `sce-atomic-commit`) and make skill the single owner of detailed atomic-commit message rules. -- Add a new Shared Context Plan workflow doc (`context/sce/shared-context-plan-workflow.md`) to mirror Code workflow structure and reduce role ambiguity. +| Surface | Shared reusable content | Surface-specific content | Ownership rule | +| --- | --- | --- | --- | +| Shared Context Plan agent | References the planning workflow | Routes Plan work to `/change-to-plan` | Keep routing-only; command and skills own behavior | +| Shared Context Code agent | References implementation lifecycle | Routes Code work to `/next-task` and `/validate` | Keep routing-only; command and skills own behavior | +| `/change-to-plan` | Structured handoffs and result branching | Sequences `sce-context-load` then `sce-plan-authoring` | Skills own context loading and plan authoring | +| `/next-task` | Structured handoffs and result branching | Sequences review, one-task execution, task sync, and continuation | `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync` own phases | +| `/validate` | Structured handoffs and result branching | Sequences final validation then validated-only plan sync | `sce-validation` and `sce-plan-context-sync` own phases | +| Task/plan context sync | Root-pass, context hygiene, and synchronization policy | Distinct handoff gates and report lifecycle | One parameterized Pkl skeleton emits two self-contained packages | + +## Current dedup boundary + +- Workflow commands own phase ordering, result branching, and authoritative handoff forwarding. +- Skills own detailed phase policy, gates, edits, verification, and result/report formats. +- Thin OpenCode agents own only role-to-command routing and target permissions. +- Claude and Pi do not receive generated agents. +- Package-local reference files are duplicated in generated targets by design so every skill package remains self-contained. +- The removed grouped shared-content catalog and automated OpenCode profile have no current owner or consumer. diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index 98733464..62d64852 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -1,81 +1,73 @@ -# Shared Context Code Workflow (`/next-task`) +# Shared Context Code Workflows (`/next-task`, `/validate`) -## What this agent is for +## Purpose -The Shared Context Code agent executes exactly one approved plan task from `context/plans/`, validates behavior, and synchronizes `context/` to match current code truth. +The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. -Use this agent when you need to: -- continue implementation from an existing SCE plan -- run a specific plan task (`T0X`) or the next unchecked task -- enforce scoped, approval-gated implementation -- treat context synchronization as a required done gate +## `/next-task` entrypoint -## Command entrypoint +`/next-task {plan-name-or-path} [T0X] [approved]` -Canonical command: +- The plan is required. +- A task ID is optional and must match `T01`, `T02`, and so on. +- The exact token `approved` is optional and may be supplied with or without a task ID. +- Unknown positional tokens are rejected. -`/next-task {plan_name_or_path} {T0X?}` +## `/next-task` phase ownership -Examples: -- `/next-task feature-auth T01` -- `/next-task context/plans/feature-auth.md T03` -- `/next-task feature-auth` +1. `sce-plan-review` + - Resolves exactly one plan and at most one task. + - Selects the requested task or the first incomplete task whose declared dependencies are complete. + - Returns `ready`, `blocked`, or `plan_complete`. +2. `sce-task-execution` + - Receives the complete `ready` result. + - Always presents the implementation gate before editing. + - Waits for confirmation unless the user supplied `approved` to the command. + - Implements and verifies exactly one task, then records status and evidence in the plan. + - Returns `declined`, `blocked`, `incomplete`, or `complete`. +3. `sce-task-context-sync` + - Runs only from the complete successful execution handoff. + - Reconciles one task with durable context and performs the mandatory root-file pass. + - Returns a Markdown report with `synced`, `no_context_change`, or `blocked`. +4. Command continuation + - Emits exactly one next-task command for the first unchecked task in plan order, or a `/validate` command when all implementation tasks are complete. + - Never executes the continuation in the same invocation. -## Workflow behavior +A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. -`/next-task` keeps orchestration/gating responsibilities, while detailed per-phase contracts are owned by the three phase skills. +## `/validate` entrypoint -1. Run `sce-plan-review` to resolve plan target, task selection, and readiness. -2. Apply the plan-review confirmation gate. - - Auto-pass only when both plan and task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria. - - Otherwise, resolve open points and require explicit user confirmation. -3. Run `sce-task-execution`. - - Mandatory implementation stop is enforced by the skill before edits. - - Scoped implementation, light checks/build-if-fast, and plan status updates are skill-owned. -4. Run `sce-context-sync` as a mandatory done gate. - - Context significance classification and root verify-vs-edit behavior are skill-owned. -5. Wait for feedback; if in-scope fixes are needed, apply fixes, rerun light checks/build-if-fast, and sync context again. -6. If this is the final plan task, run `sce-validation`. -7. If more tasks remain, prompt the next-session command for the next task. +`/validate {plan-name-or-path}` -## Mermaid diagram +1. `sce-validation` verifies that implementation tasks are complete, runs the plan's full validation commands and acceptance checks, cleans temporary scaffolding, and writes the Validation Report. +2. Failed or blocked validation ends the session without repair edits; retry uses `/validate {plan-path}`. +3. `sce-plan-context-sync` runs only from a successful `Status: validated` handoff and reconciles the completed plan with durable repository context. + +Final validation never runs from an individual implementation task. + +## Flow ```mermaid flowchart TD - A["/next-task {plan} {task?}"] --> B["sce-plan-review"] - B --> C{"Ready without issues?"} - - C -- "No" --> D["Resolve blockers/ambiguity/missing acceptance criteria"] - D --> E["Ask user: task ready?"] - E --> F{"Confirmed?"} - F -- "No" --> Z["Stop and wait"] - F -- "Yes" --> G["Mandatory implementation stop"] - - C -- "Yes (plan+task and clean review)" --> G - - G --> H["Explain scope, done checks, expected touch scope, approach/trade-offs/risks"] - H --> I["Ask: Continue with implementation now?"] - I --> J{"User says yes?"} - J -- "No" --> Z - J -- "Yes" --> K["sce-task-execution (minimal in-scope changes)"] - - K --> L["Light checks/lints and build if light/fast"] - L --> M["Update plan task status"] - M --> N["sce-context-sync (required)"] - - N --> O{"Feedback needs in-scope fixes?"} - O -- "Yes" --> P["Apply fixes + rerun light checks/build-if-fast"] - P --> N - O -- "No" --> Q{"Final plan task?"} - Q -- "Yes" --> R["sce-validation"] - Q -- "No" --> S["Prompt next session with /next-task ..."] - R --> T["Done"] - S --> T + A["/next-task {plan} {task?} {approved?}"] --> B["sce-plan-review"] + B --> C{"ready?"} + C -- "No" --> D["Report blocked or plan_complete"] + C -- "Yes" --> E["sce-task-execution gate"] + E --> F{"complete?"} + F -- "No" --> G["Report declined, blocked, or incomplete"] + F -- "Yes" --> H["sce-task-context-sync"] + H --> I{"More tasks?"} + I -- "Yes" --> J["Emit next /next-task command"] + I -- "No" --> K["Emit /validate command"] + K --> L["sce-validation"] + L --> M{"validated?"} + M -- "Yes" --> N["sce-plan-context-sync"] + M -- "No" --> O["Stop and retry /validate later"] ``` -## Guardrails +## Canonical sources -- One task per session by default unless user explicitly approves multi-task execution. -- Do not expand scope without explicit approval. -- Code is the source of truth when context and code disagree. -- Context sync is required before the task is considered done. +- `config/pkl/base/workflow-next-task.pkl` +- `config/pkl/base/workflow-validate.pkl` +- `config/pkl/base/workflow-context-sync.pkl` +- Generated baselines: `.pi/prompts/{next-task,validate}.md` diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index c53753ea..d1d6173c 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -1,90 +1,62 @@ # Shared Context Plan Workflow (`/change-to-plan`) -## What this agent is for +## Purpose -The Shared Context Plan agent prepares or updates one implementation plan in `context/plans/`, keeps task sequencing explicit, and hands off a single approved task for execution. - -Use this agent when you need to: -- start a new SCE plan from a scoped change request -- update an existing plan with clarified boundaries or acceptance checks -- stage the next executable task with explicit in/out-of-scope limits -- produce a clean handoff contract for `/next-task` +`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface for this command; workflow behavior belongs to the command and its two phase skills. ## Command entrypoint -Canonical command: - -`/change-to-plan {request_or_plan_target}` - -Examples: -- `/change-to-plan add ci artifact validation` -- `/change-to-plan context/plans/sce-plan-code-convergence-and-sync-policy.md` - -## Workflow behavior - -1. Resolve target plan intent. - - If no plan exists, create one under `context/plans/` with stable task IDs (`T01`, `T02`, ...). - - If a plan exists, load and continue it without reordering completed tasks. -2. Gather and normalize scope. - - Capture goal, constraints, non-goals, and success criteria in current-state language. -3. Break work into atomic tasks. - - Define each task with goal, boundaries, done checks, and verification notes. - - Enforce one-task/one-atomic-commit slicing: each executable task should land as one coherent commit. - - If a task would require multiple independent commits, split it into sequential tasks before approval. -4. Run clarification gate before plan approval. - - If blockers, ambiguity, or missing acceptance criteria exist, stop and ask focused questions. - - Do not mark a task ready for implementation until unresolved points are closed. -5. Publish implementation-ready output contract. - - Identify the recommended next task (`T0X`) and provide exact `/next-task {plan_name} {T0X}` handoff command. -6. Keep plan continuity durable. - - Store continuation state in the plan markdown checkboxes/status only. - - Do not mutate code/runtime files during plan-authoring work. - -## Plan lifecycle policy - -- Plans in `context/plans/` are execution artifacts for active implementation work. -- Completed plans are disposable and are not a durable context source. -- Do not use completed plan files as long-term history references from core context navigation. -- Promote durable outcomes into current-state context files (`context/overview.md`, `context/architecture.md`, `context/glossary.md`, and focused workflow docs) or decision records under `context/decisions/`. - -## Output contract - -- Plan target resolved (`plan_name` and path). -- Task stack with stable IDs and explicit acceptance checks. -- Readiness verdict for the selected task: - - `ready_for_implementation: yes|no` - - if `no`, include issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit decisions/questions required from the human before execution. -- Exact next-session execution command: `/next-task {plan_name} {T0X}`. - -## Mermaid diagram +`/change-to-plan {change request}` -```mermaid -flowchart TD - A["/change-to-plan {request_or_plan_target}"] --> B["Resolve plan target"] - B --> C{"Existing plan?"} +The request must be non-empty. The workflow does not accept approval or execution flags. + +## Phase ownership + +1. `sce-context-load` + - Confirms whether `context/` exists. + - Loads only durable context relevant to the requested focus. + - Reports gaps and context-versus-code drift without editing context. + - Returns `loaded` or `bootstrap_required`. +2. `sce-plan-authoring` + - Runs only from a complete `loaded` handoff. + - Resolves ambiguity and material decisions before writing. + - Creates or updates one plan with stable task IDs, explicit scope, dependencies, done checks, and verification notes. + - Returns `plan_ready`, `needs_clarification`, or `blocked`. + +The command forwards each phase result as the authoritative handoff rather than reconstructing it. - C -- "No" --> D["Create plan skeleton in context/plans/"] - C -- "Yes" --> E["Load existing plan state"] +## Bootstrap boundary - D --> F["Capture goals, constraints, non-goals, success criteria"] - E --> F +When context loading returns `bootstrap_required`, the workflow stops without creating context and tells the user to run: - F --> G["Define/adjust atomic tasks with T0X IDs"] - G --> H["Clarification gate"] - H --> I{"Any blockers/ambiguity/missing acceptance criteria?"} +`sce setup --bootstrap-context` - I -- "Yes" --> J["Ask focused questions and resolve decisions"] - J --> H +The user then reruns `/change-to-plan` with the original request. - I -- "No" --> K["Mark selected task ready_for_implementation: yes"] - K --> L["Provide exact handoff: /next-task {plan_name} {T0X}"] - L --> M["Wait for user to start implementation session"] +## Planning boundary + +- Planning does not implement application or test changes. +- One invocation authors at most one plan. +- Every executable task is sliced as one coherent commit unit by default. +- Durable repository context is read, not synchronized, during planning. +- A ready plan ends with an exact `/next-task {plan-path} {task-id}` handoff; the workflow does not request implementation approval itself. + +## Flow + +```mermaid +flowchart TD + A["/change-to-plan {request}"] --> B["sce-context-load"] + B --> C{"Context available?"} + C -- "No" --> D["Stop: sce setup --bootstrap-context"] + C -- "Yes" --> E["sce-plan-authoring"] + E --> F{"Authoring result"} + F -- "needs_clarification" --> G["Ask only the reported questions"] + F -- "blocked" --> H["Report blocker and required action"] + F -- "plan_ready" --> I["Emit /next-task handoff"] ``` -## Guardrails +## Canonical sources -- Planning and execution stay separate: `/change-to-plan` does not implement code changes. -- One-task execution handoff by default; multi-task execution requires explicit user approval at `/next-task` time. -- Keep plan files current-state oriented and avoid prose-heavy historical narration. -- If context and code diverge during planning, treat code as source of truth and queue context repair tasks. +- `config/pkl/base/workflow-change-to-plan.pkl` +- Generated baseline: `.pi/prompts/change-to-plan.md` +- Skills: `sce-context-load`, `sce-plan-authoring` diff --git a/flake.nix b/flake.nix index 09b46d8d..59512b3a 100644 --- a/flake.nix +++ b/flake.nix @@ -201,17 +201,10 @@ root = workspaceRoot; fileset = pkgs.lib.fileset.unions [ ./config/pkl - (pkgs.lib.fileset.maybeMissing ./config/.opencode/agent) - (pkgs.lib.fileset.maybeMissing ./config/.opencode/command) - (pkgs.lib.fileset.maybeMissing ./config/.opencode/skills) - (pkgs.lib.fileset.maybeMissing ./config/.opencode/lib/drift-collectors.js) - (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode/agent) - (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode/command) - (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode/skills) - (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode/lib/drift-collectors.js) - (pkgs.lib.fileset.maybeMissing ./config/.claude/agents) - (pkgs.lib.fileset.maybeMissing ./config/.claude/commands) - (pkgs.lib.fileset.maybeMissing ./config/.claude/skills) + (pkgs.lib.fileset.maybeMissing ./config/.opencode) + (pkgs.lib.fileset.maybeMissing ./config/.claude) + (pkgs.lib.fileset.maybeMissing ./config/.pi) + (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode) (pkgs.lib.fileset.maybeMissing ./config/schema/sce-config.schema.json) ./config/lib/pi-plugin/sce-pi-extension.ts ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts @@ -1163,32 +1156,60 @@ } trap cleanup EXIT + pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null pkl eval -m "$tmp_dir" config/pkl/generate.pkl >/dev/null paths=( "config/.opencode/agent" "config/.opencode/command" "config/.opencode/skills" - "config/.opencode/lib/drift-collectors.js" - "config/automated/.opencode/agent" - "config/automated/.opencode/command" - "config/automated/.opencode/skills" - "config/automated/.opencode/lib/drift-collectors.js" - "config/.claude/agents" + "config/.opencode/lib" + "config/.opencode/plugins" + "config/.opencode/opencode.json" "config/.claude/commands" "config/.claude/skills" - "config/.claude/lib/drift-collectors.js" + "config/.claude/hooks" + "config/.claude/settings.json" + "config/.pi/prompts" + "config/.pi/skills" + "config/.pi/extensions" "config/schema/sce-config.schema.json" ) + forbidden_paths=( + "config/automated/.opencode" + "config/.claude/agents" + ) + stale=0 for path in "''${paths[@]}"; do - if [ -e "$tmp_dir/$path" ] || [ -e "$path" ]; then - if ! git diff --no-index --exit-code -- "$tmp_dir/$path" "$path" >/dev/null 2>&1; then - stale=1 - printf 'Generated output drift detected at %s\n' "$path" - git diff --no-index -- "$tmp_dir/$path" "$path" || true - fi + if [[ ! -e "$tmp_dir/$path" ]]; then + stale=1 + printf 'Generator did not emit required output at %s\n' "$path" + continue + fi + + if [[ ! -e "$path" ]]; then + stale=1 + printf 'Required generated output is missing at %s\n' "$path" + continue + fi + + if ! git diff --no-index --exit-code -- "$tmp_dir/$path" "$path" >/dev/null 2>&1; then + stale=1 + printf 'Generated output drift detected at %s\n' "$path" + git diff --no-index -- "$tmp_dir/$path" "$path" || true + fi + done + + for path in "''${forbidden_paths[@]}"; do + if [[ -e "$tmp_dir/$path" ]]; then + stale=1 + printf 'Generator emitted removed output at %s\n' "$path" + fi + if [[ -e "$path" ]]; then + stale=1 + printf 'Removed generated output still exists at %s\n' "$path" fi done From 7cdaec503586df12fe4287d0a0acf3fa1221b56c Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 20:52:39 +0200 Subject: [PATCH 05/21] build: Generate Pkl payloads in Cargo OUT_DIR Stop compiling against committed generated trees. Evaluate canonical Pkl into Cargo OUT_DIR for repository builds, provide a deterministic packaging fallback for published and sandboxed builds, and align Nix, crates.io, and Flatpak paths with the ephemeral payload. Plan: generate-cli-assets-in-cargo-out-dir (T01, T02, T03) Co-authored-by: SCE --- .github/workflows/publish-crates.yml | 8 +- .gitignore | 1 + cli/Cargo.toml | 25 +- .../claude/agents/shared-context-code.md | 60 --- .../claude/agents/shared-context-plan.md | 66 --- .../config/claude/commands/change-to-plan.md | 17 - .../config/claude/commands/commit.md | 42 -- .../config/claude/commands/handover.md | 15 - .../config/claude/commands/next-task.md | 24 - .../config/claude/commands/validate.md | 15 - .../hooks/run-sce-or-show-install-guidance.sh | 9 - .../generated/config/claude/settings.json | 55 --- .../claude/skills/sce-atomic-commit/SKILL.md | 104 ---- .../skills/sce-bootstrap-context/SKILL.md | 57 --- .../claude/skills/sce-context-sync/SKILL.md | 93 ---- .../skills/sce-handover-writer/SKILL.md | 48 -- .../claude/skills/sce-plan-authoring/SKILL.md | 89 ---- .../claude/skills/sce-plan-review/SKILL.md | 91 ---- .../claude/skills/sce-task-execution/SKILL.md | 58 --- .../claude/skills/sce-validation/SKILL.md | 47 -- .../opencode/agent/Shared Context Code.md | 84 ---- .../opencode/agent/Shared Context Plan.md | 87 ---- .../config/opencode/command/change-to-plan.md | 20 - .../config/opencode/command/commit.md | 45 -- .../config/opencode/command/handover.md | 18 - .../config/opencode/command/next-task.md | 30 -- .../config/opencode/command/validate.md | 18 - .../opencode/lib/bash-policy-presets.json | 84 ---- .../generated/config/opencode/opencode.json | 6 - .../opencode/plugins/sce-agent-trace.ts | 422 ---------------- .../opencode/plugins/sce-bash-policy.ts | 84 ---- .../skills/sce-atomic-commit/SKILL.md | 104 ---- .../skills/sce-bootstrap-context/SKILL.md | 57 --- .../opencode/skills/sce-context-sync/SKILL.md | 93 ---- .../skills/sce-handover-writer/SKILL.md | 48 -- .../skills/sce-plan-authoring/SKILL.md | 89 ---- .../opencode/skills/sce-plan-review/SKILL.md | 91 ---- .../skills/sce-task-execution/SKILL.md | 58 --- .../opencode/skills/sce-validation/SKILL.md | 47 -- .../config/pi/extensions/sce/index.ts | 455 ------------------ .../pi/prompts/agent-shared-context-code.md | 62 --- .../pi/prompts/agent-shared-context-plan.md | 68 --- .../config/pi/prompts/change-to-plan.md | 17 - .../generated/config/pi/prompts/commit.md | 42 -- .../generated/config/pi/prompts/handover.md | 15 - .../generated/config/pi/prompts/next-task.md | 24 - .../generated/config/pi/prompts/validate.md | 15 - .../pi/skills/sce-atomic-commit/SKILL.md | 102 ---- .../pi/skills/sce-bootstrap-context/SKILL.md | 55 --- .../pi/skills/sce-context-sync/SKILL.md | 91 ---- .../pi/skills/sce-handover-writer/SKILL.md | 46 -- .../pi/skills/sce-plan-authoring/SKILL.md | 87 ---- .../config/pi/skills/sce-plan-review/SKILL.md | 89 ---- .../pi/skills/sce-task-execution/SKILL.md | 56 --- .../config/pi/skills/sce-validation/SKILL.md | 45 -- .../config/schema/agent-trace.schema.json | 149 ------ .../config/schema/sce-config.schema.json | 397 --------------- cli/build.rs | 435 ++++++++++++----- cli/src/generated_migrations.rs | 13 - cli/src/main.rs | 5 +- cli/src/services/agent_trace.rs | 6 +- cli/src/services/config/policy.rs | 6 +- cli/src/services/config/schema.rs | 6 +- cli/src/services/default_paths.rs | 80 --- cli/src/services/setup/mod.rs | 18 + config/.claude/commands/change-to-plan.md | 176 ------- config/.claude/commands/next-task.md | 192 -------- config/.claude/commands/validate.md | 145 ------ .../hooks/run-sce-or-show-install-guidance.sh | 9 - config/.claude/settings.json | 55 --- .../.claude/skills/sce-context-load/SKILL.md | 129 ----- .../references/context-brief.yaml | 153 ------ .../skills/sce-plan-authoring/SKILL.md | 290 ----------- .../references/authoring-contract.yaml | 256 ---------- .../references/plan-summary.md | 94 ---- .../references/plan-template.md | 170 ------- .../skills/sce-plan-context-sync/SKILL.md | 309 ------------ .../references/sync-report.md | 142 ------ .../.claude/skills/sce-plan-review/SKILL.md | 149 ------ .../references/readiness-contract.yaml | 246 ---------- .../skills/sce-task-context-sync/SKILL.md | 311 ------------ .../references/sync-report.md | 133 ----- .../skills/sce-task-execution/SKILL.md | 247 ---------- .../references/execution-contract.yaml | 306 ------------ .../references/implementation-gate.md | 69 --- config/.claude/skills/sce-validation/SKILL.md | 190 -------- .../references/validation-report.md | 84 ---- .../references/validation-result.md | 186 ------- config/.opencode/agent/Shared Context Code.md | 33 -- config/.opencode/agent/Shared Context Plan.md | 30 -- config/.opencode/command/change-to-plan.md | 180 ------- config/.opencode/command/next-task.md | 197 -------- config/.opencode/command/validate.md | 149 ------ config/.opencode/lib/bash-policy-presets.json | 84 ---- config/.opencode/opencode.json | 6 - config/.opencode/plugins/sce-agent-trace.ts | 422 ---------------- config/.opencode/plugins/sce-bash-policy.ts | 84 ---- .../skills/sce-context-load/SKILL.md | 129 ----- .../references/context-brief.yaml | 153 ------ .../skills/sce-plan-authoring/SKILL.md | 290 ----------- .../references/authoring-contract.yaml | 256 ---------- .../references/plan-summary.md | 94 ---- .../references/plan-template.md | 170 ------- .../skills/sce-plan-context-sync/SKILL.md | 309 ------------ .../references/sync-report.md | 142 ------ .../.opencode/skills/sce-plan-review/SKILL.md | 149 ------ .../references/readiness-contract.yaml | 246 ---------- .../skills/sce-task-context-sync/SKILL.md | 311 ------------ .../references/sync-report.md | 133 ----- .../skills/sce-task-execution/SKILL.md | 247 ---------- .../references/execution-contract.yaml | 306 ------------ .../references/implementation-gate.md | 69 --- .../.opencode/skills/sce-validation/SKILL.md | 190 -------- .../references/validation-report.md | 84 ---- .../references/validation-result.md | 186 ------- config/.pi/extensions/sce/index.ts | 455 ------------------ config/.pi/prompts/change-to-plan.md | 175 ------- config/.pi/prompts/next-task.md | 191 -------- config/.pi/prompts/validate.md | 144 ------ config/.pi/skills/sce-context-load/SKILL.md | 128 ----- .../references/context-brief.yaml | 153 ------ config/.pi/skills/sce-plan-authoring/SKILL.md | 289 ----------- .../references/authoring-contract.yaml | 256 ---------- .../references/plan-summary.md | 94 ---- .../references/plan-template.md | 170 ------- .../.pi/skills/sce-plan-context-sync/SKILL.md | 308 ------------ .../references/sync-report.md | 142 ------ config/.pi/skills/sce-plan-review/SKILL.md | 148 ------ .../references/readiness-contract.yaml | 246 ---------- .../.pi/skills/sce-task-context-sync/SKILL.md | 310 ------------ .../references/sync-report.md | 133 ----- config/.pi/skills/sce-task-execution/SKILL.md | 246 ---------- .../references/execution-contract.yaml | 306 ------------ .../references/implementation-gate.md | 69 --- config/.pi/skills/sce-validation/SKILL.md | 189 -------- .../references/validation-report.md | 84 ---- .../references/validation-result.md | 186 ------- config/pkl/README.md | 34 +- config/pkl/check-generated.sh | 112 +++-- config/schema/sce-config.schema.json | 397 --------------- context/architecture.md | 29 +- context/cli/config-precedence-contract.md | 8 +- context/cli/default-path-catalog.md | 7 +- context/context-map.md | 17 +- ...26-07-27-ephemeral-pkl-build-generation.md | 28 ++ context/glossary.md | 23 +- context/overview.md | 30 +- context/patterns.md | 20 +- .../generate-cli-assets-in-cargo-out-dir.md | 84 ++++ .../agent-trace-embedded-schema-validation.md | 2 +- ...h-policy-satisfied-by-wrapper-exemption.md | 2 +- .../sce/cli-cargo-distribution-contract.md | 13 +- .../cli-first-install-channels-contract.md | 2 +- context/sce/flatpak-distribution-patterns.md | 9 +- .../generated-opencode-plugin-registration.md | 12 +- context/sce/pi-extension-runtime.md | 21 +- .../setup-githooks-hook-asset-packaging.md | 2 +- .../sce/setup-repo-local-config-bootstrap.md | 2 +- context/sce/shared-turso-db.md | 2 +- flake.nix | 137 ++---- nix/flatpak/local-manifest-validate.sh | 4 + nix/flatpak/manifest.nix | 8 +- nix/flatpak/static-validate.sh | 7 +- packaging/flatpak/dev.crocoder.sce.yml | 4 +- packaging/flatpak/sce-flatpak.sh | 16 + scripts/prepare-cli-generated-assets.sh | 94 +++- 166 files changed, 787 insertions(+), 18244 deletions(-) delete mode 100644 cli/assets/generated/config/claude/agents/shared-context-code.md delete mode 100644 cli/assets/generated/config/claude/agents/shared-context-plan.md delete mode 100644 cli/assets/generated/config/claude/commands/change-to-plan.md delete mode 100644 cli/assets/generated/config/claude/commands/commit.md delete mode 100644 cli/assets/generated/config/claude/commands/handover.md delete mode 100644 cli/assets/generated/config/claude/commands/next-task.md delete mode 100644 cli/assets/generated/config/claude/commands/validate.md delete mode 100644 cli/assets/generated/config/claude/hooks/run-sce-or-show-install-guidance.sh delete mode 100644 cli/assets/generated/config/claude/settings.json delete mode 100644 cli/assets/generated/config/claude/skills/sce-atomic-commit/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-bootstrap-context/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-context-sync/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-handover-writer/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-plan-authoring/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-plan-review/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-task-execution/SKILL.md delete mode 100644 cli/assets/generated/config/claude/skills/sce-validation/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/agent/Shared Context Code.md delete mode 100644 cli/assets/generated/config/opencode/agent/Shared Context Plan.md delete mode 100644 cli/assets/generated/config/opencode/command/change-to-plan.md delete mode 100644 cli/assets/generated/config/opencode/command/commit.md delete mode 100644 cli/assets/generated/config/opencode/command/handover.md delete mode 100644 cli/assets/generated/config/opencode/command/next-task.md delete mode 100644 cli/assets/generated/config/opencode/command/validate.md delete mode 100644 cli/assets/generated/config/opencode/lib/bash-policy-presets.json delete mode 100644 cli/assets/generated/config/opencode/opencode.json delete mode 100644 cli/assets/generated/config/opencode/plugins/sce-agent-trace.ts delete mode 100644 cli/assets/generated/config/opencode/plugins/sce-bash-policy.ts delete mode 100644 cli/assets/generated/config/opencode/skills/sce-atomic-commit/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-bootstrap-context/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-context-sync/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-handover-writer/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-plan-authoring/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-plan-review/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-task-execution/SKILL.md delete mode 100644 cli/assets/generated/config/opencode/skills/sce-validation/SKILL.md delete mode 100644 cli/assets/generated/config/pi/extensions/sce/index.ts delete mode 100644 cli/assets/generated/config/pi/prompts/agent-shared-context-code.md delete mode 100644 cli/assets/generated/config/pi/prompts/agent-shared-context-plan.md delete mode 100644 cli/assets/generated/config/pi/prompts/change-to-plan.md delete mode 100644 cli/assets/generated/config/pi/prompts/commit.md delete mode 100644 cli/assets/generated/config/pi/prompts/handover.md delete mode 100644 cli/assets/generated/config/pi/prompts/next-task.md delete mode 100644 cli/assets/generated/config/pi/prompts/validate.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-atomic-commit/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-bootstrap-context/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-context-sync/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-handover-writer/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-plan-authoring/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-plan-review/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-task-execution/SKILL.md delete mode 100644 cli/assets/generated/config/pi/skills/sce-validation/SKILL.md delete mode 100644 cli/assets/generated/config/schema/agent-trace.schema.json delete mode 100644 cli/assets/generated/config/schema/sce-config.schema.json delete mode 100644 cli/src/generated_migrations.rs delete mode 100644 config/.claude/commands/change-to-plan.md delete mode 100644 config/.claude/commands/next-task.md delete mode 100644 config/.claude/commands/validate.md delete mode 100644 config/.claude/hooks/run-sce-or-show-install-guidance.sh delete mode 100644 config/.claude/settings.json delete mode 100644 config/.claude/skills/sce-context-load/SKILL.md delete mode 100644 config/.claude/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.claude/skills/sce-plan-authoring/SKILL.md delete mode 100644 config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 config/.claude/skills/sce-plan-authoring/references/plan-summary.md delete mode 100644 config/.claude/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 config/.claude/skills/sce-plan-context-sync/SKILL.md delete mode 100644 config/.claude/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 config/.claude/skills/sce-plan-review/SKILL.md delete mode 100644 config/.claude/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 config/.claude/skills/sce-task-context-sync/SKILL.md delete mode 100644 config/.claude/skills/sce-task-context-sync/references/sync-report.md delete mode 100644 config/.claude/skills/sce-task-execution/SKILL.md delete mode 100644 config/.claude/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 config/.claude/skills/sce-task-execution/references/implementation-gate.md delete mode 100644 config/.claude/skills/sce-validation/SKILL.md delete mode 100644 config/.claude/skills/sce-validation/references/validation-report.md delete mode 100644 config/.claude/skills/sce-validation/references/validation-result.md delete mode 100644 config/.opencode/agent/Shared Context Code.md delete mode 100644 config/.opencode/agent/Shared Context Plan.md delete mode 100644 config/.opencode/command/change-to-plan.md delete mode 100644 config/.opencode/command/next-task.md delete mode 100644 config/.opencode/command/validate.md delete mode 100644 config/.opencode/lib/bash-policy-presets.json delete mode 100644 config/.opencode/opencode.json delete mode 100644 config/.opencode/plugins/sce-agent-trace.ts delete mode 100644 config/.opencode/plugins/sce-bash-policy.ts delete mode 100644 config/.opencode/skills/sce-context-load/SKILL.md delete mode 100644 config/.opencode/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.opencode/skills/sce-plan-authoring/SKILL.md delete mode 100644 config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 config/.opencode/skills/sce-plan-authoring/references/plan-summary.md delete mode 100644 config/.opencode/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 config/.opencode/skills/sce-plan-context-sync/SKILL.md delete mode 100644 config/.opencode/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 config/.opencode/skills/sce-plan-review/SKILL.md delete mode 100644 config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 config/.opencode/skills/sce-task-context-sync/SKILL.md delete mode 100644 config/.opencode/skills/sce-task-context-sync/references/sync-report.md delete mode 100644 config/.opencode/skills/sce-task-execution/SKILL.md delete mode 100644 config/.opencode/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 config/.opencode/skills/sce-task-execution/references/implementation-gate.md delete mode 100644 config/.opencode/skills/sce-validation/SKILL.md delete mode 100644 config/.opencode/skills/sce-validation/references/validation-report.md delete mode 100644 config/.opencode/skills/sce-validation/references/validation-result.md delete mode 100644 config/.pi/extensions/sce/index.ts delete mode 100644 config/.pi/prompts/change-to-plan.md delete mode 100644 config/.pi/prompts/next-task.md delete mode 100644 config/.pi/prompts/validate.md delete mode 100644 config/.pi/skills/sce-context-load/SKILL.md delete mode 100644 config/.pi/skills/sce-context-load/references/context-brief.yaml delete mode 100644 config/.pi/skills/sce-plan-authoring/SKILL.md delete mode 100644 config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 config/.pi/skills/sce-plan-authoring/references/plan-summary.md delete mode 100644 config/.pi/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 config/.pi/skills/sce-plan-context-sync/SKILL.md delete mode 100644 config/.pi/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 config/.pi/skills/sce-plan-review/SKILL.md delete mode 100644 config/.pi/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 config/.pi/skills/sce-task-context-sync/SKILL.md delete mode 100644 config/.pi/skills/sce-task-context-sync/references/sync-report.md delete mode 100644 config/.pi/skills/sce-task-execution/SKILL.md delete mode 100644 config/.pi/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 config/.pi/skills/sce-task-execution/references/implementation-gate.md delete mode 100644 config/.pi/skills/sce-validation/SKILL.md delete mode 100644 config/.pi/skills/sce-validation/references/validation-report.md delete mode 100644 config/.pi/skills/sce-validation/references/validation-result.md delete mode 100644 config/schema/sce-config.schema.json create mode 100644 context/decisions/2026-07-27-ephemeral-pkl-build-generation.md create mode 100644 context/plans/generate-cli-assets-in-cargo-out-dir.md mode change 100644 => 100755 scripts/prepare-cli-generated-assets.sh diff --git a/.github/workflows/publish-crates.yml b/.github/workflows/publish-crates.yml index e187c6db..d8cc0fae 100644 --- a/.github/workflows/publish-crates.yml +++ b/.github/workflows/publish-crates.yml @@ -92,7 +92,7 @@ jobs: printf 'Publishing checked-in crate version %s from tag %s\n' "$version" "$release_tag" fi - - name: Prepare crate-local generated assets + - name: Prepare packaging-only crate fallback env: WORK_ROOT: ${{ runner.temp }}/sce-crates-publish REPO_COPY: ${{ runner.temp }}/sce-crates-publish/repo @@ -101,14 +101,14 @@ jobs: rm -rf "$WORK_ROOT" mkdir -p "$REPO_COPY" rsync -a --exclude '.git/' ./ "$REPO_COPY/" - bash "$REPO_COPY/scripts/prepare-cli-generated-assets.sh" "$REPO_COPY" + nix develop "$REPO_COPY" -c bash "$REPO_COPY/scripts/prepare-cli-generated-assets.sh" "$REPO_COPY" - name: Cargo publish dry run if: env.DRY_RUN == 'true' env: REPO_COPY: ${{ runner.temp }}/sce-crates-publish/repo run: | - nix develop -c cargo publish --manifest-path "$REPO_COPY/cli/Cargo.toml" --locked --dry-run + nix develop "$REPO_COPY" -c cargo publish --manifest-path "$REPO_COPY/cli/Cargo.toml" --locked --dry-run - name: Ensure crates.io token is configured if: env.DRY_RUN != 'true' @@ -125,4 +125,4 @@ jobs: env: REPO_COPY: ${{ runner.temp }}/sce-crates-publish/repo run: | - nix develop -c cargo publish --manifest-path "$REPO_COPY/cli/Cargo.toml" --locked + nix develop "$REPO_COPY" -c cargo publish --manifest-path "$REPO_COPY/cli/Cargo.toml" --locked diff --git a/.gitignore b/.gitignore index 1109ef32..6314d21c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .direnv/ node_modules/ cli/target/ +cli/package-fallback/ integrations/**/target/ result* dist/ diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d3d067c3..f1110d04 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -8,24 +8,23 @@ repository = "https://github.com/crocoder-dev/shared-context-engineering" homepage = "https://sce.crocoder.dev" documentation = "https://sce.crocoder.dev/docs" readme = "README.md" - -[[bin]] -name = "sce" -path = "src/main.rs" - include = [ - "README.md", - "Cargo.toml", - "Cargo.lock", - "build.rs", - "assets/hooks/**", - "assets/generated/**", - "migrations/**", - "src/**", + "/README.md", + "/Cargo.toml", + "/Cargo.lock", + "/build.rs", + "/package-fallback/SHA256SUMS", + "/package-fallback/pkl-generated/**", + "/package-fallback/static/**", + "/src/**", ] keywords = ["cli", "automation", "developer-tools"] categories = ["command-line-utilities", "development-tools"] +[[bin]] +name = "sce" +path = "src/main.rs" + [dependencies] anyhow = "1" chrono = "0.4" diff --git a/cli/assets/generated/config/claude/agents/shared-context-code.md b/cli/assets/generated/config/claude/agents/shared-context-code.md deleted file mode 100644 index b56786a0..00000000 --- a/cli/assets/generated/config/claude/agents/shared-context-code.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: shared-context-code -description: Use when the user wants to execute one approved SCE task and sync context. -model: inherit -color: green -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/cli/assets/generated/config/claude/agents/shared-context-plan.md b/cli/assets/generated/config/claude/agents/shared-context-plan.md deleted file mode 100644 index c81866e7..00000000 --- a/cli/assets/generated/config/claude/agents/shared-context-plan.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: shared-context-plan -description: Use when the user needs to create or update an SCE plan before implementation. -model: inherit -color: blue -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/cli/assets/generated/config/claude/commands/change-to-plan.md b/cli/assets/generated/config/claude/commands/change-to-plan.md deleted file mode 100644 index 310ebb5b..00000000 --- a/cli/assets/generated/config/claude/commands/change-to-plan.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill ---- - -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/claude/commands/commit.md b/cli/assets/generated/config/claude/commands/commit.md deleted file mode 100644 index 1192e4f5..00000000 --- a/cli/assets/generated/config/claude/commands/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/cli/assets/generated/config/claude/commands/handover.md b/cli/assets/generated/config/claude/commands/handover.md deleted file mode 100644 index 0e91be08..00000000 --- a/cli/assets/generated/config/claude/commands/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/cli/assets/generated/config/claude/commands/next-task.md b/cli/assets/generated/config/claude/commands/next-task.md deleted file mode 100644 index b74c996a..00000000 --- a/cli/assets/generated/config/claude/commands/next-task.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. diff --git a/cli/assets/generated/config/claude/commands/validate.md b/cli/assets/generated/config/claude/commands/validate.md deleted file mode 100644 index ece8cebc..00000000 --- a/cli/assets/generated/config/claude/commands/validate.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. diff --git a/cli/assets/generated/config/claude/hooks/run-sce-or-show-install-guidance.sh b/cli/assets/generated/config/claude/hooks/run-sce-or-show-install-guidance.sh deleted file mode 100644 index a01dc897..00000000 --- a/cli/assets/generated/config/claude/hooks/run-sce-or-show-install-guidance.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if ! command -v sce >/dev/null 2>&1; then - echo "sce CLI not found. Install it from https://sce.crocoder.dev/docs/getting-started#install-cli" >&2 - exit 0 -fi - -exec "$@" \ No newline at end of file diff --git a/cli/assets/generated/config/claude/settings.json b/cli/assets/generated/config/claude/settings.json deleted file mode 100644 index 75cda4c6..00000000 --- a/cli/assets/generated/config/claude/settings.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "hooks": { - "PreToolUse": [ - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce policy bash" - } - ] - } - ], - "PostToolUse": [ - { - "matcher": "Write|Edit|MultiEdit|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks diff-trace" - } - ] - }, - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ], - "UserPromptSubmit": [ - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ], - "Stop": [ - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/cli/assets/generated/config/claude/skills/sce-atomic-commit/SKILL.md b/cli/assets/generated/config/claude/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7a3cf4..00000000 --- a/cli/assets/generated/config/claude/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: claude ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/cli/assets/generated/config/claude/skills/sce-bootstrap-context/SKILL.md b/cli/assets/generated/config/claude/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 2981a743..00000000 --- a/cli/assets/generated/config/claude/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: claude ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/cli/assets/generated/config/claude/skills/sce-context-sync/SKILL.md b/cli/assets/generated/config/claude/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 199413fc..00000000 --- a/cli/assets/generated/config/claude/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: claude ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/cli/assets/generated/config/claude/skills/sce-handover-writer/SKILL.md b/cli/assets/generated/config/claude/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 07a14634..00000000 --- a/cli/assets/generated/config/claude/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: claude ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/cli/assets/generated/config/claude/skills/sce-plan-authoring/SKILL.md b/cli/assets/generated/config/claude/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 3f1af5d9..00000000 --- a/cli/assets/generated/config/claude/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. -compatibility: claude ---- - -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/claude/skills/sce-plan-review/SKILL.md b/cli/assets/generated/config/claude/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 69cf6ba0..00000000 --- a/cli/assets/generated/config/claude/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". -compatibility: claude ---- - -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill diff --git a/cli/assets/generated/config/claude/skills/sce-task-execution/SKILL.md b/cli/assets/generated/config/claude/skills/sce-task-execution/SKILL.md deleted file mode 100644 index d90a14fb..00000000 --- a/cli/assets/generated/config/claude/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. -compatibility: claude ---- - -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. diff --git a/cli/assets/generated/config/claude/skills/sce-validation/SKILL.md b/cli/assets/generated/config/claude/skills/sce-validation/SKILL.md deleted file mode 100644 index 22068f7f..00000000 --- a/cli/assets/generated/config/claude/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. -compatibility: claude ---- - -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` diff --git a/cli/assets/generated/config/opencode/agent/Shared Context Code.md b/cli/assets/generated/config/opencode/agent/Shared Context Code.md deleted file mode 100644 index d5edcd48..00000000 --- a/cli/assets/generated/config/opencode/agent/Shared Context Code.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -name: "Shared Context Code" -description: Executes one approved SCE task, validates behavior, and syncs context. -temperature: 0.1 -color: "#059669" -permission: - default: ask - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: ask - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: ask - skill: - "*": ask - "sce-plan-review": allow - "sce-task-execution": allow - "sce-context-sync": allow - "sce-validation": allow - "sce-atomic-commit": allow ---- - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/cli/assets/generated/config/opencode/agent/Shared Context Plan.md b/cli/assets/generated/config/opencode/agent/Shared Context Plan.md deleted file mode 100644 index 4499d961..00000000 --- a/cli/assets/generated/config/opencode/agent/Shared Context Plan.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: "Shared Context Plan" -description: Plans a change into atomic tasks in context/plans without touching application code. -temperature: 0.1 -color: "#2563eb" -permission: - default: ask - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: ask - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: ask - skill: - "*": ask - "sce-bootstrap-context": allow - "sce-plan-authoring": allow ---- - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/cli/assets/generated/config/opencode/command/change-to-plan.md b/cli/assets/generated/config/opencode/command/change-to-plan.md deleted file mode 100644 index 1f2cd988..00000000 --- a/cli/assets/generated/config/opencode/command/change-to-plan.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -agent: "Shared Context Plan" -entry-skill: "sce-plan-authoring" -skills: - - "sce-plan-authoring" ---- - -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/opencode/command/commit.md b/cli/assets/generated/config/opencode/command/commit.md deleted file mode 100644 index 384b7803..00000000 --- a/cli/assets/generated/config/opencode/command/commit.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -agent: "Shared Context Code" -entry-skill: "sce-atomic-commit" -skills: - - "sce-atomic-commit" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/cli/assets/generated/config/opencode/command/handover.md b/cli/assets/generated/config/opencode/command/handover.md deleted file mode 100644 index ce592cda..00000000 --- a/cli/assets/generated/config/opencode/command/handover.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -agent: "Shared Context Code" -entry-skill: "sce-handover-writer" -skills: - - "sce-handover-writer" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/cli/assets/generated/config/opencode/command/next-task.md b/cli/assets/generated/config/opencode/command/next-task.md deleted file mode 100644 index 71a1f974..00000000 --- a/cli/assets/generated/config/opencode/command/next-task.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -agent: "Shared Context Code" -entry-skill: "sce-plan-review" -skills: - - "sce-plan-review" - - "sce-task-execution" - - "sce-context-sync" - - "sce-validation" ---- - -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. diff --git a/cli/assets/generated/config/opencode/command/validate.md b/cli/assets/generated/config/opencode/command/validate.md deleted file mode 100644 index 3c128608..00000000 --- a/cli/assets/generated/config/opencode/command/validate.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" -agent: "Shared Context Code" -entry-skill: "sce-validation" -skills: - - "sce-validation" ---- - -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. diff --git a/cli/assets/generated/config/opencode/lib/bash-policy-presets.json b/cli/assets/generated/config/opencode/lib/bash-policy-presets.json deleted file mode 100644 index 88afd047..00000000 --- a/cli/assets/generated/config/opencode/lib/bash-policy-presets.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "schema_version": 1, - "presets": [ - { - "id": "forbid-git-all", - "match": { - "argv_prefixes": [ - [ - "git" - ] - ] - }, - "message": "This repository blocks `git` via SCE bash-tool policy. Explain to user that they should run `git` commands themselves." - }, - { - "id": "forbid-git-commit", - "match": { - "argv_prefixes": [ - [ - "git", - "add" - ], - [ - "git", - "commit" - ], - [ - "git", - "push" - ] - ] - }, - "message": "This repository blocks direct `git add`, `git commit`, and `git push`. Explain to user that they should run `git` commands themselves." - }, - { - "id": "use-pnpm-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `pnpm` over `npm`. Use `pnpm` instead." - }, - { - "id": "use-bun-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `bun` over `npm`. Use `bun` instead." - }, - { - "id": "use-nix-flake-over-cargo", - "match": { - "argv_prefixes": [ - [ - "cargo" - ] - ] - }, - "message": "This repository prefers Nix flake entrypoints over direct `cargo` commands. Run Cargo through the documented `nix develop` / flake workflows instead." - } - ], - "mutually_exclusive": [ - [ - "use-pnpm-over-npm", - "use-bun-over-npm" - ] - ], - "redundancy_warnings": [ - { - "if_enabled": [ - "forbid-git-all", - "forbid-git-commit" - ], - "warning": "Preset 'forbid-git-commit' is redundant when 'forbid-git-all' is also enabled." - } - ] -} diff --git a/cli/assets/generated/config/opencode/opencode.json b/cli/assets/generated/config/opencode/opencode.json deleted file mode 100644 index dbd5d890..00000000 --- a/cli/assets/generated/config/opencode/opencode.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "plugin": [ - "./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts" - ] -} \ No newline at end of file diff --git a/cli/assets/generated/config/opencode/plugins/sce-agent-trace.ts b/cli/assets/generated/config/opencode/plugins/sce-agent-trace.ts deleted file mode 100644 index 980ceb06..00000000 --- a/cli/assets/generated/config/opencode/plugins/sce-agent-trace.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { spawn } from "node:child_process"; -import type { Hooks, Plugin } from "@opencode-ai/plugin"; - -type OpenCodeEvent = Parameters>[0]["event"]; - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -const REQUIRED_EVENTS: Set = new Set([ - "message.updated", - "message.part.updated", - "session.created", - "session.updated", -]); - -const ALL_CAPTURED_EVENTS = REQUIRED_EVENTS; - -type TraceInput = { - event?: OpenCodeEvent; -}; - -type DiffTracePayload = { - sessionID: string; - diff: string; - time: number; - model_id: string; -}; - -type ConversationTraceMessageUpdatedItem = { - type: "message"; - session_id: string; - message_id: string; - role: EventMessageUpdated["properties"]["info"]["role"]; - generated_at_unix_ms: number; -}; - -type ConversationTraceMessagePartUpdatedItem = { - type: "message.part"; - session_id: string; - message_id: string; - part_type: "text" | "reasoning" | "patch" | "question"; - text: unknown; - generated_at_unix_ms: number; -}; - -type ConversationTraceItem = - | ConversationTraceMessageUpdatedItem - | ConversationTraceMessagePartUpdatedItem; - -type ConversationTracePayload = { - payloads: ConversationTraceItem[]; -}; - -type QuestionToolAnswer = { - question: string; - answer: string; -}; - -const QUESTION_TOOL_ANSWER_SEPARATOR = ", "; - -type EventMessageUpdated = Extract< - NonNullable, - { type: "message.updated" } ->; - -type EventMessagePartUpdated = Extract< - NonNullable, - { type: "message.part.updated" } ->; - -type EventMessagePart = EventMessagePartUpdated["properties"]["part"]; -type EventMessageToolPart = Extract; -type EventAllowedPart = - | Extract - | Extract; - -function extractDiffEntries( - eventInfo: EventMessageUpdated["properties"]["info"], -) { - if (typeof eventInfo.summary === "object") { - return eventInfo.summary.diffs; - } - return undefined; -} - -function extractDiffTracePayload( - event: EventMessageUpdated, -): DiffTracePayload | undefined { - const eventInfo = event.properties.info; - // Only capture user messages (filter out assistant, system, etc.) - if (eventInfo.role !== "user") { - return undefined; - } - - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patches: string[] = []; - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - patches.push(entry.patch); - } - } - - if (patches.length === 0) { - return undefined; - } - - return { - sessionID: eventInfo.sessionID, - diff: patches.join("\n"), - time: Date.now(), - model_id: `${eventInfo.model.providerID}/${eventInfo.model.modelID}`, - }; -} - -function shouldCaptureEvent(eventType: OpenCodeEvent["type"]): boolean { - return ALL_CAPTURED_EVENTS.has(eventType); -} - -function extractQuestionToolAnswers( - eventPart: EventMessageToolPart, -): QuestionToolAnswer[] | undefined { - const state = eventPart.state; - - if (state.status !== "completed") { - return undefined; - } - - const questions = - "questions" in state.input && Array.isArray(state.input.questions) - ? state.input.questions - : []; - const answers = - "answers" in state.metadata && Array.isArray(state.metadata.answers) - ? state.metadata.answers - : []; - - if (questions.length === 0 || questions.length !== answers.length) { - return undefined; - } - - const result: QuestionToolAnswer[] = []; - - questions.forEach((q, index) => { - const question = - "question" in q && typeof q.question === "string" ? q.question : ""; - if (question) { - const answer = Array.isArray(answers[index]) ? answers[index] : []; - result.push({ - question, - answer: answer.join(QUESTION_TOOL_ANSWER_SEPARATOR), - }); - } - }); - - return result; -} - -function buildConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload { - const eventInfo = event.properties.info; - - return { - payloads: [ - { - type: "message", - session_id: eventInfo.sessionID, - message_id: eventInfo.id, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -export function buildMessagePartConversationTracePayload( - eventPart: EventAllowedPart, -): ConversationTracePayload { - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: eventPart.type, - text: "text" in eventPart ? eventPart.text : "", - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildQuestionToolConversationTracePayload( - eventPart: EventMessageToolPart, -): ConversationTracePayload | undefined { - const pairedAnswers = extractQuestionToolAnswers(eventPart); - - if (pairedAnswers === undefined) { - return undefined; - } - - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: "question", - text: JSON.stringify(pairedAnswers), - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildPatchConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload | undefined { - const eventInfo = event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patchMessageId = `${eventInfo.id}-patch`; - const payloads: ConversationTraceItem[] = []; - - payloads.push({ - type: "message", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }); - - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - payloads.push({ - type: "message.part", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - part_type: "patch", - text: entry.patch, - generated_at_unix_ms: Date.now(), - }); - } - } - - return { payloads }; -} - -export async function recordConversationTrace( - repoRoot: string, - event: EventMessageUpdated | EventMessagePartUpdated, -): Promise { - if ( - event.type === "message.part.updated" && - event.properties.part.type === "tool" && - event.properties.part.tool === "question" - ) { - const questionToolPayload = buildQuestionToolConversationTracePayload( - event.properties.part, - ); - if (questionToolPayload !== undefined) { - await runConversationTraceHook(repoRoot, questionToolPayload); - return; - } - } - - if ( - event.type === "message.part.updated" && - (event.properties.part.type === "reasoning" || - event.properties.part.type === "text") && - event.properties.part.text - ) { - await runConversationTraceHook( - repoRoot, - buildMessagePartConversationTracePayload(event.properties.part), - ); - return; - } - - if (event.type === "message.updated") { - const patchPayload = buildPatchConversationTracePayload(event); - - if (patchPayload !== undefined) { - await runConversationTraceHook(repoRoot, patchPayload); - return; - } - - await runConversationTraceHook( - repoRoot, - buildConversationTracePayload(event), - ); - } -} - -async function buildTrace( - repoRoot: string, - event: EventMessageUpdated, - clientVersion: string | null, -): Promise { - const diffTracePayload = extractDiffTracePayload(event); - - if (diffTracePayload === undefined) { - return; - } - - await runDiffTraceHook(repoRoot, { - ...diffTracePayload, - tool_name: "opencode", - tool_version: clientVersion, - }); -} - -async function runDiffTraceHook( - repoRoot: string, - payload: DiffTracePayload & { - tool_name: string; - tool_version: string | null; - }, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "diff-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -async function runConversationTraceHook( - repoRoot: string, - payload: ConversationTracePayload, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "conversation-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -export const SceAgentTracePlugin: Plugin = async ({ directory, worktree }) => { - const repoRoot = worktree ?? directory ?? process.cwd(); - const clientVersionsBySessionId: Map = new Map(); - const processedDiffsMessageIds: Set = new Set(); - - return { - event: async (input) => { - if (!shouldCaptureEvent(input.event.type)) { - return; - } - - if ( - input.event.type === "session.created" || - input.event.type === "session.updated" - ) { - clientVersionsBySessionId.set( - input.event.properties.info.id, - input.event.properties.info.version, - ); - } - - if (input.event.type === "message.updated") { - const eventInfo = input.event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - const hasDiffs = diffEntries !== undefined && diffEntries.length > 0; - - if (hasDiffs) { - const dedupKey = `${eventInfo.sessionID}:${eventInfo.id}`; - if (processedDiffsMessageIds.has(dedupKey)) { - return; - } - processedDiffsMessageIds.add(dedupKey); - } - - const clientVersion = - clientVersionsBySessionId.get( - input.event.properties.info.sessionID, - ) || null; - await recordConversationTrace(repoRoot, input.event); - await buildTrace(repoRoot, input.event, clientVersion); - } - - if (input.event.type === "message.part.updated") { - await recordConversationTrace(repoRoot, input.event); - } - }, - }; -}; diff --git a/cli/assets/generated/config/opencode/plugins/sce-bash-policy.ts b/cli/assets/generated/config/opencode/plugins/sce-bash-policy.ts deleted file mode 100644 index 0b2b8d9c..00000000 --- a/cli/assets/generated/config/opencode/plugins/sce-bash-policy.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { spawnSync } from "node:child_process"; -import type { Plugin } from "@opencode-ai/plugin"; - -interface JsonPolicyResult { - status: string; - decision: string; - command: string; - normalized_argv?: string[]; - reason?: string; - policy_id?: string; -} - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -/** - * Evaluate a bash command against SCE bash-tool policy by delegating to the - * Rust `sce policy bash` command. Returns the parsed JSON result, or null if - * the policy check could not be performed (fail-open). - */ -function evaluateBashCommandPolicy(command: string): JsonPolicyResult | null { - try { - const result = spawnSync( - "sce", - ["policy", "bash", "--input", "normalized", "--output", "json"], - { - input: JSON.stringify({ command }), - encoding: "utf8", - timeout: 10_000, - }, - ); - - if (result.error) { - if ((result.error as NodeJS.ErrnoException).code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - return null; - } - - if (result.status !== 0) { - return null; - } - - const stdout = result.stdout?.trim(); - if (!stdout) { - return null; - } - - const parsed: JsonPolicyResult = JSON.parse(stdout); - return parsed; - } catch { - return null; - } -} - -export const SceBashPolicyPlugin: Plugin = async () => { - return { - "tool.execute.before": async (input, output) => { - if (input.tool !== "bash") { - return; - } - - const args = output?.args; - if (args === undefined || args === null) { - return; - } - - const command = (args as { command?: unknown }).command; - if (typeof command !== "string" || command.length === 0) { - return; - } - - const policyResult = evaluateBashCommandPolicy(command); - if (!policyResult) { - // Fail open: if the policy check cannot be performed, allow the command. - return; - } - - if (policyResult.decision === "deny" && policyResult.reason) { - throw new Error(policyResult.reason); - } - }, - }; -}; diff --git a/cli/assets/generated/config/opencode/skills/sce-atomic-commit/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 50c63fe8..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: opencode ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/cli/assets/generated/config/opencode/skills/sce-bootstrap-context/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index c0193c49..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: opencode ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/cli/assets/generated/config/opencode/skills/sce-context-sync/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 16e27bf7..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: opencode ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/cli/assets/generated/config/opencode/skills/sce-handover-writer/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 43bb1238..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: opencode ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/cli/assets/generated/config/opencode/skills/sce-plan-authoring/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 3632b0b8..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. -compatibility: opencode ---- - -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/opencode/skills/sce-plan-review/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-plan-review/SKILL.md deleted file mode 100644 index da87e50e..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". -compatibility: opencode ---- - -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill diff --git a/cli/assets/generated/config/opencode/skills/sce-task-execution/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 2e13a754..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. -compatibility: opencode ---- - -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. diff --git a/cli/assets/generated/config/opencode/skills/sce-validation/SKILL.md b/cli/assets/generated/config/opencode/skills/sce-validation/SKILL.md deleted file mode 100644 index 9391ee6d..00000000 --- a/cli/assets/generated/config/opencode/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. -compatibility: opencode ---- - -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` diff --git a/cli/assets/generated/config/pi/extensions/sce/index.ts b/cli/assets/generated/config/pi/extensions/sce/index.ts deleted file mode 100644 index 25770ff8..00000000 --- a/cli/assets/generated/config/pi/extensions/sce/index.ts +++ /dev/null @@ -1,455 +0,0 @@ -import { spawn, spawnSync } from "node:child_process"; -import { randomUUID } from "node:crypto"; -import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; -import { createRequire } from "node:module"; -import { tmpdir } from "node:os"; -import { - dirname, - isAbsolute, - join, - relative, - resolve as resolvePath, -} from "node:path"; -import { - type ExtensionAPI, - isToolCallEventType, -} from "@earendil-works/pi-coding-agent"; - -interface JsonPolicyResult { - status: string; - decision: string; - command: string; - normalized_argv?: string[]; - reason?: string; - policy_id?: string; -} - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -type ConversationTraceMessageItem = { - type: "message"; - session_id: string; - message_id: string; - role: "user" | "assistant"; - generated_at_unix_ms: number; -}; - -type ConversationTraceMessagePartItem = { - type: "message.part"; - session_id: string; - message_id: string; - part_type: "text" | "reasoning" | "patch"; - text: string; - generated_at_unix_ms: number; -}; - -type ConversationTraceItem = - | ConversationTraceMessageItem - | ConversationTraceMessagePartItem; - -type ConversationTracePayload = { - payloads: ConversationTraceItem[]; -}; - -type DiffTracePayload = { - sessionID: string; - diff: string; - time: number; - model_id: string | null; - tool_name: "pi"; - tool_version: string | null; -}; - -type PendingFileMutation = { - absolutePath: string; - diffLabel: string; - before: string | undefined; -}; - -/** - * Evaluate a bash command against SCE bash-tool policy by delegating to the - * Rust `sce policy bash` command. Returns the parsed JSON result, or null if - * the policy check could not be performed (fail-open). - */ -function evaluateBashCommandPolicy(command: string): JsonPolicyResult | null { - try { - const result = spawnSync( - "sce", - ["policy", "bash", "--input", "normalized", "--output", "json"], - { - input: JSON.stringify({ command }), - encoding: "utf8", - timeout: 10_000, - }, - ); - - if (result.error) { - if ((result.error as NodeJS.ErrnoException).code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - return null; - } - - if (result.status !== 0) { - return null; - } - - const stdout = result.stdout?.trim(); - if (!stdout) { - return null; - } - - const parsed: JsonPolicyResult = JSON.parse(stdout); - return parsed; - } catch { - return null; - } -} - -/** - * Send a conversation-trace payload to `sce hooks conversation-trace`, - * fire-and-forget. Fail-open: stderr is ignored so that sce intake errors do - * not leak into the Pi TUI, and the returned promise never rejects. - */ -function runConversationTraceHook( - cwd: string, - payload: ConversationTracePayload, -): Promise { - return new Promise((resolve) => { - const child = spawn("sce", ["hooks", "conversation-trace"], { - cwd, - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -type MessageContentBlock = { - type: string; - text?: unknown; - thinking?: unknown; -}; - -function extractMessageParts( - content: string | readonly MessageContentBlock[], -): Array<{ part_type: "text" | "reasoning"; text: string }> { - if (typeof content === "string") { - return content.length > 0 ? [{ part_type: "text", text: content }] : []; - } - - const parts: Array<{ part_type: "text" | "reasoning"; text: string }> = []; - for (const block of content) { - if (block.type === "text" && typeof block.text === "string" && block.text) { - parts.push({ part_type: "text", text: block.text }); - } else if ( - block.type === "thinking" && - typeof block.thinking === "string" && - block.thinking - ) { - parts.push({ part_type: "reasoning", text: block.thinking }); - } - } - return parts; -} - -function buildMessageEndConversationTracePayload( - sessionId: string, - message: { - role: string; - content: string | readonly MessageContentBlock[]; - responseId?: string; - }, -): ConversationTracePayload | undefined { - if (message.role !== "user" && message.role !== "assistant") { - return undefined; - } - - const messageId = message.responseId ?? randomUUID(); - const generatedAtUnixMs = Date.now(); - - const payloads: ConversationTraceItem[] = [ - { - type: "message", - session_id: sessionId, - message_id: messageId, - role: message.role, - generated_at_unix_ms: generatedAtUnixMs, - }, - ]; - - for (const part of extractMessageParts(message.content)) { - payloads.push({ - type: "message.part", - session_id: sessionId, - message_id: messageId, - part_type: part.part_type, - text: part.text, - generated_at_unix_ms: generatedAtUnixMs, - }); - } - - return { payloads }; -} - -/** - * Resolve the installed Pi package version for diff-trace `tool_version`. - * The package's `exports` map does not expose `package.json`, so resolve the - * package entry point and read `package.json` from the package root instead. - * Returns null when resolution fails (normalized diff traces permit it). - */ -async function resolvePiToolVersion(): Promise { - try { - const require_ = createRequire(import.meta.url); - const entryPath = require_.resolve("@earendil-works/pi-coding-agent"); - const packageJsonPath = join(dirname(entryPath), "..", "package.json"); - const parsed: { version?: unknown } = JSON.parse( - await readFile(packageJsonPath, "utf8"), - ); - return typeof parsed.version === "string" && parsed.version.length > 0 - ? parsed.version - : null; - } catch { - return null; - } -} - -/** - * Send a diff-trace payload to `sce hooks diff-trace`, fire-and-forget. - * Fail-open: stderr is ignored and the returned promise never rejects. - */ -function runDiffTraceHook( - cwd: string, - payload: DiffTracePayload, -): Promise { - return new Promise((resolve) => { - const child = spawn("sce", ["hooks", "diff-trace"], { - cwd, - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -async function readFileOrUndefined(path: string): Promise { - try { - return await readFile(path, "utf8"); - } catch { - return undefined; - } -} - -function diffLabelFor(cwd: string, absolutePath: string): string { - const relPath = relative(cwd, absolutePath); - return relPath.length > 0 && !relPath.startsWith("..") && !isAbsolute(relPath) - ? relPath - : absolutePath; -} - -/** - * Rewrite temp-file path labels in git diff header lines to the repo-relative - * target path. Only header lines before the first `@@` hunk marker are - * touched so that content lines starting with `--- ` / `+++ ` are preserved. - */ -function rewriteDiffLabels( - diff: string, - label: string, - isCreate: boolean, -): string { - const lines = diff.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.startsWith("@@")) { - break; - } - if (line.startsWith("diff --git ")) { - lines[i] = `diff --git a/${label} b/${label}`; - } else if (line.startsWith("--- ")) { - lines[i] = isCreate ? "--- /dev/null" : `--- a/${label}`; - } else if (line.startsWith("+++ ")) { - lines[i] = `+++ b/${label}`; - } - } - return lines.join("\n"); -} - -/** - * Produce a unified diff between before/after contents by writing them to - * temp files and spawning `git diff --no-index --no-ext-diff` (exit status 1 - * means "files differ"). Returns undefined for no-op diffs or any failure; - * temp files are always cleaned up. - */ -async function buildUnifiedDiff( - label: string, - before: string | undefined, - after: string, -): Promise { - const tempDir = await mkdtemp(join(tmpdir(), "sce-pi-diff-")); - try { - const beforePath = join(tempDir, "before"); - const afterPath = join(tempDir, "after"); - await writeFile(beforePath, before ?? "", "utf8"); - await writeFile(afterPath, after, "utf8"); - - const result = spawnSync( - "git", - ["diff", "--no-index", "--no-ext-diff", "--", beforePath, afterPath], - { encoding: "utf8", timeout: 10_000 }, - ); - - if (result.error || result.status !== 1) { - return undefined; - } - const stdout = result.stdout; - if (!stdout) { - return undefined; - } - return rewriteDiffLabels(stdout, label, before === undefined); - } catch { - return undefined; - } finally { - await rm(tempDir, { recursive: true, force: true }).catch(() => {}); - } -} - -export default function sceExtension(pi: ExtensionAPI): void { - const pendingFileMutations = new Map(); - const piToolVersionPromise = resolvePiToolVersion(); - - pi.on("tool_call", (event) => { - if (!isToolCallEventType("bash", event)) { - return undefined; - } - - const command = event.input.command; - if (typeof command !== "string" || command.length === 0) { - return undefined; - } - - const policyResult = evaluateBashCommandPolicy(command); - if (!policyResult) { - // Fail open: if the policy check cannot be performed, allow the command. - return undefined; - } - - if (policyResult.decision === "deny" && policyResult.reason) { - return { block: true, reason: policyResult.reason }; - } - - return undefined; - }); - - pi.on("tool_call", async (event, ctx) => { - if ( - !isToolCallEventType("edit", event) && - !isToolCallEventType("write", event) - ) { - return undefined; - } - - const targetPath = event.input.path; - if (typeof targetPath !== "string" || targetPath.length === 0) { - return undefined; - } - - const absolutePath = resolvePath(ctx.cwd, targetPath); - pendingFileMutations.set(event.toolCallId, { - absolutePath, - diffLabel: diffLabelFor(ctx.cwd, absolutePath), - before: await readFileOrUndefined(absolutePath), - }); - return undefined; - }); - - pi.on("tool_result", async (event, ctx) => { - const pending = pendingFileMutations.get(event.toolCallId); - if (!pending) { - return; - } - pendingFileMutations.delete(event.toolCallId); - - if (event.isError) { - return; - } - - const after = await readFileOrUndefined(pending.absolutePath); - if (after === undefined || after === pending.before) { - return; - } - - const diff = await buildUnifiedDiff( - pending.diffLabel, - pending.before, - after, - ); - if (!diff) { - return; - } - - const sessionId = ctx.sessionManager.getSessionId(); - const generatedAtUnixMs = Date.now(); - const patchMessageId = `${event.toolCallId}-patch`; - - void runConversationTraceHook(ctx.cwd, { - payloads: [ - { - type: "message", - session_id: sessionId, - message_id: patchMessageId, - role: "assistant", - generated_at_unix_ms: generatedAtUnixMs, - }, - { - type: "message.part", - session_id: sessionId, - message_id: patchMessageId, - part_type: "patch", - text: diff, - generated_at_unix_ms: generatedAtUnixMs, - }, - ], - }); - - void runDiffTraceHook(ctx.cwd, { - sessionID: sessionId, - diff, - time: generatedAtUnixMs, - model_id: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : null, - tool_name: "pi", - tool_version: await piToolVersionPromise, - }); - }); - - pi.on("message_end", (event, ctx) => { - const message = event.message; - if (message.role !== "user" && message.role !== "assistant") { - return; - } - - const payload = buildMessageEndConversationTracePayload( - ctx.sessionManager.getSessionId(), - message, - ); - if (payload) { - void runConversationTraceHook(ctx.cwd, payload); - } - }); -} diff --git a/cli/assets/generated/config/pi/prompts/agent-shared-context-code.md b/cli/assets/generated/config/pi/prompts/agent-shared-context-code.md deleted file mode 100644 index 9d3abdd5..00000000 --- a/cli/assets/generated/config/pi/prompts/agent-shared-context-code.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -description: "Act in the shared-context-code role to execute one approved SCE task and sync context." -argument-hint: " [T0X]" ---- - -Act as the Shared Context Code agent for the rest of this session. Load and follow the `sce-task-execution` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/cli/assets/generated/config/pi/prompts/agent-shared-context-plan.md b/cli/assets/generated/config/pi/prompts/agent-shared-context-plan.md deleted file mode 100644 index 5dbad4e1..00000000 --- a/cli/assets/generated/config/pi/prompts/agent-shared-context-plan.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -description: "Act in the shared-context-plan role to create or update an SCE plan before implementation." -argument-hint: "" ---- - -Act as the Shared Context Plan agent for the rest of this session. Load and follow the `sce-plan-authoring` skill when its workflow applies. Stay within this role's rules below until the task completes. - -Input: -`$ARGUMENTS` - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/cli/assets/generated/config/pi/prompts/change-to-plan.md b/cli/assets/generated/config/pi/prompts/change-to-plan.md deleted file mode 100644 index 8a782aea..00000000 --- a/cli/assets/generated/config/pi/prompts/change-to-plan.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" ---- - -Load and follow the `sce-plan-authoring` skill. - -Input change request: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/pi/prompts/commit.md b/cli/assets/generated/config/pi/prompts/commit.md deleted file mode 100644 index b868096a..00000000 --- a/cli/assets/generated/config/pi/prompts/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -argument-hint: "[oneshot|skip]" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/cli/assets/generated/config/pi/prompts/handover.md b/cli/assets/generated/config/pi/prompts/handover.md deleted file mode 100644 index af3666ff..00000000 --- a/cli/assets/generated/config/pi/prompts/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -argument-hint: "[task context]" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/cli/assets/generated/config/pi/prompts/next-task.md b/cli/assets/generated/config/pi/prompts/next-task.md deleted file mode 100644 index 3cfa8607..00000000 --- a/cli/assets/generated/config/pi/prompts/next-task.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" -argument-hint: " [T0X]" ---- - -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. diff --git a/cli/assets/generated/config/pi/prompts/validate.md b/cli/assets/generated/config/pi/prompts/validate.md deleted file mode 100644 index e2c32ffe..00000000 --- a/cli/assets/generated/config/pi/prompts/validate.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" -argument-hint: "" ---- - -Load and follow the `sce-validation` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. diff --git a/cli/assets/generated/config/pi/skills/sce-atomic-commit/SKILL.md b/cli/assets/generated/config/pi/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7fe5bd..00000000 --- a/cli/assets/generated/config/pi/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: sce-atomic-commit -description: Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/cli/assets/generated/config/pi/skills/sce-bootstrap-context/SKILL.md b/cli/assets/generated/config/pi/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 69610b01..00000000 --- a/cli/assets/generated/config/pi/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: sce-bootstrap-context -description: Use when user wants to Bootstrap SCE baseline context directory when missing. ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/cli/assets/generated/config/pi/skills/sce-context-sync/SKILL.md b/cli/assets/generated/config/pi/skills/sce-context-sync/SKILL.md deleted file mode 100644 index f051a981..00000000 --- a/cli/assets/generated/config/pi/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: sce-context-sync -description: Use when user wants to Synchronize context files to match current code behavior after task execution. ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/cli/assets/generated/config/pi/skills/sce-handover-writer/SKILL.md b/cli/assets/generated/config/pi/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 73292812..00000000 --- a/cli/assets/generated/config/pi/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: sce-handover-writer -description: Use when user wants to create a structured SCE handover for the current task. ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/cli/assets/generated/config/pi/skills/sce-plan-authoring/SKILL.md b/cli/assets/generated/config/pi/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 02c177e4..00000000 --- a/cli/assets/generated/config/pi/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: sce-plan-authoring -description: Use when user wants to Create or update an SCE implementation plan with scoped atomic tasks. ---- - -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. diff --git a/cli/assets/generated/config/pi/skills/sce-plan-review/SKILL.md b/cli/assets/generated/config/pi/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 471baf7b..00000000 --- a/cli/assets/generated/config/pi/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: sce-plan-review -description: Use when user wants to review an existing plan and prepare the next task safely. ---- - -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill diff --git a/cli/assets/generated/config/pi/skills/sce-task-execution/SKILL.md b/cli/assets/generated/config/pi/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 36a78e5b..00000000 --- a/cli/assets/generated/config/pi/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: sce-task-execution -description: Use when user wants to Execute one approved task with explicit scope, evidence, and status updates. ---- - -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. diff --git a/cli/assets/generated/config/pi/skills/sce-validation/SKILL.md b/cli/assets/generated/config/pi/skills/sce-validation/SKILL.md deleted file mode 100644 index efb7a23e..00000000 --- a/cli/assets/generated/config/pi/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: sce-validation -description: Use when user wants to Run final plan validation and cleanup with evidence capture. ---- - -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` diff --git a/cli/assets/generated/config/schema/agent-trace.schema.json b/cli/assets/generated/config/schema/agent-trace.schema.json deleted file mode 100644 index 5ff94911..00000000 --- a/cli/assets/generated/config/schema/agent-trace.schema.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-trace.dev/schemas/v1/trace-record.json", - "title": "Agent Trace Record", - "type": "object", - "required": ["version", "id", "timestamp", "files"], - "properties": { - "version": { - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", - "description": "Agent Trace specification version (e.g., '1.0.0')" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for this trace record" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "RFC 3339 timestamp when trace was recorded" - }, - "vcs": { - "$ref": "#/$defs/vcs", - "description": "Version control system information for this trace" - }, - "tool": { - "$ref": "#/$defs/tool", - "description": "The tool that generated this trace" - }, - "files": { - "type": "array", - "items": { - "$ref": "#/$defs/file" - }, - "description": "Array of files with attributed ranges" - }, - "metadata": { - "type": "object", - "description": "Additional metadata for implementation-specific or vendor-specific data" - } - }, - "$defs": { - "vcs": { - "type": "object", - "required": ["type", "revision"], - "properties": { - "type": { - "type": "string", - "enum": ["git", "jj", "hg", "svn"], - "description": "Version control system type" - }, - "revision": { - "type": "string", - "description": "Revision identifier (e.g., git commit SHA, jj change ID)" - } - } - }, - "tool": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "version": { "type": "string" } - } - }, - "file": { - "type": "object", - "required": ["path", "conversations"], - "properties": { - "path": { - "type": "string", - "description": "Relative file path from repository root" - }, - "conversations": { - "type": "array", - "items": { - "$ref": "#/$defs/conversation" - }, - "description": "Array of conversations that contributed to this file" - } - } - }, - "contributor": { - "type": "object", - "required": ["type"], - "properties": { - "type": { - "type": "string", - "enum": ["human", "ai", "mixed", "unknown"] - }, - "model_id": { - "type": "string", - "maxLength": 250, - "description": "The model's unique identifier following models.dev convention (e.g., 'anthropic/claude-opus-4-5-20251101')" - } - } - }, - "conversation": { - "type": "object", - "required": ["ranges"], - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "URL to look up the conversation that produced this code" - }, - "contributor": { - "$ref": "#/$defs/contributor", - "description": "The contributor for ranges in this conversation (can be overridden per-range)" - }, - "ranges": { - "type": "array", - "items": { - "$ref": "#/$defs/range" - }, - "description": "Array of line ranges produced by this conversation" - }, - "related": { - "type": "array", - "items": { - "type": "object", - "required": ["type", "url"], - "properties": { - "type": { "type": "string" }, - "url": { "type": "string", "format": "uri" } - } - }, - "description": "Other related resources" - } - } - }, - "range": { - "type": "object", - "required": ["start_line", "end_line"], - "properties": { - "start_line": { "type": "integer", "minimum": 1 }, - "end_line": { "type": "integer", "minimum": 1 }, - "content_hash": { - "type": "string", - "description": "Hash of attributed content for position-independent tracking" - }, - "contributor": { - "$ref": "#/$defs/contributor", - "description": "Override contributor for this specific range (e.g., for agent handoffs)" - } - } - } - } -} diff --git a/cli/assets/generated/config/schema/sce-config.schema.json b/cli/assets/generated/config/schema/sce-config.schema.json deleted file mode 100644 index 22d97cf4..00000000 --- a/cli/assets/generated/config/schema/sce-config.schema.json +++ /dev/null @@ -1,397 +0,0 @@ -{ - "$id": "https://sce.crocoder.dev/config.json", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCE Config", - "description": "Canonical JSON Schema for global and repo-local sce/config.json files.", - "type": "object", - "properties": { - "$schema": { - "type": "string", - "const": "https://sce.crocoder.dev/config.json" - }, - "log_level": { - "type": "string", - "enum": [ - "error", - "warn", - "info", - "debug" - ] - }, - "log_format": { - "type": "string", - "enum": [ - "text", - "json" - ] - }, - "log_file": { - "type": "string", - "minLength": 1 - }, - "log_file_mode": { - "type": "string", - "enum": [ - "truncate", - "append" - ] - }, - "timeout_ms": { - "type": "integer", - "minimum": 0 - }, - "workos_client_id": { - "type": "string" - }, - "agent_trace": { - "description": "Agent Trace repository identity configuration. Selects the repository-scoped Agent Trace database.", - "type": "object", - "properties": { - "repository_id": { - "description": "Explicit repository identity. When set, overrides Git remote based repository identity resolution.", - "type": "string", - "minLength": 1 - }, - "repository_remote": { - "description": "Git remote name used to derive repository identity. Defaults to origin when omitted.", - "default": "origin", - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": false - }, - "policies": { - "type": "object", - "properties": { - "attribution_hooks": { - "description": "Attribution hook policy. Commit-msg attribution is enabled by default and can be suppressed with SCE_ATTRIBUTION_HOOKS_DISABLED=1 or by setting enabled to false.", - "type": "object", - "properties": { - "enabled": { - "description": "Enable SCE attribution hooks. Defaults to true when omitted; set false as an explicit opt-out. Environment opt-out: SCE_ATTRIBUTION_HOOKS_DISABLED.", - "default": true, - "type": "boolean" - } - }, - "additionalProperties": false - }, - "database_retry": { - "type": "object", - "properties": { - "local_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - }, - "agent_trace_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - }, - "auth_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "bash": { - "type": "object", - "properties": { - "presets": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "forbid-git-all", - "forbid-git-commit", - "use-pnpm-over-npm", - "use-bun-over-npm", - "use-nix-flake-over-cargo" - ] - }, - "uniqueItems": true, - "allOf": [ - { - "not": { - "allOf": [ - { - "contains": { - "const": "use-pnpm-over-npm" - } - }, - { - "contains": { - "const": "use-bun-over-npm" - } - } - ] - } - } - ] - }, - "custom": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "minLength": 1, - "not": { - "enum": [ - "forbid-git-all", - "forbid-git-commit", - "use-pnpm-over-npm", - "use-bun-over-npm", - "use-nix-flake-over-cargo" - ] - } - }, - "match": { - "type": "object", - "properties": { - "argv_prefix": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1 - } - }, - "additionalProperties": false, - "required": [ - "argv_prefix" - ] - }, - "satisfied_by": { - "description": "Wrapper argv prefixes that already satisfy this policy. The policy does not fire when the matched command was unwrapped from one of these wrappers, so a policy steering `rg` toward nix can stay quiet for `nix shell nixpkgs#ripgrep -c rg ...` while still blocking a bare `rg`.", - "type": "array", - "items": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1 - } - }, - "message": { - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": false, - "required": [ - "id", - "match", - "message" - ] - } - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "integrations": { - "type": "object", - "properties": { - "target": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "opencode", - "claude", - "pi" - ] - }, - "uniqueItems": true - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false, - "dependentRequired": { - "log_file_mode": [ - "log_file" - ] - } -} diff --git a/cli/build.rs b/cli/build.rs index 395875d4..ef132573 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -5,156 +5,280 @@ use std::{ fs, io::{self, Write as IoWrite}, path::{Path, PathBuf}, + process::Command, }; +const PKL_OUTPUT_DIR: &str = "pkl-generated"; +const STATIC_OUTPUT_DIR: &str = "static"; +const MIGRATIONS_ROOT: &str = "migrations"; +const PACKAGE_FALLBACK_DIR: &str = "package-fallback"; +const PACKAGE_FALLBACK_INVENTORY: &str = "SHA256SUMS"; + const TARGETS: &[TargetSpec] = &[ TargetSpec { const_name: "OPENCODE_EMBEDDED_ASSETS", - relative_root: "assets/generated/config/opencode", - allow_dead_code: false, + generated_root: "config/.opencode", }, TargetSpec { const_name: "CLAUDE_EMBEDDED_ASSETS", - relative_root: "assets/generated/config/claude", - allow_dead_code: false, + generated_root: "config/.claude", }, TargetSpec { const_name: "PI_EMBEDDED_ASSETS", - relative_root: "assets/generated/config/pi", - allow_dead_code: false, + generated_root: "config/.pi", }, TargetSpec { const_name: "HOOK_EMBEDDED_ASSETS", - relative_root: "assets/hooks", - allow_dead_code: false, + generated_root: "static/hooks", }, ]; -const MIGRATIONS_ROOT: &str = "migrations"; -const GENERATED_MIGRATIONS_PATH: &str = "src/generated_migrations.rs"; - struct TargetSpec { const_name: &'static str, - relative_root: &'static str, - allow_dead_code: bool, + generated_root: &'static str, } fn main() { - if let Err(error) = generate_embedded_asset_manifest() { - panic!("failed to generate setup embedded asset manifest: {error}"); - } - - if let Err(error) = generate_migration_manifest() { - panic!("failed to generate embedded migration manifest: {error}"); + if let Err(error) = prepare_build_artifacts() { + panic!("failed to prepare embedded CLI build artifacts: {error}"); } emit_git_commit(); emit_repo_version(); } -fn generate_migration_manifest() -> io::Result<()> { +fn prepare_build_artifacts() -> io::Result<()> { println!("cargo:rerun-if-changed=build.rs"); let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|e| invalid_data(&e))?); - let migrations_root = manifest_dir.join(MIGRATIONS_ROOT); - let destination_path = manifest_dir.join(GENERATED_MIGRATIONS_PATH); + let repository_root = manifest_dir + .parent() + .ok_or_else(|| invalid_data(&"CLI manifest directory must have a repository parent"))?; + let out_dir = PathBuf::from(env::var("OUT_DIR").map_err(|e| invalid_data(&e))?); - println!("cargo:rerun-if-changed={}", migrations_root.display()); + if repository_sources_available(repository_root) { + generate_pkl_outputs(repository_root, &out_dir)?; + stage_static_inputs(repository_root, &manifest_dir, &out_dir)?; + } else { + stage_packaged_fallback(&manifest_dir, &out_dir)?; + } + validate_staged_artifacts(&out_dir)?; + generate_embedded_asset_manifest(&out_dir)?; + generate_migration_manifest(&out_dir) +} - let mut databases = collect_migration_databases(&migrations_root)?; - databases.sort_unstable_by(|a, b| a.directory_name.cmp(&b.directory_name)); +fn repository_sources_available(repository_root: &Path) -> bool { + repository_root.join("config/pkl/generate.pkl").is_file() + && repository_root.join("config/lib").is_dir() +} - let mut output = String::new(); - output.push_str("// @generated by build.rs; do not edit by hand.\n"); - output.push_str("#![allow(dead_code)]\n\n"); +fn generate_pkl_outputs(repository_root: &Path, out_dir: &Path) -> io::Result<()> { + let pkl_root = repository_root.join("config/pkl"); + let config_lib_root = repository_root.join("config/lib"); + emit_rerun_tree(&pkl_root)?; + emit_rerun_tree(&config_lib_root)?; + + let output_root = out_dir.join(PKL_OUTPUT_DIR); + remove_path_if_exists(&output_root)?; + fs::create_dir_all(&output_root)?; + + let generator = pkl_root.join("generate.pkl"); + let status = Command::new("pkl") + .arg("eval") + .arg("-m") + .arg(&output_root) + .arg(&generator) + .current_dir(repository_root) + .status() + .map_err(|error| { + invalid_data(&format!( + "could not run Pkl generator '{}': {error}. Run Cargo from the Nix dev shell", + generator.display() + )) + })?; + + if !status.success() { + return Err(invalid_data(&format!( + "Pkl generator '{}' exited with {status}", + generator.display() + ))); + } - for database in &databases { - output.push_str("#[rustfmt::skip]\n"); - output.push_str("pub static "); - output.push_str(&database.const_name); - output.push_str(": &[(&str, &str)] = &[\n"); + for target in TARGETS.iter().take(3) { + let expected_root = output_root.join(target.generated_root); + if !expected_root.is_dir() { + return Err(invalid_data(&format!( + "Pkl generator did not emit required target directory '{}'", + expected_root.display() + ))); + } + } - for migration in &database.migrations { - println!( - "cargo:rerun-if-changed={}", - migration.absolute_path.display() - ); - writeln!( - output, - " (\"{}\", include_str!(\"{}\")),", - escape_for_rust_string(&migration.id), - escape_for_rust_string(&migration.include_path), - ) - .expect("writing to String buffer should never fail"); + Ok(()) +} + +fn stage_packaged_fallback(manifest_dir: &Path, out_dir: &Path) -> io::Result<()> { + let fallback_root = manifest_dir.join(PACKAGE_FALLBACK_DIR); + println!("cargo:rerun-if-changed={}", fallback_root.display()); + validate_fallback_inventory(&fallback_root)?; + + for directory in [PKL_OUTPUT_DIR, STATIC_OUTPUT_DIR] { + let source = fallback_root.join(directory); + let destination = out_dir.join(directory); + remove_path_if_exists(&destination)?; + copy_tree(&source, &destination)?; + } + + Ok(()) +} + +fn validate_fallback_inventory(fallback_root: &Path) -> io::Result<()> { + let inventory_path = fallback_root.join(PACKAGE_FALLBACK_INVENTORY); + let expected = fs::read_to_string(&inventory_path).map_err(|error| { + invalid_data(&format!( + "packaged fallback inventory '{}' is unavailable: {error}. The crate package must be prepared with scripts/prepare-cli-generated-assets.sh", + inventory_path.display() + )) + })?; + + let mut files = Vec::new(); + for directory in [PKL_OUTPUT_DIR, STATIC_OUTPUT_DIR] { + let root = fallback_root.join(directory); + if !root.is_dir() { + return Err(invalid_data(&format!( + "packaged fallback is missing required directory '{}'. Recreate the crate package with scripts/prepare-cli-generated-assets.sh", + root.display() + ))); } + collect_files(fallback_root, &root, &mut files)?; + } + files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path)); - output.push_str("];\n\n"); + let mut actual = String::new(); + for file in files { + let digest = compute_sha256(&fs::read(&file.absolute_path)?); + writeln!(actual, "{} {}", format_hex(&digest), file.relative_path) + .expect("writing to String buffer should never fail"); } - let trimmed = format!("{}\n", output.trim_end()); - write_if_changed(&destination_path, trimmed.as_bytes()) + if actual != expected { + return Err(invalid_data(&format!( + "packaged fallback inventory '{}' does not match its payload. Recreate the crate package with scripts/prepare-cli-generated-assets.sh", + inventory_path.display() + ))); + } + + Ok(()) } -fn emit_git_commit() { - // Commit embedding is release-only: the flake sets SCE_GIT_COMMIT solely on - // the release package derivation. Ordinary native builds, `cargo test`, - // Clippy, fmt, and other checks leave it unset so they stay cache-reusable - // across commits. When absent, the app falls back to "unknown" via - // `option_env!`. Deliberately no `git rev-parse` fallback and no - // `.git/HEAD` / `.git/packed-refs` rerun watches. - println!("cargo:rerun-if-env-changed=SCE_GIT_COMMIT"); +fn validate_staged_artifacts(out_dir: &Path) -> io::Result<()> { + for target in TARGETS.iter().take(3) { + let expected_root = out_dir.join(PKL_OUTPUT_DIR).join(target.generated_root); + if !expected_root.is_dir() { + return Err(invalid_data(&format!( + "embedded artifact preparation did not provide required target directory '{}'", + expected_root.display() + ))); + } + } - if let Ok(commit) = env::var("SCE_GIT_COMMIT") { - let commit = commit.trim(); - if !commit.is_empty() { - println!("cargo:rustc-env=SCE_GIT_COMMIT={commit}"); + for relative_path in [ + "static/hooks", + "static/migrations", + "static/schema/agent-trace.schema.json", + "pkl-generated/config/schema/sce-config.schema.json", + ] { + if !out_dir.join(relative_path).exists() { + return Err(invalid_data(&format!( + "embedded artifact preparation did not provide required path '{}'", + out_dir.join(relative_path).display() + ))); } } + + Ok(()) } -fn emit_repo_version() { - let manifest_dir = match env::var("CARGO_MANIFEST_DIR") { - Ok(value) => PathBuf::from(value), - Err(_) => return, - }; +fn stage_static_inputs( + repository_root: &Path, + manifest_dir: &Path, + out_dir: &Path, +) -> io::Result<()> { + let static_root = out_dir.join(STATIC_OUTPUT_DIR); + remove_path_if_exists(&static_root)?; + + copy_tree( + &manifest_dir.join("assets/hooks"), + &static_root.join("hooks"), + )?; + copy_tree( + &manifest_dir.join(MIGRATIONS_ROOT), + &static_root.join(MIGRATIONS_ROOT), + )?; + copy_file( + &repository_root.join("config/schema/agent-trace.schema.json"), + &static_root.join("schema/agent-trace.schema.json"), + ) +} - let repository_root = match manifest_dir.parent() { - Some(path) => path.to_path_buf(), - None => return, - }; +fn copy_tree(source_root: &Path, destination_root: &Path) -> io::Result<()> { + println!("cargo:rerun-if-changed={}", source_root.display()); - let version_path = repository_root.join(".version"); - println!("cargo:rerun-if-changed={}", version_path.display()); + let mut files = Vec::new(); + collect_files(source_root, source_root, &mut files)?; + files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path)); - let Ok(bytes) = fs::read(&version_path) else { - return; - }; + for file in files { + println!("cargo:rerun-if-changed={}", file.absolute_path.display()); + copy_file( + &file.absolute_path, + &destination_root.join(&file.relative_path), + )?; + } - let version = String::from_utf8_lossy(&bytes); - let version = version.trim(); - if !version.is_empty() { - println!("cargo:rustc-env=SCE_VERSION={version}"); + Ok(()) +} + +fn copy_file(source: &Path, destination: &Path) -> io::Result<()> { + println!("cargo:rerun-if-changed={}", source.display()); + let parent = destination + .parent() + .ok_or_else(|| invalid_data(&"staged file must have a parent directory"))?; + fs::create_dir_all(parent)?; + fs::copy(source, destination)?; + Ok(()) +} + +fn emit_rerun_tree(root: &Path) -> io::Result<()> { + println!("cargo:rerun-if-changed={}", root.display()); + let mut files = Vec::new(); + collect_files(root, root, &mut files)?; + files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path)); + for file in files { + println!("cargo:rerun-if-changed={}", file.absolute_path.display()); } + Ok(()) } -fn generate_embedded_asset_manifest() -> io::Result<()> { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|e| invalid_data(&e))?); - let out_dir = PathBuf::from(env::var("OUT_DIR").map_err(|e| invalid_data(&e))?); +fn generate_embedded_asset_manifest(out_dir: &Path) -> io::Result<()> { let destination_path = out_dir.join("setup_embedded_assets.rs"); - let mut output = String::new(); for target in TARGETS { - let source_root = manifest_dir.join(target.relative_root); - println!("cargo:rerun-if-changed={}", source_root.display()); + let source_root = if target.generated_root.starts_with("static/") { + out_dir.join(target.generated_root) + } else { + out_dir.join(PKL_OUTPUT_DIR).join(target.generated_root) + }; + let include_root = source_root + .strip_prefix(out_dir) + .map_err(|_| invalid_data(&"embedded asset root must be inside OUT_DIR"))?; + let include_root = normalize_relative_path(include_root)?; let mut files = Vec::new(); collect_files(&source_root, &source_root, &mut files)?; - files.sort_unstable_by(|a, b| a.relative_path.cmp(&b.relative_path)); + files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path)); - if target.allow_dead_code { - output.push_str("#[allow(dead_code)]\n"); - } writeln!( output, "pub static {}: &[EmbeddedAsset] = &[", @@ -163,15 +287,12 @@ fn generate_embedded_asset_manifest() -> io::Result<()> { .expect("writing to String buffer should never fail"); for file in &files { - println!("cargo:rerun-if-changed={}", file.absolute_path.display()); let bytes = fs::read(&file.absolute_path)?; let sha256 = compute_sha256(&bytes); - let include_path = format!("{}/{}", target.relative_root, file.relative_path); + let include_path = format!("{include_root}/{}", file.relative_path); writeln!( output, - " EmbeddedAsset {{ relative_path: \"{}\", \ - bytes: include_bytes!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/{}\")), \ - sha256: {} }},", + " EmbeddedAsset {{ relative_path: \"{}\", bytes: include_bytes!(concat!(env!(\"OUT_DIR\"), \"/{}\")), sha256: {} }},", escape_for_rust_string(&file.relative_path), escape_for_rust_string(&include_path), format_byte_literal("[", &sha256), @@ -186,6 +307,71 @@ fn generate_embedded_asset_manifest() -> io::Result<()> { output_file.write_all(output.as_bytes()) } +fn generate_migration_manifest(out_dir: &Path) -> io::Result<()> { + let migrations_root = out_dir.join(STATIC_OUTPUT_DIR).join(MIGRATIONS_ROOT); + let destination_path = out_dir.join("generated_migrations.rs"); + let mut databases = collect_migration_databases(&migrations_root)?; + databases.sort_unstable_by(|left, right| left.directory_name.cmp(&right.directory_name)); + + let mut output = String::new(); + output.push_str("// @generated by build.rs; do not edit by hand.\n\n"); + + for database in &databases { + output.push_str("#[rustfmt::skip]\n"); + output.push_str("pub static "); + output.push_str(&database.const_name); + output.push_str(": &[(&str, &str)] = &[\n"); + + for migration in &database.migrations { + writeln!( + output, + " (\"{}\", include_str!(concat!(env!(\"OUT_DIR\"), \"/static/migrations/{}/{}.sql\"))),", + escape_for_rust_string(&migration.id), + escape_for_rust_string(&database.directory_name), + escape_for_rust_string(&migration.id), + ) + .expect("writing to String buffer should never fail"); + } + + output.push_str("];\n\n"); + } + + write_if_changed(&destination_path, output.as_bytes()) +} + +fn emit_git_commit() { + println!("cargo:rerun-if-env-changed=SCE_GIT_COMMIT"); + + if let Ok(commit) = env::var("SCE_GIT_COMMIT") { + let commit = commit.trim(); + if !commit.is_empty() { + println!("cargo:rustc-env=SCE_GIT_COMMIT={commit}"); + } + } +} + +fn emit_repo_version() { + let manifest_dir = match env::var("CARGO_MANIFEST_DIR") { + Ok(value) => PathBuf::from(value), + Err(_) => return, + }; + let Some(repository_root) = manifest_dir.parent() else { + return; + }; + + let version_path = repository_root.join(".version"); + println!("cargo:rerun-if-changed={}", version_path.display()); + + let Ok(bytes) = fs::read(&version_path) else { + return; + }; + let version = String::from_utf8_lossy(&bytes); + let version = version.trim(); + if !version.is_empty() { + println!("cargo:rustc-env=SCE_VERSION={version}"); + } +} + #[derive(Debug)] struct MigrationDatabase { directory_name: String, @@ -195,9 +381,7 @@ struct MigrationDatabase { #[derive(Debug)] struct MigrationFile { - absolute_path: PathBuf, id: String, - include_path: String, sort_prefix: u64, } @@ -206,7 +390,6 @@ fn collect_migration_databases(migrations_root: &Path) -> io::Result io::Result io::Result io::Result> { +fn collect_migration_files(directory_path: &Path) -> io::Result> { let mut migrations = Vec::new(); for entry in fs::read_dir(directory_path)? { let entry = entry?; let path = entry.path(); - if entry.file_type()?.is_dir() || path.extension().and_then(|value| value.to_str()) != Some("sql") { @@ -258,10 +434,7 @@ fn collect_migration_files( .and_then(|value| value.to_str()) .ok_or_else(|| invalid_data(&"non-UTF-8 migration filenames are not supported"))? .to_owned(); - migrations.push(MigrationFile { - absolute_path: path, - include_path: format!("../{MIGRATIONS_ROOT}/{directory_name}/{id}.sql"), sort_prefix: migration_sort_prefix(&id)?, id, }); @@ -275,19 +448,16 @@ fn migration_sort_prefix(id: &str) -> io::Result { .split_once('_') .map(|(prefix, _)| prefix) .ok_or_else(|| invalid_data(&format!("migration filename '{id}' must contain '_'")))?; - if prefix.is_empty() || !prefix.chars().all(|character| character.is_ascii_digit()) { return Err(invalid_data(&format!( "migration filename '{id}' must start with a numeric prefix" ))); } - prefix.parse::().map_err(|error| invalid_data(&error)) } fn migration_const_name(directory_name: &str) -> io::Result { let mut const_name = String::new(); - for character in directory_name.chars() { if character.is_ascii_alphanumeric() { const_name.push(character.to_ascii_uppercase()); @@ -299,11 +469,9 @@ fn migration_const_name(directory_name: &str) -> io::Result { ))); } } - if const_name.is_empty() { return Err(invalid_data(&"migration directory name cannot be empty")); } - const_name.push_str("_MIGRATIONS"); Ok(const_name) } @@ -322,7 +490,6 @@ fn collect_files( for entry in fs::read_dir(current_dir)? { let entry = entry?; let path = entry.path(); - if entry.file_type()?.is_dir() { collect_files(base_root, &path, output)?; continue; @@ -331,15 +498,12 @@ fn collect_files( let relative_path = path .strip_prefix(base_root) .map_err(|_| invalid_data(&"failed to strip source root from file path"))?; - let relative_path = normalize_relative_path(relative_path)?; - output.push(SourceFile { absolute_path: path, relative_path, }); } - Ok(()) } @@ -348,16 +512,20 @@ fn normalize_relative_path(path: &Path) -> io::Result { .to_str() .ok_or_else(|| invalid_data(&"non-UTF-8 config paths are not supported"))? .replace('\\', "/"); - - if normalized.is_empty() { - return Err(invalid_data(&"relative path cannot be empty")); + if normalized.is_empty() || normalized.starts_with('/') { + return Err(invalid_data(&"path must be a non-empty relative path")); } + Ok(normalized) +} - if normalized.starts_with('/') { - return Err(invalid_data(&"relative path must not start with '/'")); +fn remove_path_if_exists(path: &Path) -> io::Result<()> { + if path.is_dir() { + fs::remove_dir_all(path) + } else if path.exists() { + fs::remove_file(path) + } else { + Ok(()) } - - Ok(normalized) } fn escape_for_rust_string(value: &str) -> String { @@ -365,8 +533,14 @@ fn escape_for_rust_string(value: &str) -> String { } fn compute_sha256(bytes: &[u8]) -> [u8; 32] { - let digest = Sha256::digest(bytes); - digest.into() + Sha256::digest(bytes).into() +} + +fn format_hex(bytes: &[u8]) -> String { + bytes.iter().fold(String::new(), |mut output, byte| { + write!(output, "{byte:02x}").expect("writing to String buffer should never fail"); + output + }) } fn format_byte_literal(prefix: &str, bytes: &[u8]) -> String { @@ -384,7 +558,6 @@ fn write_if_changed(path: &Path, bytes: &[u8]) -> io::Result<()> { if fs::read(path).is_ok_and(|existing| existing == bytes) { return Ok(()); } - fs::write(path, bytes) } diff --git a/cli/src/generated_migrations.rs b/cli/src/generated_migrations.rs deleted file mode 100644 index 1acdb477..00000000 --- a/cli/src/generated_migrations.rs +++ /dev/null @@ -1,13 +0,0 @@ -// @generated by build.rs; do not edit by hand. -#![allow(dead_code)] - -#[rustfmt::skip] -pub static AGENT_TRACE_REPOSITORY_MIGRATIONS: &[(&str, &str)] = &[ - ("001_repository_schema", include_str!("../migrations/agent-trace-repository/001_repository_schema.sql")), -]; - -#[rustfmt::skip] -pub static AUTH_MIGRATIONS: &[(&str, &str)] = &[ - ("001_create_auth_tokens", include_str!("../migrations/auth/001_create_auth_tokens.sql")), - ("002_create_auth_credentials_updated_at_trigger", include_str!("../migrations/auth/002_create_auth_credentials_updated_at_trigger.sql")), -]; diff --git a/cli/src/main.rs b/cli/src/main.rs index 91a30184..5f4ee707 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,7 +1,10 @@ mod app; mod cli_schema; mod command_surface; -mod generated_migrations; +#[allow(dead_code)] +mod generated_migrations { + include!(concat!(env!("OUT_DIR"), "/generated_migrations.rs")); +} mod services; use std::process::ExitCode; diff --git a/cli/src/services/agent_trace.rs b/cli/src/services/agent_trace.rs index cec0c6a6..b68dc9e9 100644 --- a/cli/src/services/agent_trace.rs +++ b/cli/src/services/agent_trace.rs @@ -133,8 +133,10 @@ fn parse_commit_timestamp(commit_timestamp: &str) -> Result = OnceLock::new(); diff --git a/cli/src/services/config/policy.rs b/cli/src/services/config/policy.rs index 853760af..3a3302c2 100644 --- a/cli/src/services/config/policy.rs +++ b/cli/src/services/config/policy.rs @@ -19,8 +19,10 @@ use super::schema::{ use super::types::{ConfigPathSource, ResolvedOptionalValue, ValueSource}; use crate::services::style; -const BASH_POLICY_PRESET_CATALOG_JSON: &str = - include_str!("../../../assets/generated/config/opencode/lib/bash-policy-presets.json"); +const BASH_POLICY_PRESET_CATALOG_JSON: &str = include_str!(concat!( + env!("OUT_DIR"), + "/pkl-generated/config/.opencode/lib/bash-policy-presets.json" +)); static BUILTIN_BASH_POLICY_CATALOG: OnceLock = OnceLock::new(); diff --git a/cli/src/services/config/schema.rs b/cli/src/services/config/schema.rs index 8a1feec1..ae19364a 100644 --- a/cli/src/services/config/schema.rs +++ b/cli/src/services/config/schema.rs @@ -23,8 +23,10 @@ use super::types::{ }; use crate::services::resilience::RetryPolicy; -pub(crate) const SCE_CONFIG_SCHEMA_JSON: &str = - include_str!("../../../assets/generated/config/schema/sce-config.schema.json"); +pub(crate) const SCE_CONFIG_SCHEMA_JSON: &str = include_str!(concat!( + env!("OUT_DIR"), + "/pkl-generated/config/schema/sce-config.schema.json" +)); pub(crate) const CONFIG_SCHEMA_DECLARATION_KEY: &str = "$schema"; diff --git a/cli/src/services/default_paths.rs b/cli/src/services/default_paths.rs index 40a98bdd..2ebd37c7 100644 --- a/cli/src/services/default_paths.rs +++ b/cli/src/services/default_paths.rs @@ -362,12 +362,6 @@ pub(crate) mod hook_dir { pub const POST_COMMIT: &str = "post-commit"; } -#[allow(dead_code)] -pub(crate) mod embedded_asset_root { - pub const GENERATED_CONFIG: &str = "assets/generated/config"; - pub const HOOKS: &str = "assets/hooks"; -} - #[allow(dead_code)] pub(crate) mod opencode_asset { pub const OPENCODE_DIR: &str = "opencode"; @@ -383,7 +377,6 @@ pub(crate) mod opencode_asset { } pub(crate) mod claude_asset { - pub const CLAUDE_DIR: &str = "claude"; pub const SETTINGS_FILE: &str = "settings.json"; pub const HOOKS_DIR: &str = "hooks"; pub const SKILLS_DIR: &str = "skills"; @@ -518,79 +511,6 @@ impl RepoPaths { } } -#[allow(dead_code)] -#[derive(Clone, Debug, Eq, PartialEq)] -pub(crate) struct EmbeddedAssetPaths { - cli_root: PathBuf, -} - -#[allow(dead_code)] -impl EmbeddedAssetPaths { - pub(crate) fn new(cli_root: impl Into) -> Self { - Self { - cli_root: cli_root.into(), - } - } - - pub(crate) fn generated_config_root(&self) -> PathBuf { - self.cli_root.join(embedded_asset_root::GENERATED_CONFIG) - } - - pub(crate) fn hooks_root(&self) -> PathBuf { - self.cli_root.join(embedded_asset_root::HOOKS) - } - - pub(crate) fn opencode_assets_dir(&self) -> PathBuf { - self.generated_config_root() - .join(opencode_asset::OPENCODE_DIR) - } - - pub(crate) fn opencode_plugins_dir(&self) -> PathBuf { - self.opencode_assets_dir().join(opencode_asset::PLUGINS_DIR) - } - - pub(crate) fn opencode_plugin_file(&self) -> PathBuf { - self.opencode_plugins_dir() - .join(opencode_asset::PLUGIN_FILE) - } - - pub(crate) fn opencode_lib_dir(&self) -> PathBuf { - self.opencode_assets_dir().join(opencode_asset::LIB_DIR) - } - - pub(crate) fn opencode_preset_catalog(&self) -> PathBuf { - self.opencode_lib_dir().join(opencode_asset::PRESET_CATALOG) - } - - pub(crate) fn opencode_skills_dir(&self) -> PathBuf { - self.opencode_assets_dir().join(opencode_asset::SKILLS_DIR) - } - - pub(crate) fn opencode_agents_dir(&self) -> PathBuf { - self.opencode_assets_dir().join(opencode_asset::AGENTS_DIR) - } - - pub(crate) fn claude_assets_dir(&self) -> PathBuf { - self.generated_config_root().join(claude_asset::CLAUDE_DIR) - } - - pub(crate) fn claude_skills_dir(&self) -> PathBuf { - self.claude_assets_dir().join(claude_asset::SKILLS_DIR) - } - - pub(crate) fn claude_agents_dir(&self) -> PathBuf { - self.claude_assets_dir().join(claude_asset::AGENTS_DIR) - } - - pub(crate) fn config_schema_dir(&self) -> PathBuf { - self.cli_root.join(schema::SCHEMA_DIR) - } - - pub(crate) fn sce_config_schema_file(&self) -> PathBuf { - self.config_schema_dir().join(schema::SCE_CONFIG_SCHEMA) - } -} - #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct InstallTargetPaths { repo_root: PathBuf, diff --git a/cli/src/services/setup/mod.rs b/cli/src/services/setup/mod.rs index 5254c47d..aeeb4b01 100644 --- a/cli/src/services/setup/mod.rs +++ b/cli/src/services/setup/mod.rs @@ -1296,4 +1296,22 @@ mod tests { assert!(iter_embedded_assets_for_setup_target(SetupTarget::Pi).count() > 0); assert_eq!(all_count, concrete_sum); } + + #[test] + fn embedded_build_payload_contains_generated_targets_and_static_hooks() { + let contains = |target, path| { + iter_embedded_assets_for_setup_target(target) + .any(|asset| asset.relative_path == path && !asset.bytes.is_empty()) + }; + + assert!(contains(SetupTarget::OpenCode, "command/next-task.md")); + assert!(contains( + SetupTarget::OpenCode, + "lib/bash-policy-presets.json" + )); + assert!(contains(SetupTarget::Claude, "commands/next-task.md")); + assert!(contains(SetupTarget::Pi, "prompts/next-task.md")); + assert!(contains(SetupTarget::Pi, "extensions/sce/index.ts")); + assert!(iter_required_hook_assets().all(|asset| !asset.bytes.is_empty())); + } } diff --git a/config/.claude/commands/change-to-plan.md b/config/.claude/commands/change-to-plan.md deleted file mode 100644 index 556c578e..00000000 --- a/config/.claude/commands/change-to-plan.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill ---- - -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> Continue to the next step. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> Continue to the next step. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.claude/commands/next-task.md b/config/.claude/commands/next-task.md deleted file mode 100644 index a52e26ff..00000000 --- a/config/.claude/commands/next-task.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" -argument-hint: " [T0X] [approved]" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> Pass the complete readiness result to `sce-task-execution`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> continue to the next step. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. diff --git a/config/.claude/commands/validate.md b/config/.claude/commands/validate.md deleted file mode 100644 index bbaeca4f..00000000 --- a/config/.claude/commands/validate.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" -argument-hint: "" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. diff --git a/config/.claude/hooks/run-sce-or-show-install-guidance.sh b/config/.claude/hooks/run-sce-or-show-install-guidance.sh deleted file mode 100644 index a01dc897..00000000 --- a/config/.claude/hooks/run-sce-or-show-install-guidance.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if ! command -v sce >/dev/null 2>&1; then - echo "sce CLI not found. Install it from https://sce.crocoder.dev/docs/getting-started#install-cli" >&2 - exit 0 -fi - -exec "$@" \ No newline at end of file diff --git a/config/.claude/settings.json b/config/.claude/settings.json deleted file mode 100644 index 75cda4c6..00000000 --- a/config/.claude/settings.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "hooks": { - "PreToolUse": [ - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce policy bash" - } - ] - } - ], - "PostToolUse": [ - { - "matcher": "Write|Edit|MultiEdit|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks diff-trace" - } - ] - }, - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ], - "UserPromptSubmit": [ - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ], - "Stop": [ - { - "hooks": [ - { - "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-show-install-guidance.sh\" sce hooks conversation-trace" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/config/.claude/skills/sce-context-load/SKILL.md b/config/.claude/skills/sce-context-load/SKILL.md deleted file mode 100644 index 67e569b8..00000000 --- a/config/.claude/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. -compatibility: claude ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -`references/context-brief.yaml` - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.claude/skills/sce-context-load/references/context-brief.yaml b/config/.claude/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/config/.claude/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/config/.claude/skills/sce-plan-authoring/SKILL.md b/config/.claude/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 1b34665e..00000000 --- a/config/.claude/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -name: sce-plan-authoring -description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. -compatibility: claude ---- - -# SCE Plan Authoring - -## Purpose - -Turn exactly one change request into `context/plans/{plan_name}.md` without -inventing material requirements. - -This skill owns: - -- Resolving whether the request targets a new or an existing plan. -- Judging whether the change is worth making, and recording the doubt when it - is not clear that it is. -- Deciding whether the request can be planned safely. -- Normalizing the change summary, acceptance criteria, constraints, and - non-goals. -- Slicing the work into atomic implementation tasks. -- Writing the plan file. -- Returning one structured authoring result. - -Use the document format defined in: - -`references/plan-template.md` - -Return a result matching: - -`references/authoring-contract.yaml` - -The invoking workflow renders that result as the summary defined in: - -`references/plan-summary.md` - -## Input - -The invoking workflow provides: - -- One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. - -The change request may name a plan, describe a change to an existing plan, or -describe entirely new work. Resolving which applies is this skill's -responsibility. - -The context brief is the durable memory this plan starts from. Treat its -`key_facts` as recorded current state, its `gaps` as areas with no durable -context, and its `drift` as context the code has already outrun. - -When no brief is supplied, load the context named by the change request before -authoring, and follow the selection discipline in *Inspect relevant context*. - -Answers the user gave to earlier clarification questions arrive as part of the -change request. Incorporate them into the plan. - -A revision of a plan authored earlier in the session also arrives as the change -request, and it is usually terse: a task boundary the user disagrees with, an -ordering they want changed, work they want added or dropped. Read it against the -existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the -plan already carries; ask only when the revision itself is genuinely undecidable. - -## Workflow - -### 1. Resolve the plan target - -Determine whether the request targets a new plan or an existing plan in -`context/plans/`. - -When it targets an existing plan, read that plan before authoring. Preserve its -completed tasks, their recorded evidence, its structure, and its terminology. - -When multiple existing plans match and none can be selected safely, return -`blocked` with the matching candidates. - -When the request targets a new plan, derive `plan_name` as a short kebab-case -slug of the change, and confirm it does not collide with an existing plan. - -Resolve exactly one plan target per invocation. - -### 2. Challenge the change - -Before planning how to build the change, work out whether it is worth building. -A plan is a commitment of someone's time; authoring one for work that should not -happen is worse than authoring none. - -Interrogate the request: - -- What breaks, or stays broken, if this is never built? If the answer is - nothing concrete, say so. -- What problem is it actually solving, as opposed to what it proposes to do? A - request that names only a solution has not stated a problem. -- Does the repository already do this, or most of it? The brief's `key_facts` - are the first place to check. -- Is there a materially smaller version that gets most of the value? Name it. -- What does this cost beyond the tasks: new dependency, new concept in the - glossary, a boundary crossed, a surface that now needs maintaining forever? -- Does the stated justification survive contact with the code, or does the code - show the premise is already false? - -Doubt that survives this is not an implementation detail to be tidied away. It -belongs in the plan's `Open questions` and in `open_questions`, in the plain -words you would use to a colleague. "Is this worth doing at all, given X?" is a -legitimate open question. So is "this looks like it duplicates Y". - -Weigh honestly in both directions. A request that is obviously worth building -gets no manufactured doubt: inventing questions to look rigorous is its own -failure, and it teaches the user to ignore the section. Most changes are fine. -Say nothing when there is nothing to say. - -Keep going regardless. Skepticism shapes the plan and the open questions; it -does not withhold the plan. The only value judgment that stops authoring is -`no_actionable_work`, when the change is already implemented. - -### 3. Run the clarification gate - -Before writing or updating any plan file, check the request for critical -unresolved detail: - -- Scope boundaries and out-of-scope items. -- Acceptance criteria and the checks that prove them. -- Constraints and non-goals. -- Dependency choices, including new libraries or services, versions, and the - integration approach. -- Domain ambiguity, including unclear business rules, terminology, or ownership. -- Architecture concerns, including patterns, interfaces, data flow, migration - strategy, and risk tradeoffs. -- Task ordering assumptions and prerequisite sequencing. - -Return `needs_clarification` with one to three targeted questions when any of -these would materially change the plan. Write no plan file in that case. - -Use repository conventions for ordinary local choices. Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change scope, acceptance criteria, or task ordering. - -Record those choices under `assumptions`. - -Do not silently invent missing requirements. When the user has explicitly -allowed assumptions, record them in the plan's `Assumptions` section instead of -asking. - -A justification that does not survive inspection is itself a critical unresolved -detail. "For consistency", "to make it cleaner", "we will need it later" name no -outcome and prove nothing; ask what the change is actually for before planning -around it. Do not treat confident phrasing as evidence. - -### 4. Inspect relevant context - -Start from the context brief. Read code only where the brief leaves the change -underspecified: - -- Existing behavior the change affects. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests and available verification commands. -- Decisions or specifications connected to the change. - -Where the brief reports `drift`, the code is the source of truth. Plan against -the code, and schedule the context repair as part of the change when it falls -inside scope. - -Where the brief reports `gaps`, the plan may need to establish durable context -the repository does not yet have. - -Do not explore the entire repository by default. - -### 5. Author the acceptance criteria - -State how the finished plan is proven, before slicing tasks. - -Each criterion describes observable behavior of the finished system and names -the check that proves it. Record repository-wide checks once under -`Full validation`, and the durable context the change must be reflected in -under `Context sync`. - -`/validate` runs this section after the last task completes. It is the only -place a plan says how it is validated. - -### 6. Author the task stack - -Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. - -Every executable task must be completable and landable as one coherent commit. -Split any task that would require multiple independent commits. Convert broad -wrappers such as `polish` or `finalize` into specific outcomes with concrete -acceptance checks. - -Order tasks so each one's declared dependencies precede it. - -The last task is an ordinary implementation task. Do not author a trailing -validation-and-cleanup task, or any task whose only purpose is running the full -check suite, verifying durable context, or removing scaffolding. - -Confirm every acceptance criterion is satisfied by at least one task. When one -is not, the task stack is incomplete. - -A finished stack always leaves at least one incomplete task, so the invoking -workflow can always hand off to `/next-task`. When the request resolves to a -plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category -`no_actionable_work` instead of writing the plan. - -### 7. Write the plan - -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. - -When updating an existing plan, keep completed tasks and their evidence intact, -and append or renumber new tasks without disturbing recorded history. - -### 8. Return the result - -Return exactly one structured result: - -- `plan_ready` -- `needs_clarification` -- `blocked` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Tone - -Every question and open question this skill writes is read by the user. Write -them the way a senior engineer talks in review: direct, specific, and unbothered -by the possibility of being unwelcome. - -- Ask about the thing that actually worries you, not a safer neighbouring thing. - A question you would not bother asking a colleague is not worth the user's - attention either. -- State a doubt as a doubt. "I do not think this is worth the two tasks it - costs, because X" is useful. "It may be worth considering whether this aligns - with broader goals" is noise. -- Name the alternative you have in mind. A challenge with no proposal behind it - is just friction. -- Do not open with praise, do not close with reassurance, and do not apologize - for asking. Do not pad a doubt with hedges to make it land more gently. -- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not - restate the same doubt in three shapes to give it more weight. -- Being disagreeable is not the goal. Being easy to agree with is the failure - mode. A plan the user waves through without reading has cost them nothing and - bought them nothing. - -When the user overrules a doubt, record it and move on. Do not relitigate a -decision the user has made, and do not smuggle the objection back in as a -constraint, a non-goal, or a task. - -## Boundaries - -Do not: - -- Ask the user questions directly. Return `needs_clarification` and let the - invoking workflow present the questions. -- Answer your own clarification questions. -- Write a plan file when returning `needs_clarification` or `blocked`. -- Implement any task in the plan. -- Modify application code or tests. -- Modify any file under `context/` outside `context/plans/`. Plan the context - repair instead of performing it. -- Mark any task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Author a validation, cleanup, or context-verification task. `/validate` owns - that phase. -- Return `plan_ready` for a plan with no incomplete task. -- Create a Git commit. -- Author more than one plan. - -## Completion - -The skill is complete after: - -- One plan target was resolved, or resolution failed and was reported. -- The plan file was written, or no file was written because the result is - `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/config/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/config/.claude/skills/sce-plan-authoring/references/plan-summary.md b/config/.claude/skills/sce-plan-authoring/references/plan-summary.md deleted file mode 100644 index 0261808d..00000000 --- a/config/.claude/skills/sce-plan-authoring/references/plan-summary.md +++ /dev/null @@ -1,94 +0,0 @@ -# SCE Plan Summary - -The user-facing summary shown after a plan is written. The invoking workflow -renders it from the `plan_ready` result, immediately before the continuation -block. - -This is chat output, not a file. Nothing here is written to the plan. - -## Layout - -``` -# Plan: {plan.name} - -Path: {plan.path} - -## Summary: -{plan summary} - -## Tasks: -1. {task.id} — {task.title} -2. {task.id} — {task.title} - -## Assumptions: -- {assumption} - -## Open questions: -- {open question} -``` - -## Field mapping - -Every value comes from the `plan_ready` result. Render nothing the result does -not carry. - -- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. - Render nothing extra when it is `created`. -- `Path:` — `plan.path`, exactly as returned, so it stays runnable. -- `Summary:` — `summary`, as prose. This is the only place the reader learns - what the plan actually does, so never omit it and never replace it with a - restatement of the task titles. -- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append - ` (done)` to any task whose `status` is `done`. -- `Assumptions:` — one line per entry in `assumptions`. -- `Open questions:` — one line per entry in `open_questions`. - -## Empty sections - -Never drop a section heading. An absent section reads as an oversight; an -explicit `None.` confirms nothing is pending. - -When `assumptions` is empty: - -``` -## Assumptions: -- None. -``` - -When `open_questions` is absent: - -``` -## Open questions: -- None. -``` - -## Rules - -- Render the sections in the order above. -- Keep task titles as authored. Do not reword, expand, or re-scope them. -- Do not restate goals, boundaries, done checks, or verification notes. The plan - file owns task detail; this summary orients the reader. -- Do not print the raw result, and do not wrap the summary in a code fence. -- Do not add commentary, recommendations, or a next step. The continuation block - that follows owns the handoff. - -## Example - -``` -# Plan: red-sce-banner - -Path: context/plans/red-sce-banner.md - -## Summary: -Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. - -## Tasks: -1. T01 — Render the SCE banner in red - -## Assumptions: -- "SCE letters" refers to the ASCII-art banner in top-level help. -- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. - -## Open questions: -- None. -``` diff --git a/config/.claude/skills/sce-plan-authoring/references/plan-template.md b/config/.claude/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/config/.claude/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/config/.claude/skills/sce-plan-context-sync/SKILL.md b/config/.claude/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index 96127523..00000000 --- a/config/.claude/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. -compatibility: claude ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.claude/skills/sce-plan-context-sync/references/sync-report.md b/config/.claude/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/config/.claude/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/config/.claude/skills/sce-plan-review/SKILL.md b/config/.claude/skills/sce-plan-review/SKILL.md deleted file mode 100644 index a55fee1d..00000000 --- a/config/.claude/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. -compatibility: claude ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -`references/readiness-contract.yaml` - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was - returned. diff --git a/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml b/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/config/.claude/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/config/.claude/skills/sce-task-context-sync/SKILL.md b/config/.claude/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index 437585c2..00000000 --- a/config/.claude/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. -compatibility: claude ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.claude/skills/sce-task-context-sync/references/sync-report.md b/config/.claude/skills/sce-task-context-sync/references/sync-report.md deleted file mode 100644 index 7d5acb94..00000000 --- a/config/.claude/skills/sce-task-context-sync/references/sync-report.md +++ /dev/null @@ -1,133 +0,0 @@ -# Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input execution status is always `complete` and does not need to be repeated -as a separate workflow state. - -## Synced variant - -# Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against implementation and execution evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** none - -{Explain why the completed implementation did not introduce durable, -non-obvious repository knowledge requiring an update.} - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with implementation and execution evidence.} - ---- - -## Blocked variant - -# Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which context synchronization should run -again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Omit **Feature existence** only when the task implemented no feature. -- Describe durable truth, not implementation-session chronology. -- Keep evidence concise and factual. -- Do not claim final validation passed. -- Do not determine whether the plan is complete. -- Do not recommend a next implementation task. diff --git a/config/.claude/skills/sce-task-execution/SKILL.md b/config/.claude/skills/sce-task-execution/SKILL.md deleted file mode 100644 index da53bb98..00000000 --- a/config/.claude/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,247 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. -compatibility: claude ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal YAML result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -`references/execution-contract.yaml` - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. -- Relevant files and context. -- Review assumptions. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task has not materially changed since review. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return YAML, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by `references/execution-contract.yaml`. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return YAML - -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` - was returned. diff --git a/config/.claude/skills/sce-task-execution/references/execution-contract.yaml b/config/.claude/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/config/.claude/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.claude/skills/sce-task-execution/references/implementation-gate.md b/config/.claude/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index d4ad836c..00000000 --- a/config/.claude/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,69 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a YAML result. This -file is the only authority for the gate's content and order. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/config/.claude/skills/sce-validation/SKILL.md b/config/.claude/skills/sce-validation/SKILL.md deleted file mode 100644 index ddb04f99..00000000 --- a/config/.claude/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. -compatibility: claude ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -`references/validation-result.md` - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was - returned. diff --git a/config/.claude/skills/sce-validation/references/validation-report.md b/config/.claude/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/config/.claude/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/config/.claude/skills/sce-validation/references/validation-result.md b/config/.claude/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/config/.claude/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. diff --git a/config/.opencode/agent/Shared Context Code.md b/config/.opencode/agent/Shared Context Code.md deleted file mode 100644 index c88395a2..00000000 --- a/config/.opencode/agent/Shared Context Code.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: "Shared Context Code" -description: Executes one approved SCE task, validates behavior, and syncs context. -temperature: 0.1 -color: "#059669" -permission: - default: ask - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: ask - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: ask - skill: - "*": ask - "sce-plan-review": allow - "sce-task-execution": allow - "sce-task-context-sync": allow - "sce-validation": allow - "sce-plan-context-sync": allow ---- - -Route implementation work through `/next-task` and final plan validation through `/validate`. diff --git a/config/.opencode/agent/Shared Context Plan.md b/config/.opencode/agent/Shared Context Plan.md deleted file mode 100644 index 23425736..00000000 --- a/config/.opencode/agent/Shared Context Plan.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: "Shared Context Plan" -description: Plans a change into atomic tasks in context/plans without touching application code. -temperature: 0.1 -color: "#2563eb" -permission: - default: ask - read: allow - edit: allow - glob: allow - grep: allow - list: allow - bash: allow - task: allow - external_directory: ask - todowrite: allow - todoread: allow - question: allow - webfetch: allow - websearch: allow - codesearch: allow - lsp: allow - doom_loop: ask - skill: - "*": ask - "sce-context-load": allow - "sce-plan-authoring": allow ---- - -Route plan creation and revision through `/change-to-plan`. diff --git a/config/.opencode/command/change-to-plan.md b/config/.opencode/command/change-to-plan.md deleted file mode 100644 index 27cc07a2..00000000 --- a/config/.opencode/command/change-to-plan.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" -agent: "Shared Context Plan" -entry-skill: "sce-context-load" -skills: - - "sce-context-load" - - "sce-plan-authoring" ---- - -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> Continue to the next step. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> Continue to the next step. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.opencode/command/next-task.md b/config/.opencode/command/next-task.md deleted file mode 100644 index 9c2ff4e3..00000000 --- a/config/.opencode/command/next-task.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" -argument-hint: " [T0X] [approved]" -agent: "Shared Context Code" -entry-skill: "sce-plan-review" -skills: - - "sce-plan-review" - - "sce-task-execution" - - "sce-task-context-sync" ---- - -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> Pass the complete readiness result to `sce-task-execution`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> continue to the next step. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. diff --git a/config/.opencode/command/validate.md b/config/.opencode/command/validate.md deleted file mode 100644 index 4b95c2ab..00000000 --- a/config/.opencode/command/validate.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" -argument-hint: "" -agent: "Shared Context Code" -entry-skill: "sce-validation" -skills: - - "sce-validation" - - "sce-plan-context-sync" ---- - -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. diff --git a/config/.opencode/lib/bash-policy-presets.json b/config/.opencode/lib/bash-policy-presets.json deleted file mode 100644 index 88afd047..00000000 --- a/config/.opencode/lib/bash-policy-presets.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "schema_version": 1, - "presets": [ - { - "id": "forbid-git-all", - "match": { - "argv_prefixes": [ - [ - "git" - ] - ] - }, - "message": "This repository blocks `git` via SCE bash-tool policy. Explain to user that they should run `git` commands themselves." - }, - { - "id": "forbid-git-commit", - "match": { - "argv_prefixes": [ - [ - "git", - "add" - ], - [ - "git", - "commit" - ], - [ - "git", - "push" - ] - ] - }, - "message": "This repository blocks direct `git add`, `git commit`, and `git push`. Explain to user that they should run `git` commands themselves." - }, - { - "id": "use-pnpm-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `pnpm` over `npm`. Use `pnpm` instead." - }, - { - "id": "use-bun-over-npm", - "match": { - "argv_prefixes": [ - [ - "npm" - ] - ] - }, - "message": "This repository prefers `bun` over `npm`. Use `bun` instead." - }, - { - "id": "use-nix-flake-over-cargo", - "match": { - "argv_prefixes": [ - [ - "cargo" - ] - ] - }, - "message": "This repository prefers Nix flake entrypoints over direct `cargo` commands. Run Cargo through the documented `nix develop` / flake workflows instead." - } - ], - "mutually_exclusive": [ - [ - "use-pnpm-over-npm", - "use-bun-over-npm" - ] - ], - "redundancy_warnings": [ - { - "if_enabled": [ - "forbid-git-all", - "forbid-git-commit" - ], - "warning": "Preset 'forbid-git-commit' is redundant when 'forbid-git-all' is also enabled." - } - ] -} diff --git a/config/.opencode/opencode.json b/config/.opencode/opencode.json deleted file mode 100644 index dbd5d890..00000000 --- a/config/.opencode/opencode.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "plugin": [ - "./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts" - ] -} \ No newline at end of file diff --git a/config/.opencode/plugins/sce-agent-trace.ts b/config/.opencode/plugins/sce-agent-trace.ts deleted file mode 100644 index 980ceb06..00000000 --- a/config/.opencode/plugins/sce-agent-trace.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { spawn } from "node:child_process"; -import type { Hooks, Plugin } from "@opencode-ai/plugin"; - -type OpenCodeEvent = Parameters>[0]["event"]; - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -const REQUIRED_EVENTS: Set = new Set([ - "message.updated", - "message.part.updated", - "session.created", - "session.updated", -]); - -const ALL_CAPTURED_EVENTS = REQUIRED_EVENTS; - -type TraceInput = { - event?: OpenCodeEvent; -}; - -type DiffTracePayload = { - sessionID: string; - diff: string; - time: number; - model_id: string; -}; - -type ConversationTraceMessageUpdatedItem = { - type: "message"; - session_id: string; - message_id: string; - role: EventMessageUpdated["properties"]["info"]["role"]; - generated_at_unix_ms: number; -}; - -type ConversationTraceMessagePartUpdatedItem = { - type: "message.part"; - session_id: string; - message_id: string; - part_type: "text" | "reasoning" | "patch" | "question"; - text: unknown; - generated_at_unix_ms: number; -}; - -type ConversationTraceItem = - | ConversationTraceMessageUpdatedItem - | ConversationTraceMessagePartUpdatedItem; - -type ConversationTracePayload = { - payloads: ConversationTraceItem[]; -}; - -type QuestionToolAnswer = { - question: string; - answer: string; -}; - -const QUESTION_TOOL_ANSWER_SEPARATOR = ", "; - -type EventMessageUpdated = Extract< - NonNullable, - { type: "message.updated" } ->; - -type EventMessagePartUpdated = Extract< - NonNullable, - { type: "message.part.updated" } ->; - -type EventMessagePart = EventMessagePartUpdated["properties"]["part"]; -type EventMessageToolPart = Extract; -type EventAllowedPart = - | Extract - | Extract; - -function extractDiffEntries( - eventInfo: EventMessageUpdated["properties"]["info"], -) { - if (typeof eventInfo.summary === "object") { - return eventInfo.summary.diffs; - } - return undefined; -} - -function extractDiffTracePayload( - event: EventMessageUpdated, -): DiffTracePayload | undefined { - const eventInfo = event.properties.info; - // Only capture user messages (filter out assistant, system, etc.) - if (eventInfo.role !== "user") { - return undefined; - } - - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patches: string[] = []; - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - patches.push(entry.patch); - } - } - - if (patches.length === 0) { - return undefined; - } - - return { - sessionID: eventInfo.sessionID, - diff: patches.join("\n"), - time: Date.now(), - model_id: `${eventInfo.model.providerID}/${eventInfo.model.modelID}`, - }; -} - -function shouldCaptureEvent(eventType: OpenCodeEvent["type"]): boolean { - return ALL_CAPTURED_EVENTS.has(eventType); -} - -function extractQuestionToolAnswers( - eventPart: EventMessageToolPart, -): QuestionToolAnswer[] | undefined { - const state = eventPart.state; - - if (state.status !== "completed") { - return undefined; - } - - const questions = - "questions" in state.input && Array.isArray(state.input.questions) - ? state.input.questions - : []; - const answers = - "answers" in state.metadata && Array.isArray(state.metadata.answers) - ? state.metadata.answers - : []; - - if (questions.length === 0 || questions.length !== answers.length) { - return undefined; - } - - const result: QuestionToolAnswer[] = []; - - questions.forEach((q, index) => { - const question = - "question" in q && typeof q.question === "string" ? q.question : ""; - if (question) { - const answer = Array.isArray(answers[index]) ? answers[index] : []; - result.push({ - question, - answer: answer.join(QUESTION_TOOL_ANSWER_SEPARATOR), - }); - } - }); - - return result; -} - -function buildConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload { - const eventInfo = event.properties.info; - - return { - payloads: [ - { - type: "message", - session_id: eventInfo.sessionID, - message_id: eventInfo.id, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -export function buildMessagePartConversationTracePayload( - eventPart: EventAllowedPart, -): ConversationTracePayload { - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: eventPart.type, - text: "text" in eventPart ? eventPart.text : "", - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildQuestionToolConversationTracePayload( - eventPart: EventMessageToolPart, -): ConversationTracePayload | undefined { - const pairedAnswers = extractQuestionToolAnswers(eventPart); - - if (pairedAnswers === undefined) { - return undefined; - } - - return { - payloads: [ - { - type: "message.part", - session_id: eventPart.sessionID, - message_id: eventPart.messageID, - part_type: "question", - text: JSON.stringify(pairedAnswers), - generated_at_unix_ms: Date.now(), - }, - ], - }; -} - -function buildPatchConversationTracePayload( - event: EventMessageUpdated, -): ConversationTracePayload | undefined { - const eventInfo = event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - - if (!diffEntries || diffEntries.length === 0) { - return undefined; - } - - const patchMessageId = `${eventInfo.id}-patch`; - const payloads: ConversationTraceItem[] = []; - - payloads.push({ - type: "message", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - role: eventInfo.role, - generated_at_unix_ms: Date.now(), - }); - - for (const entry of diffEntries) { - if ("patch" in entry && typeof entry.patch === "string") { - payloads.push({ - type: "message.part", - session_id: eventInfo.sessionID, - message_id: patchMessageId, - part_type: "patch", - text: entry.patch, - generated_at_unix_ms: Date.now(), - }); - } - } - - return { payloads }; -} - -export async function recordConversationTrace( - repoRoot: string, - event: EventMessageUpdated | EventMessagePartUpdated, -): Promise { - if ( - event.type === "message.part.updated" && - event.properties.part.type === "tool" && - event.properties.part.tool === "question" - ) { - const questionToolPayload = buildQuestionToolConversationTracePayload( - event.properties.part, - ); - if (questionToolPayload !== undefined) { - await runConversationTraceHook(repoRoot, questionToolPayload); - return; - } - } - - if ( - event.type === "message.part.updated" && - (event.properties.part.type === "reasoning" || - event.properties.part.type === "text") && - event.properties.part.text - ) { - await runConversationTraceHook( - repoRoot, - buildMessagePartConversationTracePayload(event.properties.part), - ); - return; - } - - if (event.type === "message.updated") { - const patchPayload = buildPatchConversationTracePayload(event); - - if (patchPayload !== undefined) { - await runConversationTraceHook(repoRoot, patchPayload); - return; - } - - await runConversationTraceHook( - repoRoot, - buildConversationTracePayload(event), - ); - } -} - -async function buildTrace( - repoRoot: string, - event: EventMessageUpdated, - clientVersion: string | null, -): Promise { - const diffTracePayload = extractDiffTracePayload(event); - - if (diffTracePayload === undefined) { - return; - } - - await runDiffTraceHook(repoRoot, { - ...diffTracePayload, - tool_name: "opencode", - tool_version: clientVersion, - }); -} - -async function runDiffTraceHook( - repoRoot: string, - payload: DiffTracePayload & { - tool_name: string; - tool_version: string | null; - }, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "diff-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -async function runConversationTraceHook( - repoRoot: string, - payload: ConversationTracePayload, -): Promise { - await new Promise((resolve) => { - const child = spawn("sce", ["hooks", "conversation-trace"], { - cwd: repoRoot, - // Fail-open: stderr is ignored so that sce intake errors - // (connection refused, timeout, etc.) do not leak into the - // OpenCode TUI. Resolve unconditionally on any outcome. - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -export const SceAgentTracePlugin: Plugin = async ({ directory, worktree }) => { - const repoRoot = worktree ?? directory ?? process.cwd(); - const clientVersionsBySessionId: Map = new Map(); - const processedDiffsMessageIds: Set = new Set(); - - return { - event: async (input) => { - if (!shouldCaptureEvent(input.event.type)) { - return; - } - - if ( - input.event.type === "session.created" || - input.event.type === "session.updated" - ) { - clientVersionsBySessionId.set( - input.event.properties.info.id, - input.event.properties.info.version, - ); - } - - if (input.event.type === "message.updated") { - const eventInfo = input.event.properties.info; - const diffEntries = extractDiffEntries(eventInfo); - const hasDiffs = diffEntries !== undefined && diffEntries.length > 0; - - if (hasDiffs) { - const dedupKey = `${eventInfo.sessionID}:${eventInfo.id}`; - if (processedDiffsMessageIds.has(dedupKey)) { - return; - } - processedDiffsMessageIds.add(dedupKey); - } - - const clientVersion = - clientVersionsBySessionId.get( - input.event.properties.info.sessionID, - ) || null; - await recordConversationTrace(repoRoot, input.event); - await buildTrace(repoRoot, input.event, clientVersion); - } - - if (input.event.type === "message.part.updated") { - await recordConversationTrace(repoRoot, input.event); - } - }, - }; -}; diff --git a/config/.opencode/plugins/sce-bash-policy.ts b/config/.opencode/plugins/sce-bash-policy.ts deleted file mode 100644 index 0b2b8d9c..00000000 --- a/config/.opencode/plugins/sce-bash-policy.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { spawnSync } from "node:child_process"; -import type { Plugin } from "@opencode-ai/plugin"; - -interface JsonPolicyResult { - status: string; - decision: string; - command: string; - normalized_argv?: string[]; - reason?: string; - policy_id?: string; -} - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -/** - * Evaluate a bash command against SCE bash-tool policy by delegating to the - * Rust `sce policy bash` command. Returns the parsed JSON result, or null if - * the policy check could not be performed (fail-open). - */ -function evaluateBashCommandPolicy(command: string): JsonPolicyResult | null { - try { - const result = spawnSync( - "sce", - ["policy", "bash", "--input", "normalized", "--output", "json"], - { - input: JSON.stringify({ command }), - encoding: "utf8", - timeout: 10_000, - }, - ); - - if (result.error) { - if ((result.error as NodeJS.ErrnoException).code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - return null; - } - - if (result.status !== 0) { - return null; - } - - const stdout = result.stdout?.trim(); - if (!stdout) { - return null; - } - - const parsed: JsonPolicyResult = JSON.parse(stdout); - return parsed; - } catch { - return null; - } -} - -export const SceBashPolicyPlugin: Plugin = async () => { - return { - "tool.execute.before": async (input, output) => { - if (input.tool !== "bash") { - return; - } - - const args = output?.args; - if (args === undefined || args === null) { - return; - } - - const command = (args as { command?: unknown }).command; - if (typeof command !== "string" || command.length === 0) { - return; - } - - const policyResult = evaluateBashCommandPolicy(command); - if (!policyResult) { - // Fail open: if the policy check cannot be performed, allow the command. - return; - } - - if (policyResult.decision === "deny" && policyResult.reason) { - throw new Error(policyResult.reason); - } - }, - }; -}; diff --git a/config/.opencode/skills/sce-context-load/SKILL.md b/config/.opencode/skills/sce-context-load/SKILL.md deleted file mode 100644 index 5e28b0ee..00000000 --- a/config/.opencode/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. -compatibility: opencode ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -`references/context-brief.yaml` - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.opencode/skills/sce-context-load/references/context-brief.yaml b/config/.opencode/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/config/.opencode/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/config/.opencode/skills/sce-plan-authoring/SKILL.md b/config/.opencode/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index fdc754a9..00000000 --- a/config/.opencode/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -name: sce-plan-authoring -description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. -compatibility: opencode ---- - -# SCE Plan Authoring - -## Purpose - -Turn exactly one change request into `context/plans/{plan_name}.md` without -inventing material requirements. - -This skill owns: - -- Resolving whether the request targets a new or an existing plan. -- Judging whether the change is worth making, and recording the doubt when it - is not clear that it is. -- Deciding whether the request can be planned safely. -- Normalizing the change summary, acceptance criteria, constraints, and - non-goals. -- Slicing the work into atomic implementation tasks. -- Writing the plan file. -- Returning one structured authoring result. - -Use the document format defined in: - -`references/plan-template.md` - -Return a result matching: - -`references/authoring-contract.yaml` - -The invoking workflow renders that result as the summary defined in: - -`references/plan-summary.md` - -## Input - -The invoking workflow provides: - -- One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. - -The change request may name a plan, describe a change to an existing plan, or -describe entirely new work. Resolving which applies is this skill's -responsibility. - -The context brief is the durable memory this plan starts from. Treat its -`key_facts` as recorded current state, its `gaps` as areas with no durable -context, and its `drift` as context the code has already outrun. - -When no brief is supplied, load the context named by the change request before -authoring, and follow the selection discipline in *Inspect relevant context*. - -Answers the user gave to earlier clarification questions arrive as part of the -change request. Incorporate them into the plan. - -A revision of a plan authored earlier in the session also arrives as the change -request, and it is usually terse: a task boundary the user disagrees with, an -ordering they want changed, work they want added or dropped. Read it against the -existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the -plan already carries; ask only when the revision itself is genuinely undecidable. - -## Workflow - -### 1. Resolve the plan target - -Determine whether the request targets a new plan or an existing plan in -`context/plans/`. - -When it targets an existing plan, read that plan before authoring. Preserve its -completed tasks, their recorded evidence, its structure, and its terminology. - -When multiple existing plans match and none can be selected safely, return -`blocked` with the matching candidates. - -When the request targets a new plan, derive `plan_name` as a short kebab-case -slug of the change, and confirm it does not collide with an existing plan. - -Resolve exactly one plan target per invocation. - -### 2. Challenge the change - -Before planning how to build the change, work out whether it is worth building. -A plan is a commitment of someone's time; authoring one for work that should not -happen is worse than authoring none. - -Interrogate the request: - -- What breaks, or stays broken, if this is never built? If the answer is - nothing concrete, say so. -- What problem is it actually solving, as opposed to what it proposes to do? A - request that names only a solution has not stated a problem. -- Does the repository already do this, or most of it? The brief's `key_facts` - are the first place to check. -- Is there a materially smaller version that gets most of the value? Name it. -- What does this cost beyond the tasks: new dependency, new concept in the - glossary, a boundary crossed, a surface that now needs maintaining forever? -- Does the stated justification survive contact with the code, or does the code - show the premise is already false? - -Doubt that survives this is not an implementation detail to be tidied away. It -belongs in the plan's `Open questions` and in `open_questions`, in the plain -words you would use to a colleague. "Is this worth doing at all, given X?" is a -legitimate open question. So is "this looks like it duplicates Y". - -Weigh honestly in both directions. A request that is obviously worth building -gets no manufactured doubt: inventing questions to look rigorous is its own -failure, and it teaches the user to ignore the section. Most changes are fine. -Say nothing when there is nothing to say. - -Keep going regardless. Skepticism shapes the plan and the open questions; it -does not withhold the plan. The only value judgment that stops authoring is -`no_actionable_work`, when the change is already implemented. - -### 3. Run the clarification gate - -Before writing or updating any plan file, check the request for critical -unresolved detail: - -- Scope boundaries and out-of-scope items. -- Acceptance criteria and the checks that prove them. -- Constraints and non-goals. -- Dependency choices, including new libraries or services, versions, and the - integration approach. -- Domain ambiguity, including unclear business rules, terminology, or ownership. -- Architecture concerns, including patterns, interfaces, data flow, migration - strategy, and risk tradeoffs. -- Task ordering assumptions and prerequisite sequencing. - -Return `needs_clarification` with one to three targeted questions when any of -these would materially change the plan. Write no plan file in that case. - -Use repository conventions for ordinary local choices. Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change scope, acceptance criteria, or task ordering. - -Record those choices under `assumptions`. - -Do not silently invent missing requirements. When the user has explicitly -allowed assumptions, record them in the plan's `Assumptions` section instead of -asking. - -A justification that does not survive inspection is itself a critical unresolved -detail. "For consistency", "to make it cleaner", "we will need it later" name no -outcome and prove nothing; ask what the change is actually for before planning -around it. Do not treat confident phrasing as evidence. - -### 4. Inspect relevant context - -Start from the context brief. Read code only where the brief leaves the change -underspecified: - -- Existing behavior the change affects. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests and available verification commands. -- Decisions or specifications connected to the change. - -Where the brief reports `drift`, the code is the source of truth. Plan against -the code, and schedule the context repair as part of the change when it falls -inside scope. - -Where the brief reports `gaps`, the plan may need to establish durable context -the repository does not yet have. - -Do not explore the entire repository by default. - -### 5. Author the acceptance criteria - -State how the finished plan is proven, before slicing tasks. - -Each criterion describes observable behavior of the finished system and names -the check that proves it. Record repository-wide checks once under -`Full validation`, and the durable context the change must be reflected in -under `Context sync`. - -`/validate` runs this section after the last task completes. It is the only -place a plan says how it is validated. - -### 6. Author the task stack - -Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. - -Every executable task must be completable and landable as one coherent commit. -Split any task that would require multiple independent commits. Convert broad -wrappers such as `polish` or `finalize` into specific outcomes with concrete -acceptance checks. - -Order tasks so each one's declared dependencies precede it. - -The last task is an ordinary implementation task. Do not author a trailing -validation-and-cleanup task, or any task whose only purpose is running the full -check suite, verifying durable context, or removing scaffolding. - -Confirm every acceptance criterion is satisfied by at least one task. When one -is not, the task stack is incomplete. - -A finished stack always leaves at least one incomplete task, so the invoking -workflow can always hand off to `/next-task`. When the request resolves to a -plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category -`no_actionable_work` instead of writing the plan. - -### 7. Write the plan - -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. - -When updating an existing plan, keep completed tasks and their evidence intact, -and append or renumber new tasks without disturbing recorded history. - -### 8. Return the result - -Return exactly one structured result: - -- `plan_ready` -- `needs_clarification` -- `blocked` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Tone - -Every question and open question this skill writes is read by the user. Write -them the way a senior engineer talks in review: direct, specific, and unbothered -by the possibility of being unwelcome. - -- Ask about the thing that actually worries you, not a safer neighbouring thing. - A question you would not bother asking a colleague is not worth the user's - attention either. -- State a doubt as a doubt. "I do not think this is worth the two tasks it - costs, because X" is useful. "It may be worth considering whether this aligns - with broader goals" is noise. -- Name the alternative you have in mind. A challenge with no proposal behind it - is just friction. -- Do not open with praise, do not close with reassurance, and do not apologize - for asking. Do not pad a doubt with hedges to make it land more gently. -- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not - restate the same doubt in three shapes to give it more weight. -- Being disagreeable is not the goal. Being easy to agree with is the failure - mode. A plan the user waves through without reading has cost them nothing and - bought them nothing. - -When the user overrules a doubt, record it and move on. Do not relitigate a -decision the user has made, and do not smuggle the objection back in as a -constraint, a non-goal, or a task. - -## Boundaries - -Do not: - -- Ask the user questions directly. Return `needs_clarification` and let the - invoking workflow present the questions. -- Answer your own clarification questions. -- Write a plan file when returning `needs_clarification` or `blocked`. -- Implement any task in the plan. -- Modify application code or tests. -- Modify any file under `context/` outside `context/plans/`. Plan the context - repair instead of performing it. -- Mark any task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Author a validation, cleanup, or context-verification task. `/validate` owns - that phase. -- Return `plan_ready` for a plan with no incomplete task. -- Create a Git commit. -- Author more than one plan. - -## Completion - -The skill is complete after: - -- One plan target was resolved, or resolution failed and was reported. -- The plan file was written, or no file was written because the result is - `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/config/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md b/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md deleted file mode 100644 index 0261808d..00000000 --- a/config/.opencode/skills/sce-plan-authoring/references/plan-summary.md +++ /dev/null @@ -1,94 +0,0 @@ -# SCE Plan Summary - -The user-facing summary shown after a plan is written. The invoking workflow -renders it from the `plan_ready` result, immediately before the continuation -block. - -This is chat output, not a file. Nothing here is written to the plan. - -## Layout - -``` -# Plan: {plan.name} - -Path: {plan.path} - -## Summary: -{plan summary} - -## Tasks: -1. {task.id} — {task.title} -2. {task.id} — {task.title} - -## Assumptions: -- {assumption} - -## Open questions: -- {open question} -``` - -## Field mapping - -Every value comes from the `plan_ready` result. Render nothing the result does -not carry. - -- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. - Render nothing extra when it is `created`. -- `Path:` — `plan.path`, exactly as returned, so it stays runnable. -- `Summary:` — `summary`, as prose. This is the only place the reader learns - what the plan actually does, so never omit it and never replace it with a - restatement of the task titles. -- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append - ` (done)` to any task whose `status` is `done`. -- `Assumptions:` — one line per entry in `assumptions`. -- `Open questions:` — one line per entry in `open_questions`. - -## Empty sections - -Never drop a section heading. An absent section reads as an oversight; an -explicit `None.` confirms nothing is pending. - -When `assumptions` is empty: - -``` -## Assumptions: -- None. -``` - -When `open_questions` is absent: - -``` -## Open questions: -- None. -``` - -## Rules - -- Render the sections in the order above. -- Keep task titles as authored. Do not reword, expand, or re-scope them. -- Do not restate goals, boundaries, done checks, or verification notes. The plan - file owns task detail; this summary orients the reader. -- Do not print the raw result, and do not wrap the summary in a code fence. -- Do not add commentary, recommendations, or a next step. The continuation block - that follows owns the handoff. - -## Example - -``` -# Plan: red-sce-banner - -Path: context/plans/red-sce-banner.md - -## Summary: -Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. - -## Tasks: -1. T01 — Render the SCE banner in red - -## Assumptions: -- "SCE letters" refers to the ASCII-art banner in top-level help. -- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. - -## Open questions: -- None. -``` diff --git a/config/.opencode/skills/sce-plan-authoring/references/plan-template.md b/config/.opencode/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/config/.opencode/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/config/.opencode/skills/sce-plan-context-sync/SKILL.md b/config/.opencode/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index a59c57f8..00000000 --- a/config/.opencode/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. -compatibility: opencode ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md b/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/config/.opencode/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/config/.opencode/skills/sce-plan-review/SKILL.md b/config/.opencode/skills/sce-plan-review/SKILL.md deleted file mode 100644 index cb98f485..00000000 --- a/config/.opencode/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. -compatibility: opencode ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -`references/readiness-contract.yaml` - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was - returned. diff --git a/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml b/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/config/.opencode/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/config/.opencode/skills/sce-task-context-sync/SKILL.md b/config/.opencode/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index 3b3b5d80..00000000 --- a/config/.opencode/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. -compatibility: opencode ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.opencode/skills/sce-task-context-sync/references/sync-report.md b/config/.opencode/skills/sce-task-context-sync/references/sync-report.md deleted file mode 100644 index 7d5acb94..00000000 --- a/config/.opencode/skills/sce-task-context-sync/references/sync-report.md +++ /dev/null @@ -1,133 +0,0 @@ -# Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input execution status is always `complete` and does not need to be repeated -as a separate workflow state. - -## Synced variant - -# Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against implementation and execution evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** none - -{Explain why the completed implementation did not introduce durable, -non-obvious repository knowledge requiring an update.} - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with implementation and execution evidence.} - ---- - -## Blocked variant - -# Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which context synchronization should run -again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Omit **Feature existence** only when the task implemented no feature. -- Describe durable truth, not implementation-session chronology. -- Keep evidence concise and factual. -- Do not claim final validation passed. -- Do not determine whether the plan is complete. -- Do not recommend a next implementation task. diff --git a/config/.opencode/skills/sce-task-execution/SKILL.md b/config/.opencode/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 267f608c..00000000 --- a/config/.opencode/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,247 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. -compatibility: opencode ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal YAML result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -`references/execution-contract.yaml` - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. -- Relevant files and context. -- Review assumptions. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task has not materially changed since review. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return YAML, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by `references/execution-contract.yaml`. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return YAML - -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` - was returned. diff --git a/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml b/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/config/.opencode/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.opencode/skills/sce-task-execution/references/implementation-gate.md b/config/.opencode/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index d4ad836c..00000000 --- a/config/.opencode/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,69 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a YAML result. This -file is the only authority for the gate's content and order. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/config/.opencode/skills/sce-validation/SKILL.md b/config/.opencode/skills/sce-validation/SKILL.md deleted file mode 100644 index a2dc559d..00000000 --- a/config/.opencode/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. -compatibility: opencode ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -`references/validation-result.md` - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was - returned. diff --git a/config/.opencode/skills/sce-validation/references/validation-report.md b/config/.opencode/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/config/.opencode/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/config/.opencode/skills/sce-validation/references/validation-result.md b/config/.opencode/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/config/.opencode/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. diff --git a/config/.pi/extensions/sce/index.ts b/config/.pi/extensions/sce/index.ts deleted file mode 100644 index 25770ff8..00000000 --- a/config/.pi/extensions/sce/index.ts +++ /dev/null @@ -1,455 +0,0 @@ -import { spawn, spawnSync } from "node:child_process"; -import { randomUUID } from "node:crypto"; -import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; -import { createRequire } from "node:module"; -import { tmpdir } from "node:os"; -import { - dirname, - isAbsolute, - join, - relative, - resolve as resolvePath, -} from "node:path"; -import { - type ExtensionAPI, - isToolCallEventType, -} from "@earendil-works/pi-coding-agent"; - -interface JsonPolicyResult { - status: string; - decision: string; - command: string; - normalized_argv?: string[]; - reason?: string; - policy_id?: string; -} - -const SCE_INSTALL_URL = - "https://sce.crocoder.dev/docs/getting-started#install-cli"; - -type ConversationTraceMessageItem = { - type: "message"; - session_id: string; - message_id: string; - role: "user" | "assistant"; - generated_at_unix_ms: number; -}; - -type ConversationTraceMessagePartItem = { - type: "message.part"; - session_id: string; - message_id: string; - part_type: "text" | "reasoning" | "patch"; - text: string; - generated_at_unix_ms: number; -}; - -type ConversationTraceItem = - | ConversationTraceMessageItem - | ConversationTraceMessagePartItem; - -type ConversationTracePayload = { - payloads: ConversationTraceItem[]; -}; - -type DiffTracePayload = { - sessionID: string; - diff: string; - time: number; - model_id: string | null; - tool_name: "pi"; - tool_version: string | null; -}; - -type PendingFileMutation = { - absolutePath: string; - diffLabel: string; - before: string | undefined; -}; - -/** - * Evaluate a bash command against SCE bash-tool policy by delegating to the - * Rust `sce policy bash` command. Returns the parsed JSON result, or null if - * the policy check could not be performed (fail-open). - */ -function evaluateBashCommandPolicy(command: string): JsonPolicyResult | null { - try { - const result = spawnSync( - "sce", - ["policy", "bash", "--input", "normalized", "--output", "json"], - { - input: JSON.stringify({ command }), - encoding: "utf8", - timeout: 10_000, - }, - ); - - if (result.error) { - if ((result.error as NodeJS.ErrnoException).code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - return null; - } - - if (result.status !== 0) { - return null; - } - - const stdout = result.stdout?.trim(); - if (!stdout) { - return null; - } - - const parsed: JsonPolicyResult = JSON.parse(stdout); - return parsed; - } catch { - return null; - } -} - -/** - * Send a conversation-trace payload to `sce hooks conversation-trace`, - * fire-and-forget. Fail-open: stderr is ignored so that sce intake errors do - * not leak into the Pi TUI, and the returned promise never rejects. - */ -function runConversationTraceHook( - cwd: string, - payload: ConversationTracePayload, -): Promise { - return new Promise((resolve) => { - const child = spawn("sce", ["hooks", "conversation-trace"], { - cwd, - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -type MessageContentBlock = { - type: string; - text?: unknown; - thinking?: unknown; -}; - -function extractMessageParts( - content: string | readonly MessageContentBlock[], -): Array<{ part_type: "text" | "reasoning"; text: string }> { - if (typeof content === "string") { - return content.length > 0 ? [{ part_type: "text", text: content }] : []; - } - - const parts: Array<{ part_type: "text" | "reasoning"; text: string }> = []; - for (const block of content) { - if (block.type === "text" && typeof block.text === "string" && block.text) { - parts.push({ part_type: "text", text: block.text }); - } else if ( - block.type === "thinking" && - typeof block.thinking === "string" && - block.thinking - ) { - parts.push({ part_type: "reasoning", text: block.thinking }); - } - } - return parts; -} - -function buildMessageEndConversationTracePayload( - sessionId: string, - message: { - role: string; - content: string | readonly MessageContentBlock[]; - responseId?: string; - }, -): ConversationTracePayload | undefined { - if (message.role !== "user" && message.role !== "assistant") { - return undefined; - } - - const messageId = message.responseId ?? randomUUID(); - const generatedAtUnixMs = Date.now(); - - const payloads: ConversationTraceItem[] = [ - { - type: "message", - session_id: sessionId, - message_id: messageId, - role: message.role, - generated_at_unix_ms: generatedAtUnixMs, - }, - ]; - - for (const part of extractMessageParts(message.content)) { - payloads.push({ - type: "message.part", - session_id: sessionId, - message_id: messageId, - part_type: part.part_type, - text: part.text, - generated_at_unix_ms: generatedAtUnixMs, - }); - } - - return { payloads }; -} - -/** - * Resolve the installed Pi package version for diff-trace `tool_version`. - * The package's `exports` map does not expose `package.json`, so resolve the - * package entry point and read `package.json` from the package root instead. - * Returns null when resolution fails (normalized diff traces permit it). - */ -async function resolvePiToolVersion(): Promise { - try { - const require_ = createRequire(import.meta.url); - const entryPath = require_.resolve("@earendil-works/pi-coding-agent"); - const packageJsonPath = join(dirname(entryPath), "..", "package.json"); - const parsed: { version?: unknown } = JSON.parse( - await readFile(packageJsonPath, "utf8"), - ); - return typeof parsed.version === "string" && parsed.version.length > 0 - ? parsed.version - : null; - } catch { - return null; - } -} - -/** - * Send a diff-trace payload to `sce hooks diff-trace`, fire-and-forget. - * Fail-open: stderr is ignored and the returned promise never rejects. - */ -function runDiffTraceHook( - cwd: string, - payload: DiffTracePayload, -): Promise { - return new Promise((resolve) => { - const child = spawn("sce", ["hooks", "diff-trace"], { - cwd, - stdio: ["pipe", "ignore", "ignore"], - }); - - child.on("error", (err: NodeJS.ErrnoException) => { - if (err.code === "ENOENT") { - console.warn(`sce CLI not found. Install it from ${SCE_INSTALL_URL}`); - } - resolve(); - }); - child.on("close", () => resolve()); - - child.stdin.end(`${JSON.stringify(payload)}\n`); - }); -} - -async function readFileOrUndefined(path: string): Promise { - try { - return await readFile(path, "utf8"); - } catch { - return undefined; - } -} - -function diffLabelFor(cwd: string, absolutePath: string): string { - const relPath = relative(cwd, absolutePath); - return relPath.length > 0 && !relPath.startsWith("..") && !isAbsolute(relPath) - ? relPath - : absolutePath; -} - -/** - * Rewrite temp-file path labels in git diff header lines to the repo-relative - * target path. Only header lines before the first `@@` hunk marker are - * touched so that content lines starting with `--- ` / `+++ ` are preserved. - */ -function rewriteDiffLabels( - diff: string, - label: string, - isCreate: boolean, -): string { - const lines = diff.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.startsWith("@@")) { - break; - } - if (line.startsWith("diff --git ")) { - lines[i] = `diff --git a/${label} b/${label}`; - } else if (line.startsWith("--- ")) { - lines[i] = isCreate ? "--- /dev/null" : `--- a/${label}`; - } else if (line.startsWith("+++ ")) { - lines[i] = `+++ b/${label}`; - } - } - return lines.join("\n"); -} - -/** - * Produce a unified diff between before/after contents by writing them to - * temp files and spawning `git diff --no-index --no-ext-diff` (exit status 1 - * means "files differ"). Returns undefined for no-op diffs or any failure; - * temp files are always cleaned up. - */ -async function buildUnifiedDiff( - label: string, - before: string | undefined, - after: string, -): Promise { - const tempDir = await mkdtemp(join(tmpdir(), "sce-pi-diff-")); - try { - const beforePath = join(tempDir, "before"); - const afterPath = join(tempDir, "after"); - await writeFile(beforePath, before ?? "", "utf8"); - await writeFile(afterPath, after, "utf8"); - - const result = spawnSync( - "git", - ["diff", "--no-index", "--no-ext-diff", "--", beforePath, afterPath], - { encoding: "utf8", timeout: 10_000 }, - ); - - if (result.error || result.status !== 1) { - return undefined; - } - const stdout = result.stdout; - if (!stdout) { - return undefined; - } - return rewriteDiffLabels(stdout, label, before === undefined); - } catch { - return undefined; - } finally { - await rm(tempDir, { recursive: true, force: true }).catch(() => {}); - } -} - -export default function sceExtension(pi: ExtensionAPI): void { - const pendingFileMutations = new Map(); - const piToolVersionPromise = resolvePiToolVersion(); - - pi.on("tool_call", (event) => { - if (!isToolCallEventType("bash", event)) { - return undefined; - } - - const command = event.input.command; - if (typeof command !== "string" || command.length === 0) { - return undefined; - } - - const policyResult = evaluateBashCommandPolicy(command); - if (!policyResult) { - // Fail open: if the policy check cannot be performed, allow the command. - return undefined; - } - - if (policyResult.decision === "deny" && policyResult.reason) { - return { block: true, reason: policyResult.reason }; - } - - return undefined; - }); - - pi.on("tool_call", async (event, ctx) => { - if ( - !isToolCallEventType("edit", event) && - !isToolCallEventType("write", event) - ) { - return undefined; - } - - const targetPath = event.input.path; - if (typeof targetPath !== "string" || targetPath.length === 0) { - return undefined; - } - - const absolutePath = resolvePath(ctx.cwd, targetPath); - pendingFileMutations.set(event.toolCallId, { - absolutePath, - diffLabel: diffLabelFor(ctx.cwd, absolutePath), - before: await readFileOrUndefined(absolutePath), - }); - return undefined; - }); - - pi.on("tool_result", async (event, ctx) => { - const pending = pendingFileMutations.get(event.toolCallId); - if (!pending) { - return; - } - pendingFileMutations.delete(event.toolCallId); - - if (event.isError) { - return; - } - - const after = await readFileOrUndefined(pending.absolutePath); - if (after === undefined || after === pending.before) { - return; - } - - const diff = await buildUnifiedDiff( - pending.diffLabel, - pending.before, - after, - ); - if (!diff) { - return; - } - - const sessionId = ctx.sessionManager.getSessionId(); - const generatedAtUnixMs = Date.now(); - const patchMessageId = `${event.toolCallId}-patch`; - - void runConversationTraceHook(ctx.cwd, { - payloads: [ - { - type: "message", - session_id: sessionId, - message_id: patchMessageId, - role: "assistant", - generated_at_unix_ms: generatedAtUnixMs, - }, - { - type: "message.part", - session_id: sessionId, - message_id: patchMessageId, - part_type: "patch", - text: diff, - generated_at_unix_ms: generatedAtUnixMs, - }, - ], - }); - - void runDiffTraceHook(ctx.cwd, { - sessionID: sessionId, - diff, - time: generatedAtUnixMs, - model_id: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : null, - tool_name: "pi", - tool_version: await piToolVersionPromise, - }); - }); - - pi.on("message_end", (event, ctx) => { - const message = event.message; - if (message.role !== "user" && message.role !== "assistant") { - return; - } - - const payload = buildMessageEndConversationTracePayload( - ctx.sessionManager.getSessionId(), - message, - ); - if (payload) { - void runConversationTraceHook(ctx.cwd, payload); - } - }); -} diff --git a/config/.pi/prompts/change-to-plan.md b/config/.pi/prompts/change-to-plan.md deleted file mode 100644 index 9ee4f81f..00000000 --- a/config/.pi/prompts/change-to-plan.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" -argument-hint: "" ---- - -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> Continue to the next step. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> Continue to the next step. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/config/.pi/prompts/next-task.md b/config/.pi/prompts/next-task.md deleted file mode 100644 index 6859e4d4..00000000 --- a/config/.pi/prompts/next-task.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" -argument-hint: " [T0X] [approved]" ---- - -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> Pass the complete readiness result to `sce-task-execution`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> continue to the next step. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. diff --git a/config/.pi/prompts/validate.md b/config/.pi/prompts/validate.md deleted file mode 100644 index d35fb89c..00000000 --- a/config/.pi/prompts/validate.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" -argument-hint: "" ---- - -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. diff --git a/config/.pi/skills/sce-context-load/SKILL.md b/config/.pi/skills/sce-context-load/SKILL.md deleted file mode 100644 index c944be76..00000000 --- a/config/.pi/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -`references/context-brief.yaml` - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching `references/context-brief.yaml` was returned. diff --git a/config/.pi/skills/sce-context-load/references/context-brief.yaml b/config/.pi/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/config/.pi/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/config/.pi/skills/sce-plan-authoring/SKILL.md b/config/.pi/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 946e686b..00000000 --- a/config/.pi/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,289 +0,0 @@ ---- -name: sce-plan-authoring -description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. ---- - -# SCE Plan Authoring - -## Purpose - -Turn exactly one change request into `context/plans/{plan_name}.md` without -inventing material requirements. - -This skill owns: - -- Resolving whether the request targets a new or an existing plan. -- Judging whether the change is worth making, and recording the doubt when it - is not clear that it is. -- Deciding whether the request can be planned safely. -- Normalizing the change summary, acceptance criteria, constraints, and - non-goals. -- Slicing the work into atomic implementation tasks. -- Writing the plan file. -- Returning one structured authoring result. - -Use the document format defined in: - -`references/plan-template.md` - -Return a result matching: - -`references/authoring-contract.yaml` - -The invoking workflow renders that result as the summary defined in: - -`references/plan-summary.md` - -## Input - -The invoking workflow provides: - -- One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. - -The change request may name a plan, describe a change to an existing plan, or -describe entirely new work. Resolving which applies is this skill's -responsibility. - -The context brief is the durable memory this plan starts from. Treat its -`key_facts` as recorded current state, its `gaps` as areas with no durable -context, and its `drift` as context the code has already outrun. - -When no brief is supplied, load the context named by the change request before -authoring, and follow the selection discipline in *Inspect relevant context*. - -Answers the user gave to earlier clarification questions arrive as part of the -change request. Incorporate them into the plan. - -A revision of a plan authored earlier in the session also arrives as the change -request, and it is usually terse: a task boundary the user disagrees with, an -ordering they want changed, work they want added or dropped. Read it against the -existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the -plan already carries; ask only when the revision itself is genuinely undecidable. - -## Workflow - -### 1. Resolve the plan target - -Determine whether the request targets a new plan or an existing plan in -`context/plans/`. - -When it targets an existing plan, read that plan before authoring. Preserve its -completed tasks, their recorded evidence, its structure, and its terminology. - -When multiple existing plans match and none can be selected safely, return -`blocked` with the matching candidates. - -When the request targets a new plan, derive `plan_name` as a short kebab-case -slug of the change, and confirm it does not collide with an existing plan. - -Resolve exactly one plan target per invocation. - -### 2. Challenge the change - -Before planning how to build the change, work out whether it is worth building. -A plan is a commitment of someone's time; authoring one for work that should not -happen is worse than authoring none. - -Interrogate the request: - -- What breaks, or stays broken, if this is never built? If the answer is - nothing concrete, say so. -- What problem is it actually solving, as opposed to what it proposes to do? A - request that names only a solution has not stated a problem. -- Does the repository already do this, or most of it? The brief's `key_facts` - are the first place to check. -- Is there a materially smaller version that gets most of the value? Name it. -- What does this cost beyond the tasks: new dependency, new concept in the - glossary, a boundary crossed, a surface that now needs maintaining forever? -- Does the stated justification survive contact with the code, or does the code - show the premise is already false? - -Doubt that survives this is not an implementation detail to be tidied away. It -belongs in the plan's `Open questions` and in `open_questions`, in the plain -words you would use to a colleague. "Is this worth doing at all, given X?" is a -legitimate open question. So is "this looks like it duplicates Y". - -Weigh honestly in both directions. A request that is obviously worth building -gets no manufactured doubt: inventing questions to look rigorous is its own -failure, and it teaches the user to ignore the section. Most changes are fine. -Say nothing when there is nothing to say. - -Keep going regardless. Skepticism shapes the plan and the open questions; it -does not withhold the plan. The only value judgment that stops authoring is -`no_actionable_work`, when the change is already implemented. - -### 3. Run the clarification gate - -Before writing or updating any plan file, check the request for critical -unresolved detail: - -- Scope boundaries and out-of-scope items. -- Acceptance criteria and the checks that prove them. -- Constraints and non-goals. -- Dependency choices, including new libraries or services, versions, and the - integration approach. -- Domain ambiguity, including unclear business rules, terminology, or ownership. -- Architecture concerns, including patterns, interfaces, data flow, migration - strategy, and risk tradeoffs. -- Task ordering assumptions and prerequisite sequencing. - -Return `needs_clarification` with one to three targeted questions when any of -these would materially change the plan. Write no plan file in that case. - -Use repository conventions for ordinary local choices. Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change scope, acceptance criteria, or task ordering. - -Record those choices under `assumptions`. - -Do not silently invent missing requirements. When the user has explicitly -allowed assumptions, record them in the plan's `Assumptions` section instead of -asking. - -A justification that does not survive inspection is itself a critical unresolved -detail. "For consistency", "to make it cleaner", "we will need it later" name no -outcome and prove nothing; ask what the change is actually for before planning -around it. Do not treat confident phrasing as evidence. - -### 4. Inspect relevant context - -Start from the context brief. Read code only where the brief leaves the change -underspecified: - -- Existing behavior the change affects. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests and available verification commands. -- Decisions or specifications connected to the change. - -Where the brief reports `drift`, the code is the source of truth. Plan against -the code, and schedule the context repair as part of the change when it falls -inside scope. - -Where the brief reports `gaps`, the plan may need to establish durable context -the repository does not yet have. - -Do not explore the entire repository by default. - -### 5. Author the acceptance criteria - -State how the finished plan is proven, before slicing tasks. - -Each criterion describes observable behavior of the finished system and names -the check that proves it. Record repository-wide checks once under -`Full validation`, and the durable context the change must be reflected in -under `Context sync`. - -`/validate` runs this section after the last task completes. It is the only -place a plan says how it is validated. - -### 6. Author the task stack - -Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. - -Every executable task must be completable and landable as one coherent commit. -Split any task that would require multiple independent commits. Convert broad -wrappers such as `polish` or `finalize` into specific outcomes with concrete -acceptance checks. - -Order tasks so each one's declared dependencies precede it. - -The last task is an ordinary implementation task. Do not author a trailing -validation-and-cleanup task, or any task whose only purpose is running the full -check suite, verifying durable context, or removing scaffolding. - -Confirm every acceptance criterion is satisfied by at least one task. When one -is not, the task stack is incomplete. - -A finished stack always leaves at least one incomplete task, so the invoking -workflow can always hand off to `/next-task`. When the request resolves to a -plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category -`no_actionable_work` instead of writing the plan. - -### 7. Write the plan - -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. - -When updating an existing plan, keep completed tasks and their evidence intact, -and append or renumber new tasks without disturbing recorded history. - -### 8. Return the result - -Return exactly one structured result: - -- `plan_ready` -- `needs_clarification` -- `blocked` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Tone - -Every question and open question this skill writes is read by the user. Write -them the way a senior engineer talks in review: direct, specific, and unbothered -by the possibility of being unwelcome. - -- Ask about the thing that actually worries you, not a safer neighbouring thing. - A question you would not bother asking a colleague is not worth the user's - attention either. -- State a doubt as a doubt. "I do not think this is worth the two tasks it - costs, because X" is useful. "It may be worth considering whether this aligns - with broader goals" is noise. -- Name the alternative you have in mind. A challenge with no proposal behind it - is just friction. -- Do not open with praise, do not close with reassurance, and do not apologize - for asking. Do not pad a doubt with hedges to make it land more gently. -- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not - restate the same doubt in three shapes to give it more weight. -- Being disagreeable is not the goal. Being easy to agree with is the failure - mode. A plan the user waves through without reading has cost them nothing and - bought them nothing. - -When the user overrules a doubt, record it and move on. Do not relitigate a -decision the user has made, and do not smuggle the objection back in as a -constraint, a non-goal, or a task. - -## Boundaries - -Do not: - -- Ask the user questions directly. Return `needs_clarification` and let the - invoking workflow present the questions. -- Answer your own clarification questions. -- Write a plan file when returning `needs_clarification` or `blocked`. -- Implement any task in the plan. -- Modify application code or tests. -- Modify any file under `context/` outside `context/plans/`. Plan the context - repair instead of performing it. -- Mark any task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Author a validation, cleanup, or context-verification task. `/validate` owns - that phase. -- Return `plan_ready` for a plan with no incomplete task. -- Create a Git commit. -- Author more than one plan. - -## Completion - -The skill is complete after: - -- One plan target was resolved, or resolution failed and was reported. -- The plan file was written, or no file was written because the result is - `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml b/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/config/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/config/.pi/skills/sce-plan-authoring/references/plan-summary.md b/config/.pi/skills/sce-plan-authoring/references/plan-summary.md deleted file mode 100644 index 0261808d..00000000 --- a/config/.pi/skills/sce-plan-authoring/references/plan-summary.md +++ /dev/null @@ -1,94 +0,0 @@ -# SCE Plan Summary - -The user-facing summary shown after a plan is written. The invoking workflow -renders it from the `plan_ready` result, immediately before the continuation -block. - -This is chat output, not a file. Nothing here is written to the plan. - -## Layout - -``` -# Plan: {plan.name} - -Path: {plan.path} - -## Summary: -{plan summary} - -## Tasks: -1. {task.id} — {task.title} -2. {task.id} — {task.title} - -## Assumptions: -- {assumption} - -## Open questions: -- {open question} -``` - -## Field mapping - -Every value comes from the `plan_ready` result. Render nothing the result does -not carry. - -- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. - Render nothing extra when it is `created`. -- `Path:` — `plan.path`, exactly as returned, so it stays runnable. -- `Summary:` — `summary`, as prose. This is the only place the reader learns - what the plan actually does, so never omit it and never replace it with a - restatement of the task titles. -- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append - ` (done)` to any task whose `status` is `done`. -- `Assumptions:` — one line per entry in `assumptions`. -- `Open questions:` — one line per entry in `open_questions`. - -## Empty sections - -Never drop a section heading. An absent section reads as an oversight; an -explicit `None.` confirms nothing is pending. - -When `assumptions` is empty: - -``` -## Assumptions: -- None. -``` - -When `open_questions` is absent: - -``` -## Open questions: -- None. -``` - -## Rules - -- Render the sections in the order above. -- Keep task titles as authored. Do not reword, expand, or re-scope them. -- Do not restate goals, boundaries, done checks, or verification notes. The plan - file owns task detail; this summary orients the reader. -- Do not print the raw result, and do not wrap the summary in a code fence. -- Do not add commentary, recommendations, or a next step. The continuation block - that follows owns the handoff. - -## Example - -``` -# Plan: red-sce-banner - -Path: context/plans/red-sce-banner.md - -## Summary: -Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. - -## Tasks: -1. T01 — Render the SCE banner in red - -## Assumptions: -- "SCE letters" refers to the ASCII-art banner in top-level help. -- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. - -## Open questions: -- None. -``` diff --git a/config/.pi/skills/sce-plan-authoring/references/plan-template.md b/config/.pi/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/config/.pi/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/config/.pi/skills/sce-plan-context-sync/SKILL.md b/config/.pi/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index 04958458..00000000 --- a/config/.pi/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,308 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.pi/skills/sce-plan-context-sync/references/sync-report.md b/config/.pi/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/config/.pi/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/config/.pi/skills/sce-plan-review/SKILL.md b/config/.pi/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 77c36481..00000000 --- a/config/.pi/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -`references/readiness-contract.yaml` - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was - returned. diff --git a/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml b/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/config/.pi/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/config/.pi/skills/sce-task-context-sync/SKILL.md b/config/.pi/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index 7af7c880..00000000 --- a/config/.pi/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,310 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/config/.pi/skills/sce-task-context-sync/references/sync-report.md b/config/.pi/skills/sce-task-context-sync/references/sync-report.md deleted file mode 100644 index 7d5acb94..00000000 --- a/config/.pi/skills/sce-task-context-sync/references/sync-report.md +++ /dev/null @@ -1,133 +0,0 @@ -# Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input execution status is always `complete` and does not need to be repeated -as a separate workflow state. - -## Synced variant - -# Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against implementation and execution evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Context impact - -**Classification:** none - -{Explain why the completed implementation did not introduce durable, -non-obvious repository knowledge requiring an update.} - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with implementation and execution evidence.} - ---- - -## Blocked variant - -# Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` -**Task:** `{task id} — {task title}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which context synchronization should run -again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Omit **Feature existence** only when the task implemented no feature. -- Describe durable truth, not implementation-session chronology. -- Keep evidence concise and factual. -- Do not claim final validation passed. -- Do not determine whether the plan is complete. -- Do not recommend a next implementation task. diff --git a/config/.pi/skills/sce-task-execution/SKILL.md b/config/.pi/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 3c8f7f70..00000000 --- a/config/.pi/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,246 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal YAML result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -`references/execution-contract.yaml` - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. -- Relevant files and context. -- Review assumptions. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task has not materially changed since review. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return YAML, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by `references/execution-contract.yaml`. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return YAML - -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` - was returned. diff --git a/config/.pi/skills/sce-task-execution/references/execution-contract.yaml b/config/.pi/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/config/.pi/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/config/.pi/skills/sce-task-execution/references/implementation-gate.md b/config/.pi/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index d4ad836c..00000000 --- a/config/.pi/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,69 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a YAML result. This -file is the only authority for the gate's content and order. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/config/.pi/skills/sce-validation/SKILL.md b/config/.pi/skills/sce-validation/SKILL.md deleted file mode 100644 index 2cd7557b..00000000 --- a/config/.pi/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -`references/validation-result.md` - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was - returned. diff --git a/config/.pi/skills/sce-validation/references/validation-report.md b/config/.pi/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/config/.pi/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/config/.pi/skills/sce-validation/references/validation-result.md b/config/.pi/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/config/.pi/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. diff --git a/config/pkl/README.md b/config/pkl/README.md index d0cb66cd..5dae64ad 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -47,25 +47,17 @@ Validate the generator entrypoint: nix develop -c pkl eval config/pkl/generate.pkl ``` -Preview generation without touching committed outputs: +Generate into an explicit temporary directory without touching repository paths: ```bash -nix develop -c pkl eval -m context/tmp/pkl-generated config/pkl/generate.pkl +tmp_dir="$(mktemp -d)" +nix run .#pkl-generate -- "$tmp_dir" +find "$tmp_dir/config" -type f | sort ``` -Regenerate tracked outputs in place: +Repository and Nix Cargo builds invoke the same generator from `cli/build.rs` and write its output under Cargo `OUT_DIR`. Do not evaluate with `-m .`: `config/.opencode`, `config/.claude`, and `config/.pi` are install payload layouts, not repository-owned output directories. -```bash -nix develop -c pkl eval -m . config/pkl/generate.pkl -``` - -Inspect the target trees: - -```bash -git status --short config/.opencode config/.claude config/.pi config/schema/sce-config.schema.json -``` - -## Verify parity +## Verify ephemeral generation Run the focused generated-output check: @@ -75,13 +67,13 @@ nix run .#pkl-check-generated The check: +- rejects committed `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, and `cli/assets/generated` outputs; - evaluates `metadata-coverage-check.pkl` for the exact three-command, seven-skill-package, nested-reference, and two-agent OpenCode inventory; -- regenerates into a temporary directory; -- compares complete OpenCode, Claude, and Pi generated directories, so extra, missing, or changed nested files fail parity; -- compares retained scalar outputs and the generated SCE config schema; -- rejects removed whole-tree outputs such as `config/automated/.opencode` and `config/.claude/agents`. +- generates twice into temporary directories and compares sorted SHA-256 inventories; +- requires all generated target roots and the SCE config schema while rejecting removed surfaces such as `config/automated/.opencode` and `config/.claude/agents`; +- prints the stable inventory count and digest without preserving generated files. -`nix flake check` runs the same contract through the `pkl-parity` derivation. Keep `config/pkl/check-generated.sh`, the `pklParitySrc` fileset, and the `pklParityCheck` path lists in `flake.nix` aligned with `config/pkl/generate.pkl` whenever output ownership changes. +`nix flake check` runs the same script through the `pkl-generated` derivation. Keep `config/pkl/check-generated.sh` and the `pklGeneratedCheckSrc` fileset in `flake.nix` aligned with `config/pkl/generate.pkl` whenever generator inputs change. ## Vendored dependencies @@ -98,8 +90,8 @@ Pkl dependencies are vendored under `config/pkl/deps/` for Nix sandbox compatibi **Inventory check failure** — Compare the three workflow modules and renderer output mappings with the expected commands, agents, skill entrypoints, and package-local reference paths in `metadata-coverage-check.pkl`. -**Generated output drift** — Regenerate with `nix develop -c pkl eval -m . config/pkl/generate.pkl`, inspect the diff, and rerun `nix run .#pkl-check-generated`. +**Nondeterministic output** — Generate twice into separate temporary directories, compare their inventories, and correct the canonical Pkl or renderer input responsible for the difference. -**Removed output still exists** — Delete the reported obsolete generated path after confirming it is generation-owned; do not add it back to the generator or parity source list. +**Removed output still exists** — Delete the reported obsolete generated path after confirming it is generation-owned; do not restore repository target trees or add them to a source filter. **Unexpected drift outside generated-owned paths** — Stop and confirm whether the path is manual or runtime-managed before changing generation ownership. diff --git a/config/pkl/check-generated.sh b/config/pkl/check-generated.sh index a7a44fbd..ce36e0cb 100755 --- a/config/pkl/check-generated.sh +++ b/config/pkl/check-generated.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -repo_root="$(git rev-parse --show-toplevel)" +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="${SCE_REPO_ROOT:-$(cd "${script_dir}/../.." && pwd)}" cd "$repo_root" if [[ -z "${IN_NIX_SHELL:-}" ]]; then @@ -19,82 +20,97 @@ if ! command -v pkl >/dev/null 2>&1; then exit 1 fi +legacy_paths=( + "config/.opencode" + "config/.claude" + "config/.pi" + "config/schema/sce-config.schema.json" + "cli/assets/generated" +) + +for path in "${legacy_paths[@]}"; do + if [[ -e "$path" ]]; then + printf 'Removed generated output still exists at %s\n' "$path" >&2 + exit 1 + fi +done + tmp_dir="$(mktemp -d)" cleanup() { rm -rf "$tmp_dir" } trap cleanup EXIT +first_root="$tmp_dir/first" +second_root="$tmp_dir/second" +mkdir -p "$first_root" "$second_root" + pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null -pkl eval -m "$tmp_dir" config/pkl/generate.pkl >/dev/null +pkl eval -m "$first_root" config/pkl/generate.pkl >/dev/null +pkl eval -m "$second_root" config/pkl/generate.pkl >/dev/null -# Compare complete generated directories so nested skill references and stale -# files are covered without maintaining a separate per-document path list. -paths=( +required_paths=( "config/.opencode/agent" "config/.opencode/command" "config/.opencode/skills" - "config/.opencode/lib" - "config/.opencode/plugins" + "config/.opencode/lib/bash-policy-presets.json" + "config/.opencode/plugins/sce-bash-policy.ts" + "config/.opencode/plugins/sce-agent-trace.ts" "config/.opencode/opencode.json" "config/.claude/commands" "config/.claude/skills" - "config/.claude/hooks" + "config/.claude/hooks/run-sce-or-show-install-guidance.sh" "config/.claude/settings.json" "config/.pi/prompts" "config/.pi/skills" - "config/.pi/extensions" + "config/.pi/extensions/sce/index.ts" "config/schema/sce-config.schema.json" ) -# These removed surfaces must stay absent from both generated previews and the -# committed tree. Obsolete files inside retained directories are caught by the -# complete-directory comparisons above. -forbidden_paths=( +for path in "${required_paths[@]}"; do + if [[ ! -e "$first_root/$path" ]]; then + printf 'Generator did not emit required output at %s\n' "$path" >&2 + exit 1 + fi +done + +forbidden_outputs=( "config/automated/.opencode" "config/.claude/agents" ) -stale=0 -for path in "${paths[@]}"; do - if [[ ! -e "$tmp_dir/$path" ]]; then - stale=1 - printf 'Generator did not emit required output at %s\n' "$path" - continue - fi - - if [[ ! -e "$path" ]]; then - stale=1 - printf 'Required generated output is missing at %s\n' "$path" - continue - fi - - if ! git diff --no-index --exit-code -- "$tmp_dir/$path" "$path" >/dev/null; then - stale=1 - printf 'Generated output drift detected at %s\n' "$path" - git diff --no-index -- "$tmp_dir/$path" "$path" || true +for path in "${forbidden_outputs[@]}"; do + if [[ -e "$first_root/$path" ]]; then + printf 'Generator emitted removed output at %s\n' "$path" >&2 + exit 1 fi done -for path in "${forbidden_paths[@]}"; do - if [[ -e "$tmp_dir/$path" ]]; then - stale=1 - printf 'Generator emitted removed output at %s\n' "$path" - fi - if [[ -e "$path" ]]; then - stale=1 - printf 'Removed generated output still exists at %s\n' "$path" - fi -done +write_inventory() { + local generated_root="$1" + local inventory_path="$2" -if [[ "$stale" -ne 0 ]]; then - cat <<'EOF' -Generated files are stale. + ( + cd "$generated_root" + find config -type f -print \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "$path" + done + ) > "$inventory_path" +} -Regenerate with: - nix develop -c pkl eval -m . config/pkl/generate.pkl -EOF +first_inventory="$tmp_dir/first.SHA256SUMS" +second_inventory="$tmp_dir/second.SHA256SUMS" +write_inventory "$first_root" "$first_inventory" +write_inventory "$second_root" "$second_inventory" + +if ! diff -u "$first_inventory" "$second_inventory"; then + printf 'Pkl generation is not deterministic.\n' >&2 exit 1 fi -printf 'Generated outputs are up to date.\n' +inventory_digest="$(sha256sum "$first_inventory" | cut -d ' ' -f 1)" +inventory_count="$(wc -l < "$first_inventory" | tr -d ' ')" +printf 'Ephemeral Pkl generation passed: %s files, inventory sha256 %s.\n' \ + "$inventory_count" "$inventory_digest" diff --git a/config/schema/sce-config.schema.json b/config/schema/sce-config.schema.json deleted file mode 100644 index 22d97cf4..00000000 --- a/config/schema/sce-config.schema.json +++ /dev/null @@ -1,397 +0,0 @@ -{ - "$id": "https://sce.crocoder.dev/config.json", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCE Config", - "description": "Canonical JSON Schema for global and repo-local sce/config.json files.", - "type": "object", - "properties": { - "$schema": { - "type": "string", - "const": "https://sce.crocoder.dev/config.json" - }, - "log_level": { - "type": "string", - "enum": [ - "error", - "warn", - "info", - "debug" - ] - }, - "log_format": { - "type": "string", - "enum": [ - "text", - "json" - ] - }, - "log_file": { - "type": "string", - "minLength": 1 - }, - "log_file_mode": { - "type": "string", - "enum": [ - "truncate", - "append" - ] - }, - "timeout_ms": { - "type": "integer", - "minimum": 0 - }, - "workos_client_id": { - "type": "string" - }, - "agent_trace": { - "description": "Agent Trace repository identity configuration. Selects the repository-scoped Agent Trace database.", - "type": "object", - "properties": { - "repository_id": { - "description": "Explicit repository identity. When set, overrides Git remote based repository identity resolution.", - "type": "string", - "minLength": 1 - }, - "repository_remote": { - "description": "Git remote name used to derive repository identity. Defaults to origin when omitted.", - "default": "origin", - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": false - }, - "policies": { - "type": "object", - "properties": { - "attribution_hooks": { - "description": "Attribution hook policy. Commit-msg attribution is enabled by default and can be suppressed with SCE_ATTRIBUTION_HOOKS_DISABLED=1 or by setting enabled to false.", - "type": "object", - "properties": { - "enabled": { - "description": "Enable SCE attribution hooks. Defaults to true when omitted; set false as an explicit opt-out. Environment opt-out: SCE_ATTRIBUTION_HOOKS_DISABLED.", - "default": true, - "type": "boolean" - } - }, - "additionalProperties": false - }, - "database_retry": { - "type": "object", - "properties": { - "local_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - }, - "agent_trace_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - }, - "auth_db": { - "type": "object", - "properties": { - "connection_open": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - }, - "query": { - "type": "object", - "properties": { - "max_attempts": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "initial_backoff_ms": { - "type": "integer", - "minimum": 0 - }, - "max_backoff_ms": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "max_attempts", - "timeout_ms", - "initial_backoff_ms", - "max_backoff_ms" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "bash": { - "type": "object", - "properties": { - "presets": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "forbid-git-all", - "forbid-git-commit", - "use-pnpm-over-npm", - "use-bun-over-npm", - "use-nix-flake-over-cargo" - ] - }, - "uniqueItems": true, - "allOf": [ - { - "not": { - "allOf": [ - { - "contains": { - "const": "use-pnpm-over-npm" - } - }, - { - "contains": { - "const": "use-bun-over-npm" - } - } - ] - } - } - ] - }, - "custom": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "minLength": 1, - "not": { - "enum": [ - "forbid-git-all", - "forbid-git-commit", - "use-pnpm-over-npm", - "use-bun-over-npm", - "use-nix-flake-over-cargo" - ] - } - }, - "match": { - "type": "object", - "properties": { - "argv_prefix": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1 - } - }, - "additionalProperties": false, - "required": [ - "argv_prefix" - ] - }, - "satisfied_by": { - "description": "Wrapper argv prefixes that already satisfy this policy. The policy does not fire when the matched command was unwrapped from one of these wrappers, so a policy steering `rg` toward nix can stay quiet for `nix shell nixpkgs#ripgrep -c rg ...` while still blocking a bare `rg`.", - "type": "array", - "items": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1 - } - }, - "message": { - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": false, - "required": [ - "id", - "match", - "message" - ] - } - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "integrations": { - "type": "object", - "properties": { - "target": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "opencode", - "claude", - "pi" - ] - }, - "uniqueItems": true - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false, - "dependentRequired": { - "log_file_mode": [ - "log_file" - ] - } -} diff --git a/context/architecture.md b/context/architecture.md index 0d68af8a..4249a235 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -2,13 +2,9 @@ ## Config generation boundary (current approved design) -The repository keeps three parallel config target trees: +The repository keeps no committed OpenCode, Claude, or Pi generated target trees. `config/.opencode`, `config/.claude`, and `config/.pi` are logical payload layouts emitted only beneath temporary generation roots, Cargo `OUT_DIR`, and packaging-only fallback directories. -- `config/.opencode` -- `config/.claude` -- `config/.pi` - -For authored config content, generation is standardized around one canonical Pkl source model with target-specific rendering applied later in the pipeline. +Authored config content is standardized around one canonical Pkl source model with target-specific rendering applied later in the pipeline. Current location for canonical workflow content primitives: @@ -30,8 +26,8 @@ Current target renderer helper modules: - `config/pkl/renderers/claude-metadata.pkl` - `config/pkl/renderers/metadata-coverage-check.pkl` - `config/pkl/generate.pkl` (single multi-file generation entrypoint) -- `config/pkl/check-generated.sh` (dev-shell integration stale-output detection against committed generated files) -- `nix flake check` / `checks..{cli-tests,cli-clippy,cli-fmt,pkl-parity,npm-bun-tests,npm-biome-check,npm-biome-format,config-lib-bun-tests,config-lib-biome-check,config-lib-biome-format,workflow-actionlint}` plus Linux-only `flatpak-static-validation`, `cargo-sources-parity`, and `flatpak-manifest-parity` (root-flake check derivations for the current CLI, generated-output parity, JS validation inventory, workflow linting, and lightweight Flatpak static/AppStream validation) +- `config/pkl/check-generated.sh` (dev-shell integration check for two-pass deterministic temporary inventories, required outputs, and forbidden repository generated paths) +- `nix flake check` / `checks..{cli-tests,cli-clippy,cli-fmt,pkl-generated,npm-bun-tests,npm-biome-check,npm-biome-format,config-lib-bun-tests,config-lib-biome-check,config-lib-biome-format,workflow-actionlint}` plus Linux-only `flatpak-static-validation`, `cargo-sources-parity`, and `flatpak-manifest-parity` (root-flake checks for CLI behavior, ephemeral Pkl generation, JS validation, workflow linting, and lightweight Flatpak validation) - `config-lib-bun-tests` executes from `config/lib/` while using a repo-shaped copied source subset that also includes `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden fixture coverage (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). The scaffold provides stable canonical content-unit identifiers and reusable target-agnostic text primitives for all planned authored generated classes (agents, commands, skills, shared runtime assets, OpenCode plugin entrypoints, the Pi extension entrypoint, generated OpenCode package manifests, and generated Claude project settings). @@ -48,7 +44,7 @@ Renderer modules apply target-specific metadata/frontmatter rules while reusing - OpenCode, Claude, and Pi renderers expose canonical command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`. - `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's three workflow commands, seven complete skill packages with nested references, and two thin routing agents; Claude's three workflow commands and seven complete skill packages with nested references but no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (three workflow prompts, seven complete skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. -- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, evaluates exact metadata coverage, regenerates into a temporary tree, and compares complete generated directories plus scalar/schema outputs. Complete-directory comparison covers nested references and extra stale files; explicit forbidden-path checks reject `config/automated/.opencode` and `config/.claude/agents`. The root-flake `pkl-parity` derivation mirrors this inventory from a focused source set containing all retained OpenCode, Claude, and Pi generated trees. +- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. Generated authored classes: @@ -78,13 +74,14 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - The current implemented binary install/distribution surface for the `sce` CLI includes repo-flake Nix, Cargo, and npm; `Homebrew` is deferred from the active implementation stage. - Flatpak is also an official supported distribution channel for this implementation stage under application ID `dev.crocoder.sce`, with a source-built Flatpak package rather than a wrapper around Nix-built, native GitHub Release binary, npm native, or other prebuilt `sce` artifacts. - Nix-managed build/release entrypoints are the source of truth for existing binary build outputs and release automation, and Nix may orchestrate Flatpak tooling, local-source overrides, and validation without becoming the Flatpak package's binary source. -- The implemented Flatpak packaging/tooling surface lives under `packaging/flatpak/` with Nix-owned generation: `dev.crocoder.sce.yml` is the Flathub-style source-build manifest rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`) and regenerated by `nix run .#regenerate-flatpak-manifest`; `cargo-sources.json` is produced from `cli/Cargo.lock` by a Nix derivation (`nix/flatpak/cargo-sources.nix` wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py`) and regenerated by `nix run .#regenerate-cargo-sources`; both are guarded by parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`). Static manifest validation is Bash-owned at `nix/flatpak/static-validate.sh` and wrapped by Nix as `flatpak-static-check`; release-version parity validation is Bash-owned at `nix/flatpak/version-parity.sh` and wrapped by Nix as `flatpak-version-parity-check`. `dev.crocoder.sce.metainfo.xml` is the AppStream console-app metadata, `git-host-bridge` is installed as `/app/bin/git` to delegate runtime Git access to `flatpak-spawn --host git` with the required `org.freedesktop.Flatpak` permission, and `sce-flatpak.sh` is the thin imperative orchestrator (no manifest rewriting, no embedded Python) around `flatpak-builder` + `flatpak build-bundle`. -- GitHub Release Flatpak source-manifest assets are implemented for the active release model as packaging metadata only: `nix run .#release-flatpak-package -- --version --out-dir ` packages `sce-v-flatpak-manifest.tar.gz`, its `.sha256`, and `sce-v-flatpak.json` from the Flatpak manifest/support files with the staged manifest pinned to the release commit. +- The implemented Flatpak packaging/tooling surface lives under `packaging/flatpak/` with Nix-owned generation: `dev.crocoder.sce.yml` is the Flathub-style source-build manifest rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`) and regenerated by `nix run .#regenerate-flatpak-manifest`; `cargo-sources.json` is produced from `cli/Cargo.lock` by a Nix derivation (`nix/flatpak/cargo-sources.nix` wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py`) and regenerated by `nix run .#regenerate-cargo-sources`; both are guarded by parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`). Static manifest validation is Bash-owned at `nix/flatpak/static-validate.sh` and wrapped by Nix as `flatpak-static-check`; release-version parity validation is Bash-owned at `nix/flatpak/version-parity.sh` and wrapped by Nix as `flatpak-version-parity-check`. `dev.crocoder.sce.metainfo.xml` is the AppStream metadata, and `git-host-bridge` delegates runtime Git access to `flatpak-spawn --host git`. Because the Flatpak sandbox has no Pkl, `sce-flatpak.sh` prepares a checksummed fallback in the temporary manifest support directory before `flatpak-builder`; the manifest copies it into `cli/package-fallback` as a `type: dir` source. +- GitHub Release Flatpak source-manifest assets remain source-oriented rather than binary artifacts: `nix run .#release-flatpak-package -- --version --out-dir ` packages the manifest/support files plus an ephemeral checksummed fallback payload, with the staged manifest pinned to the release commit. The fallback is copied into `cli/package-fallback` by Flatpak's source list so Cargo can build without Pkl inside the sandbox. - Flatpak GitHub Release assets now also include source-built `.flatpak` bundle assets (`sce-v-x86_64.flatpak` / `sce-v-aarch64.flatpak` plus `.sha256` / `.json`) alongside source-manifest packaging metadata. - Automatic Flathub submission, prebuilt (non-source-built) Flatpak binaries/bundles, OSTree repositories, release-version bumping, and Flatpak publication beyond the approved GitHub Release asset upload remain outside the current iteration. - Repo-root `.version` is the canonical checked-in release version authority across GitHub Releases, Cargo publication, and npm publication. - GitHub Releases are the canonical publication surface for release archives, checksums, release-manifest assets, npm package assets, and approved Flatpak source-manifest and bundle assets. - Cargo/crates.io and npm registry publication belong to separate downstream publish stages that consume already-versioned checked-in package metadata rather than inventing release versions during workflow execution. +- Crates.io packaging is self-contained through ignored `cli/package-fallback/`: the preparation script generates and inventories the payload from canonical Pkl plus static inputs in a temporary clean workspace, `cli/Cargo.toml` includes only that fallback and crate sources, and unpacked-crate `build.rs` validates then copies it into `OUT_DIR` without Pkl. Repository builds detect canonical Pkl sources first and retain direct generation as the authoritative path. - npm is a downstream consumer of the shared release artifact contract rather than a separate build owner. - `flake.nix` now exposes dedicated release-packaging apps for this rollout: `apps.release-artifacts` packages the current-platform `sce` archive/checksum/manifest-fragment set from the release output `packages.sce-release` (`nix build .#sce-release`), prepares/audits the staged `bin/sce` before archive creation (including macOS `libiconv` install-name rewriting plus ad-hoc re-signing when needed), and fails if `.version`, `cli/Cargo.toml`, `npm/package.json`, the built/prepared CLI version, or the native portability audit disagree; `apps.native-portability-audit` audits native binaries for forbidden `/nix/store/` runtime references using Linux ELF/string inspection or macOS `otool -L`; `apps.release-manifest` merges per-platform metadata fragments into release-level manifest/checksum outputs and signs the merged manifest with a non-repo private key provided via env/file input; `apps.release-npm-package` packs the checked-in npm launcher package into a release-ready `sce-v-npm.tgz` tarball plus npm metadata JSON while refusing mismatched checked-in version metadata; and Linux-only `apps.release-flatpak-package` emits the Flatpak source-manifest tarball/checksum/JSON metadata while refusing `.version`/Cargo/npm/AppStream version drift and non-git checkouts that cannot resolve a release commit; Linux-only `apps.release-flatpak-bundle` builds a source-built `.flatpak` bundle from the checkout and emits per-architecture bundle/checksum/JSON metadata. - CLI release automation: `.github/workflows/release-sce.yml` orchestrates `sce` GitHub release asset assembly, validates `.version`/Cargo/npm parity before tagging or releasing, calls three reusable per-platform workflow files (`release-sce-linux.yml`, `release-sce-linux-arm.yml`, `release-sce-macos-arm.yml`), assembles the signed native release manifest, builds npm and Flatpak source-manifest release packages, and uploads the CLI/npm/Flatpak asset set to the GitHub Release. Each native reusable workflow validates its generated archive before native artifact upload by extracting the target archive, smoke-running `bin/sce version --format json`, and running `nix run .#native-portability-audit` with the lane platform. Manual `workflow_dispatch` runs can set the GitHub Release-level `prerelease` flag through an explicit checkbox; tag-triggered releases keep the flag false and no tag-name prerelease inference is performed. @@ -101,7 +98,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/observability.rs` provides deterministic runtime observability controls and rendering for app lifecycle logs, including shared config-resolved threshold/format and file-sink inputs with precedence `env > config file > defaults` for non-flag observability keys, optional file sink controls (`SCE_LOG_FILE`, `SCE_LOG_FILE_MODE` with deterministic truncate-or-append policy), stable event identifiers, severity filtering, the forced-emission warning path used for invalid discovered config startup diagnostics, stderr-only primary emission with optional mirrored file writes, and redaction-safe emission through the shared security helper. Its `observability::traits` submodule exposes the current `Logger` and object-safe `Telemetry` trait boundaries plus `NoopLogger`; the concrete observability logger and telemetry runtime still own behavior and implement those traits without changing runtime behavior. `services::app_support::render_run_outcome` consumes the logger through that trait boundary when logging classified errors and stdout-write failures. - `cli/src/services/observability.rs` no longer owns duplicate log enums or parsing helpers; it consumes the canonical primitive seam from `cli/src/services/config/mod.rs` and stays focused on logger and telemetry runtime behavior. - `cli/src/cli_schema.rs` is now the canonical owner for top-level command metadata for the real clap-backed command set (`auth`, `config`, `setup`, `doctor`, `hooks`, `version`, `completion`), including the slim top-level help purpose text and per-command visibility on `sce`, `sce help`, and `sce --help`; `cli/src/command_surface.rs` remains the custom top-level help renderer and known-command classifier, adding the synthetic `help` row plus the ASCII banner while consuming that shared metadata instead of maintaining a parallel command catalog. -- `cli/src/services/default_paths.rs` is the canonical production path catalog for the CLI: it resolves config/state/cache roots with platform-aware XDG or `dirs` fallbacks through an internal `roots` seam, exposes named default paths for current persisted artifacts and database files (global config, auth tokens, auth DB, local DB, and the sole Agent Trace DB path helper `agent_trace_db_path_for_repository` under `repos//agent-trace.db`; the former global-sentinel and per-checkout Agent Trace path helpers were removed by the `retire-legacy-agent-trace-db` plan), and owns canonical repo-relative, embedded-asset, install, hook, and context-path accessors so non-test production path definitions have one shared owner. Current production consumers such as config discovery, doctor reporting, setup/install flows, database adapters, checkout identity, Agent Trace storage resolution, and local hook runtime path resolution consume this shared catalog rather than defining owned path literals in their own modules. +- `cli/src/services/default_paths.rs` is the canonical production path catalog for the CLI: it resolves config/state/cache roots with platform-aware XDG or `dirs` fallbacks through an internal `roots` seam, exposes named default paths for current persisted artifacts and database files (global config, auth tokens, auth DB, local DB, and the sole Agent Trace DB path helper `agent_trace_db_path_for_repository` under `repos//agent-trace.db`; the former global-sentinel and per-checkout Agent Trace path helpers were removed by the `retire-legacy-agent-trace-db` plan), and owns canonical repo-relative, install, hook, and context-path accessors so non-test production runtime path definitions have one shared owner. Compile-time generated payload paths are owned by `build.rs` under `OUT_DIR`, not by the default-path catalog. Current production consumers such as config discovery, doctor reporting, setup/install flows, database adapters, checkout identity, Agent Trace storage resolution, and local hook runtime path resolution consume this shared catalog rather than defining owned path literals in their own modules. - `cli/src/services/agent_trace.rs` is the Rust CLI owner for the SCE web base URL (`SCE_WEB_BASE_URL`) and exposes helpers for SCE-owned URL construction: Agent Trace conversation lookup URLs, persisted Agent Trace trace URLs, Agent Trace session URLs, and setup-created config schema URLs. Production Rust code should consume those helpers instead of repeating `sce.crocoder.dev` literals. - `cli/src/services/config/mod.rs` is the config service facade and `sce config` orchestration surface (`show`, `validate`, `--help`), with bare `sce config` routed by `cli/src/app.rs` to the same help payload as `sce config --help`. Focused submodules own the implementation slices: `types.rs` owns shared config/runtime primitives, `schema.rs` owns generated schema embedding plus typed file parsing, `policy.rs` owns bash-policy semantic validation plus policy-specific formatting and runtime preset-catalog access for the Rust evaluator, `resolver.rs` owns deterministic config-file discovery, file-layer merging, explicit value precedence (`flags > env > config file > defaults` where flag-backed), shared auth-key resolution, observability-runtime resolution, attribution-hooks runtime gate resolution, database-retry config resolution and `DATABASE_RETRY_CONFIG` `OnceLock` initialization, default-discovered invalid-file degradation, and explicit-path fatal errors for `--config` / `SCE_CONFIG_FILE`, and private `render.rs` owns `sce config show` / `sce config validate` text and JSON output construction plus rendering-specific display-value helpers. The facade preserves existing `services::config` imports for startup/auth/hooks callers while delegating command execution to resolution plus rendering submodules. - `cli/src/services/output_format.rs` defines the canonical shared CLI output-format contract (`OutputFormat`) for supporting commands, with deterministic `text|json` parsing and command-scoped actionable invalid-value guidance. @@ -115,7 +112,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/auth_db/mod.rs` provides the encrypted auth DB spec and `AuthDb` type alias over `EncryptedTursoDb`. `AuthDbSpec` resolves `/sce/auth.db` through the shared default-path seam and embeds ordered auth migrations. Auth DB lifecycle setup/doctor integration is wired through `AuthDbLifecycle`; auth command/token-storage reads/writes are directed through `token_storage.rs`. - `cli/src/services/agent_trace_db/mod.rs` owns the shared Agent Trace insert payloads, SQL constants, and typed row helpers (diff-trace/intersection/Agent Trace/message/part) plus `ensure_schema_ready_for_hooks()` consumed by the repository adapter. `cli/src/services/agent_trace_db/repository.rs` defines the sole `RepositoryAgentTraceDb` adapter over `TursoDb` with one fresh `agent-trace-repository/001_repository_schema.sql` baseline for `diff_traces` (including `payload_type`), `post_commit_patch_intersections`, `agent_traces`, `messages`, `parts`, indexes, and triggers, `repository_metadata` validation, no trace-table `checkout_id` columns, `agent_traces.agent_trace_id NOT NULL UNIQUE`, and `recent_diff_trace_patches(cutoff_time_ms, end_time_ms)` using the inclusive chronological parser without checkout filtering. Active hook runtime, setup/lifecycle storage, and trace status/list/shell flows resolve through `agent_trace_storage` and use `RepositoryAgentTraceDb`. The checkout-scoped `AgentTraceDb`/`AgentTraceDbSpec` adapter, its `agent_trace_db_path()`/`agent_trace_db_path_for_checkout()` helpers, the 15-file `cli/migrations/agent-trace/` chain, and the `sce trace --legacy` surface were removed by the `retire-legacy-agent-trace-db` plan. - `cli/src/test_support.rs` provides a shared test-only temp-directory helper (`TestTempDir`) used by service tests that need filesystem fixtures. -- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups) generated by `cli/build.rs` from the ephemeral crate-local `cli/assets/generated/config/{opencode,claude,pi}/**` mirror plus `cli/assets/hooks/**`, and focused internal support seams for install-flow vs prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). The setup command derives a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. +- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), and compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups). For repository builds, `cli/build.rs` evaluates canonical Pkl outputs into Cargo `OUT_DIR/pkl-generated`, stages `cli/assets/hooks/**` under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; focused internal seams separate install-flow from prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). The setup command derives a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. - `cli/src/services/setup/mod.rs` keeps those responsibilities inside one file for now, but the current ownership split is explicit: the inline `install` module owns repository-path normalization, staging/swap install behavior, required-hook installation, and filesystem safety guards, while the inline `prompt` module owns interactive target selection and prompt styling. - `cli/src/services/security.rs` provides shared security utilities for deterministic secret redaction (`redact_sensitive_text`) and directory write-permission probes (`ensure_directory_is_writable`) used by app/setup/observability surfaces. - `cli/src/services/doctor/mod.rs` owns the current doctor request/report surface while focused submodules (`doctor/inspect.rs`, `doctor/render.rs`, `doctor/fixes.rs`, `doctor/types.rs`) split report fact collection, rendering, manual fix reporting, and doctor-owned domain types into smaller seams; `cli/src/services/doctor/command.rs` owns the `DoctorCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Runtime doctor execution resolves a repository root, derives a scoped context, requests the shared static lifecycle provider catalog with hooks included for service-owned `diagnose` and `fix` behavior, adapts lifecycle-owned health/fix records into doctor-owned problem/fix records, and then renders stable text/JSON problem records with category/severity/fixability/remediation fields plus deterministic fix-result reporting in fix mode. Checkout DB discovery no longer lives in `doctor`; it moved to the `trace` group (`sce trace db list`) in `cli/src/services/trace/`. Report fact collection preserves environment/repository/hook/integration display data and checkout identity facts, while service-owned lifecycle providers own config validation, local DB and repository-scoped Agent Trace DB readiness/bootstrap, and hook rollout diagnosis/repair. @@ -129,12 +126,12 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/structured_patch.rs` defines the synchronous structured editor-hook derivation seam. It derives Claude `PostToolUse` `Write` structured-update hunks, `Write` `tool_input.content` create fallback, and `Edit` structured-patch payloads into canonical `ParsedPatch` values plus Claude session/tool metadata, returning deterministic skip reasons for unsupported events/tools/payload shapes. The module is pure and side-effect-free. It is wired into `sce hooks diff-trace` for Claude payload classification at intake (T04) and into `RepositoryAgentTraceDb::recent_diff_trace_patches` for post-commit structured payload parsing dispatch at read time (T05). - `cli/src/services/` contains module boundaries for command_registry, lifecycle, auth_command, config, setup, doctor, hooks, checkout identity, bash_policy, version, completion, help, patch, SCE web URL helpers, shared database infrastructure, local DB adapters, encrypted auth DB adapters, and Agent Trace DB adapters with explicit trait seams for future implementations. `cli/src/services/checkout/` owns checkout ID file infrastructure (the per-checkout Agent Trace DB opener/path helper was removed by the `retire-legacy-agent-trace-db` plan); active setup/hooks use `agent_trace_storage` to establish checkout identity as diagnostics and initialize/open the repository-scoped DB, while `sce doctor` surfaces checkout identity facts plus credential-safe repository Agent Trace DB metadata. There is no checkout-scoped discovery or `sce trace --legacy` surface; any pre-migration `agent-trace-*.db` files on disk are never touched and no longer inspectable via the CLI. `cli/src/services/bash_policy.rs` owns both the CLI-agnostic evaluator logic and the hidden `sce policy bash` command adapter used by OpenCode, Claude, and Pi callers. `cli/src/services/command_registry.rs` defines the static `RuntimeCommand` enum, deterministic `CommandRegistry` name catalog, and `build_default_registry()` function for command dispatch metadata. Service-owned command modules own the runtime command payload structs for help/help-text, version, completion, auth, config, setup, doctor, hooks, and policy. - `cli/README.md` is the crate-local onboarding and usage source of truth for placeholder behavior, safety limitations, and roadmap mapping back to service contracts. -- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, reads the package/check version from repo-root `.version`, builds `packages.sce` through Crane (`buildDepsOnly` -> `buildPackage`) with shared host Cargo metadata plus a filtered repo-root source that preserves the Cargo tree, `cli/assets/hooks`, and only the generated config/schema inputs required by CLI embedding, then injects generated OpenCode/Claude/Pi config payloads and schema inputs into a temporary `cli/assets/generated/` mirror during derivation unpack so `cli/build.rs` can package the crate without requiring committed generated crate assets. The same `cli/build.rs` now scans `cli/migrations/*/*.sql` and writes `cli/src/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. -- The root flake runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed paths for the CLI crate; `cli-fmt` intentionally uses the CLI-only Cargo source set rather than the package source with generated config/assets so formatting is not invalidated by release/config asset churn. The flake also exposes directory-scoped JS validation derivations for both `npm/` and the shared `config/lib/` plugin package root, and `pkl-parity` uses a narrowed Pkl/generated-output source set instead of copying the entire repository. +- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, and reads package/check version from repo-root `.version`. Crane package/test/clippy sources include canonical Pkl, referenced plugin/extension sources, and static inputs, with Pkl on the native build path so `cli/build.rs` evaluates directly into `OUT_DIR`; published crates use the validated packaging-only fallback. The build script stages SQL under `OUT_DIR/static/migrations` and writes `OUT_DIR/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. +- The root flake runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed paths for the CLI crate; `cli-fmt` intentionally uses the CLI-only Cargo source set. The flake also exposes directory-scoped JS validation derivations for `npm/` and `config/lib/`, while `pkl-generated` uses a narrow canonical-input source set plus maybe-missing forbidden paths so reintroduced generated repository artifacts fail the check. - Git-commit embedding is release-only. `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment (`{ SCE_GIT_COMMIT = shortGitCommit; }`) merged only into the release derivations — `scePackageMusl` on Linux and a dedicated native-toolchain `sceReleasePackageNative` on Darwin — and is deliberately absent from `commonCargoArgs`. As a result native `packages.sce`/`packages.default` and the `cli-tests`/`cli-clippy`/`cli-fmt` check derivations carry no commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` reports the real commit. `cli/build.rs` `emit_git_commit` emits the `rustc-env` value only when `SCE_GIT_COMMIT` is explicitly set (with `rerun-if-env-changed=SCE_GIT_COMMIT` as its sole rerun trigger) — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` watches — and `cli/src/services/version/mod.rs` resolves the commit through `option_env!("SCE_GIT_COMMIT")` with an `"unknown"` fallback. On Darwin the release derivation therefore diverges from `.#sce` (shared deps `cargoArtifacts`, but distinct final crate carrying the commit). - `flake.nix` exposes `packages..ci-checks` (`ciChecks`) as the explicit long-running validation tier so the expensive work lives behind `nix build .#ci-checks` and never folds into `nix flake check`. It is a `runCommand` aggregate that symlinks its primary member `sceReleasePackage` into `$out/sce-release` (forcing the static-musl release build on Linux, native on Darwin) and, on Linux only, symlinks `releasePortabilityAuditCheck` into `$out/release-portability-audit`. That Linux-only `releasePortabilityAuditCheck` derivation runs `nix/release/native-portability-audit.sh --platform linux --binary ${sceReleasePackage}/bin/sce` (with `binutils`+`coreutils` on PATH) so `nix build .#ci-checks` fails when the real release binary carries forbidden `/nix/store/` references. This is distinct from `checks..native-portability-audit` (`nativePortabilityAuditCheck`), which remains a fixture-based unit test of the audit script on both platforms. CI wiring to `.#ci-checks` is owned by the separate `release-validation` matrix job in `.github/workflows/pr-ci.yml`, which builds `nix build .#ci-checks` on every PR/`main`/tag commit. - Flatpak flake tooling is Linux-only and reduced to a minimal app surface: `apps.sce-flatpak` is the umbrella entrypoint (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest --repo-root `, etc.) that delegates to `packaging/flatpak/sce-flatpak.sh`; `apps.release-flatpak-package` emits deterministic Flatpak GitHub Release source-manifest assets; `apps.release-flatpak-bundle` builds a source-built `.flatpak` bundle; helper apps `apps.regenerate-flatpak-manifest` and `apps.regenerate-cargo-sources` rewrite the checked-in generated artifacts from their Nix sources. The standalone `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed in favor of `sce-flatpak `. `checks..flatpak-static-validation` runs the Nix-built static validator script during default `nix flake check`, and `checks..flatpak-manifest-parity` plus `checks..cargo-sources-parity` enforce the generated-artifact parity contracts; default `nix flake check` does not run `flatpak-builder`. The Linux dev shell includes `appstreamcli`, `flatpak`, and `flatpak-builder`. -- The shared config-lib source set is rooted at `config/lib/` and includes the shared `package.json`, `bun.lock`, and `tsconfig.json` plus `agent-trace-plugin/` and `bash-policy-plugin/`; `config-lib-bun-tests` runs the bash-policy plugin wrapper tests from that shared root, while `config-lib-biome-check` and `config-lib-biome-format` run Biome over the copied shared package source. `.github/workflows/publish-crates.yml` follows the same asset-preparation rule but runs Cargo packaging from a temporary clean repository copy so crates.io publish no longer needs `--allow-dirty`. +- The shared config-lib source set is rooted at `config/lib/` and includes the shared `package.json`, `bun.lock`, and `tsconfig.json` plus `agent-trace-plugin/` and `bash-policy-plugin/`; `config-lib-bun-tests` runs the bash-policy plugin wrapper tests from that shared root, while `config-lib-biome-check` and `config-lib-biome-format` run Biome over the copied shared package source. `.github/workflows/publish-crates.yml` copies the repository to a temporary clean workspace, enters that copy's Nix dev shell to generate `cli/package-fallback/`, and runs Cargo publication against the prepared copy so crates.io publish does not mutate repository artifacts. - The config-lib check source preserves repo-relative access to shared CLI patch fixtures: Nix copies a filtered repo-shaped source containing `config/lib/**` plus `cli/src/services/structured_patch/fixtures`, then runs Bun/Biome from `config/lib/`. - `flake.nix` exposes the **native** development package as `packages.sce` (`packages.default = packages.sce`) plus `apps.sce` and `apps.default`, all targeting `${packages.sce}/bin/sce`; this keeps repo-local and remote flake run/install flows (`nix run .`, `nix run github:crocoder-dev/shared-context-engineering`, `nix profile install github:crocoder-dev/shared-context-engineering`) aligned to the native CLI output. The static-musl release binary is a distinct output, `packages.sce-release` (`apps.sce-release`); see the native/release split note above and `context/sce/cli-release-artifact-contract.md`. - `biome.json` at the repository root is the canonical Biome configuration for the current JS tooling slice and deliberately scopes coverage to `npm/**` plus the shared `config/lib/**` plugin package root while excluding package-local `node_modules/**`; `flake.nix` exposes Biome through the default dev shell rather than through package-local installs. diff --git a/context/cli/config-precedence-contract.md b/context/cli/config-precedence-contract.md index 54c48e37..06e92f44 100644 --- a/context/cli/config-precedence-contract.md +++ b/context/cli/config-precedence-contract.md @@ -2,7 +2,7 @@ ## Scope -This contract documents the implemented `sce config` command behavior in `cli/src/services/config/mod.rs`, the runtime resolver in `cli/src/services/config/resolver.rs`, the text/JSON output renderer in `cli/src/services/config/render.rs`, the canonical Pkl-authored `sce/config.json` schema artifact generated to `config/schema/sce-config.schema.json` and embedded by `cli/src/services/config/schema.rs` as `SCE_CONFIG_SCHEMA_JSON`, the typed serde DTO + mapping pipeline used for config-file parsing, and parser/dispatch wiring in `cli/src/app.rs`. +This contract documents the implemented `sce config` command behavior, runtime resolver, renderer, and canonical Pkl-authored `sce/config.json` schema. The schema is emitted to payload-relative `config/schema/sce-config.schema.json` under Cargo `OUT_DIR` or packaging fallbacks and embedded by `cli/src/services/config/schema.rs` as `SCE_CONFIG_SCHEMA_JSON`; no generated schema is committed. The current implementation resolves flat logging keys with deterministic env-over-config precedence and source metadata, uses those resolved values in `cli/src/app.rs` / `cli/src/services/observability.rs` for runtime logging, exposes resolved-value inspection through `sce config show`, and keeps `sce config validate` focused on validation status plus errors/warnings. @@ -58,8 +58,8 @@ When a default-discovered global or repo-local config file exists but fails JSON ## Validation contract -- The canonical JSON Schema artifact for both global and repo-local `sce/config.json` files is authored in `config/pkl/base/sce-config-schema.pkl` and generated to `config/schema/sce-config.schema.json`. -- `cli/src/services/config/schema.rs` embeds that generated artifact at compile time as `SCE_CONFIG_SCHEMA_JSON` and uses it for runtime schema validation before mapping parsed files into typed serde DTOs. +- The canonical JSON Schema for both global and repo-local `sce/config.json` files is authored in `config/pkl/base/sce-config-schema.pkl` and generated beneath `OUT_DIR/pkl-generated/config/schema/sce-config.schema.json` for repository builds. +- `cli/src/services/config/schema.rs` embeds that `OUT_DIR` artifact at compile time as `SCE_CONFIG_SCHEMA_JSON`; packaged builds receive the same path from their validated fallback. - `sce config validate` and `sce doctor` both validate config-file structure against that shared generated schema before applying Rust-owned semantic checks such as duplicate custom `argv_prefix` detection and redundancy warnings. - After schema validation, `cli/src/services/config/schema.rs` deserializes top-level and nested config structure (`policies`, `policies.bash`, `policies.attribution_hooks`) into typed serde DTOs and applies focused Rust-owned mapping helpers for enum conversion and source attribution; policy-specific semantic checks are owned by `cli/src/services/config/policy.rs`. - The canonical top-level schema declaration `"$schema": "https://sce.crocoder.dev/config.json"` is a supported config key for both explicit and discovered `sce/config.json` files, including command-startup paths like `sce version` and other config-loading commands that parse config before normal command dispatch. @@ -129,7 +129,7 @@ When a default-discovered global or repo-local config file exists but fails JSON ## Related files - `config/pkl/base/sce-config-schema.pkl` -- `config/schema/sce-config.schema.json` +- `config/pkl/generate.pkl` - `cli/src/app.rs` - `cli/src/command_surface.rs` - `cli/src/services/config/mod.rs` diff --git a/context/cli/default-path-catalog.md b/context/cli/default-path-catalog.md index 09115685..4b468fa7 100644 --- a/context/cli/default-path-catalog.md +++ b/context/cli/default-path-catalog.md @@ -7,7 +7,6 @@ - per-user persisted paths - repo-relative CLI paths - install target paths -- embedded asset paths - context-document path constants used by CLI-owned workflows ## Current path families @@ -28,13 +27,13 @@ - `.git/`, `.git/hooks/`, `.git/COMMIT_EDITMSG` - `context/`, `context/plans/`, `context/decisions/`, `context/handovers/`, `context/tmp/` -### Embedded/install paths +### Install paths -- `assets/generated/config/` -- `assets/hooks/` - OpenCode plugin/catalog targets under `.opencode/` - required git hook install targets under `.git/hooks/` +Compile-time payload locations are build-script-owned `OUT_DIR` paths rather than default runtime paths and are intentionally absent from this catalog. + ## Contract - Production CLI code should define named path accessors or constants in `default_paths.rs`, not introduce new hardcoded path owners elsewhere. diff --git a/context/context-map.md b/context/context-map.md index 0fa9ac00..40284d19 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -10,7 +10,7 @@ Primary context files: Feature/domain context: - `context/cli/cli-command-surface.md` (CLI command surface including top-level help with ASCII art banner and gradient rendering, setup install flow, WorkOS device authorization flow + token storage behavior, attribution-only hook routing with validated post-commit `--remote-url` plumbing plus DB-backed `diff-trace` dual persistence and post-commit Agent Trace payload persistence including range `content_hash`, setup-owned local DB + repository-scoped Agent Trace DB bootstrap plus doctor DB health coverage with credential-safe repository identity diagnostics, centralized Rust SCE web URL helpers in `services::agent_trace`, nested flake release package/app installability, Cargo local install + crates.io readiness policy, and hidden `sce policy bash` command adapter for bash-policy hook callers; `sce sync` command wiring is deferred to `0.4.0`; static `RuntimeCommand` enum dispatch lives in `services/command_registry.rs`, command payload structs for help/version/completion/auth/config/setup/doctor/hooks/policy are owned by their respective `services/{name}/command.rs` files, and clap-to-runtime conversion lives in `services/parse/command_runtime.rs`) -- `context/cli/default-path-catalog.md` (canonical production CLI path-ownership contract centered on `cli/src/services/default_paths.rs`, including persisted auth/config files, named DB paths for auth/local/Agent Trace databases, repo-relative, embedded-asset, install, hook, and context-path families plus the regression guard that keeps production path ownership centralized) +- `context/cli/default-path-catalog.md` (canonical production CLI path-ownership contract centered on `cli/src/services/default_paths.rs`, including persisted auth/config files, named DB paths for auth/local/Agent Trace databases, repo-relative install/hook/context paths, the exclusion of build-time `OUT_DIR` payload paths, and the regression guard that keeps production path ownership centralized) - `context/cli/repository-identity.md` (repository identity module in `cli/src/services/repository_identity/`: pure scheme-neutral `host[:port]/path` canonicalization for SCP/`ssh://`/HTTPS/`git://` remote URLs with credential stripping, hostname lowercasing, default-port removal, and query/fragment/trailing-`.git` cleanup, trim-only explicit-identity handling, `sha256("sce-repository-id-v1\0" + canonical_identity)` repository IDs, credential-safe fieldless errors, plus the `resolve` runtime submodule applying explicit-config-then-configured-remote precedence with `git config --get remote..url` lookup, `RepositoryIdentitySource` provenance, and `.sce/config.json`-guidance resolution errors that never echo URLs; consumed by the T04 `agent_trace_storage` resolver) - `context/cli/agent-trace-storage.md` (repository-scoped Agent Trace storage resolver in `cli/src/services/agent_trace_storage/`: `AgentTraceStorageContext` inputs mirroring the `agent_trace.*` config keys, `ResolvedAgentTraceStorage` carrying repository identity + checkout ID + `/sce/repos//agent-trace.db` path + open `RepositoryAgentTraceDb`, `resolve_agent_trace_storage{,_at_state_root}` entrypoints with idempotent concurrent-safe first open via bounded fast-path-then-migrate retry plus narrow one-file schema migration-metadata repair and repository metadata validation, path-unsafe repository ID rejection in `default_paths::agent_trace_db_path_for_repository{,_at}`, strict never-touch boundary for any pre-migration checkout-scoped/global DB files, and active hook/runtime plus Agent Trace lifecycle setup call-site consumption after T08) - `context/cli/checkout-identity.md` (current checkout identity infrastructure in `cli/src/services/checkout/`, including `/sce/checkout-id` UUIDv7 storage, setup/hook integration that creates/reuses checkout identity as repository-scoped Agent Trace diagnostic metadata, the removed per-checkout DB opener/path helper, `sce doctor` checkout identity display, and the never-touch on-disk handling of pre-migration checkout-scoped DB files that are no longer inspectable via the CLI) @@ -46,7 +46,7 @@ Feature/domain context: - `context/sce/agent-trace-post-rewrite-local-remap-ingestion.md` (current post-rewrite no-op baseline plus historical remap-ingestion reference) - `context/sce/agent-trace-rewrite-trace-transformation.md` (current post-rewrite no-op baseline plus historical rewrite-transformation reference) - `context/sce/local-db.md` (implemented `cli/src/services/local_db/mod.rs` local database spec with `LocalDb = TursoDb`, canonical local DB path resolution, zero local migrations, and inherited retry-backed blocking `execute`/`query`/`query_map` methods using the shared Turso adapter) -- `context/sce/shared-turso-db.md` (current shared `cli/src/services/db/mod.rs` Turso database infrastructure seam, including `DbSpec`, generic `TursoDb`, encrypted `EncryptedTursoDb`, build-time generated migration constants from `cli/build.rs`/`cli/src/generated_migrations.rs`, config-driven constructor/open-connect retry via `run_with_retry_sync`, no-migration `TursoDb::open_without_migrations()` / explicit-path `open_without_migrations_at(path)` for hot runtime paths, migration-running `new()` / explicit-path `new_at(path)` / `run_migrations()` with per-database `__sce_migrations` tracking, config-driven operation retry for `execute`/`query`/`query_values`/`query_map` with a `<= 2_000ms` default query failure budget, raw-value row fetching for deterministic operator-facing rendering, row-mapping excluded from retry, generic embedded migration execution, non-mutating `migration_metadata_problems()` and `ensure_schema_ready(setup_guidance)` readiness methods on `TursoDb`, and concrete wrappers for `LocalDb`, `AuthDb`, plus `RepositoryAgentTraceDb`) +- `context/sce/shared-turso-db.md` (current shared `cli/src/services/db/mod.rs` Turso database infrastructure seam, including `DbSpec`, generic `TursoDb`, encrypted `EncryptedTursoDb`, build-time generated migration constants from `cli/build.rs`/Cargo `OUT_DIR`, config-driven constructor/open-connect retry via `run_with_retry_sync`, no-migration `TursoDb::open_without_migrations()` / explicit-path `open_without_migrations_at(path)` for hot runtime paths, migration-running `new()` / explicit-path `new_at(path)` / `run_migrations()` with per-database `__sce_migrations` tracking, config-driven operation retry for `execute`/`query`/`query_values`/`query_map` with a `<= 2_000ms` default query failure budget, raw-value row fetching for deterministic operator-facing rendering, row-mapping excluded from retry, generic embedded migration execution, non-mutating `migration_metadata_problems()` and `ensure_schema_ready(setup_guidance)` readiness methods on `TursoDb`, and concrete wrappers for `LocalDb`, `AuthDb`, plus `RepositoryAgentTraceDb`) - `context/sce/auth-db.md` (encrypted `AuthDb = EncryptedTursoDb` adapter, canonical `/sce/auth.db` path, build-time generated `AUTH_MIGRATIONS` from `cli/migrations/auth/`, auth credential schema and updated-at trigger baseline, lifecycle setup/doctor integration, encrypted token-storage persistence, and `SCE_AUTH_DB_ENCRYPTION_KEY`/OS credential-store key handling) - `context/sce/agent-trace-db.md` (implemented Agent Trace database adapter: the sole repository-scoped `RepositoryAgentTraceDb` backed by one fresh multi-statement schema file with `repository_metadata` validation, narrow concurrent-first-open repair for missing one-file baseline migration metadata after all required schema tables exist, no trace-table `checkout_id` columns, repository-level typed insert helpers for diff traces, post-commit intersections, Agent Trace rows, messages, and parts, repository-level recent diff-trace reads without checkout filtering, on-demand command/hook initialization with no daemon/background service, and the never-touch on-disk boundary for any pre-migration checkout-scoped/global DB files; the checkout-scoped `AgentTraceDb` adapter, its `agent_trace_db_path()`/`agent_trace_db_path_for_checkout()` helpers, and the 15-file `cli/migrations/agent-trace/` chain were removed by the `retire-legacy-agent-trace-db` plan; active hook writers/readers and Agent Trace setup/lifecycle resolve repository storage through `agent_trace_storage`) - `context/sce/agent-trace-core-schema-migrations.md` (historical reference for removed local DB schema bootstrap behavior; T03 now implements the actual local DB with migrations) @@ -56,15 +56,15 @@ Feature/domain context: - `context/sce/agent-trace-hooks-command-routing.md` (implemented `sce hooks` command routing plus current runtime behavior: enabled-by-default commit-msg attribution with explicit opt-out controls, no-op `pre-commit`/`post-rewrite` entrypoints, active `post-commit` intersection and Agent Trace DB persistence, DB-only `diff-trace` STDIN intake with OpenCode normalized payloads and Claude structured `PostToolUse` payload classification, tool-prefixed stored `diff_traces.session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), direct nullable `model_id`/`tool_version` persistence without session fallback, Claude direct model metadata extraction from top-level or nested `model` fields with `claude/` prefix normalization, no parsed-payload artifact persistence under `context/tmp`, `session-model` removed from the supported hook surface, and `conversation-trace` STDIN intake for normalized batches plus supported raw Claude events; this document also owns the current `diff-trace` and `conversation-trace` fail-open intake contracts.) - `context/sce/bash-tool-policy-enforcement-contract.md` (approved bash-tool blocking contract plus current Rust evaluator seam and OpenCode/Claude delegation references, including config schema, argv-prefix matching, shell/nix unwrapping, custom-policy `satisfied_by` wrapper exemption, fixed preset catalog/messages, and precedence rules) - `context/sce/bash-policy-satisfied-by-wrapper-exemption.md` (custom-policy `satisfied_by` field: optional list of wrapper argv prefixes that exempt a policy from firing when the matched command was unwrapped from one of them; `NormalizedSegment` wrapper-chain tracking, matching model, examples, and scope) -- `context/sce/generated-opencode-plugin-registration.md` (current generated OpenCode plugin-registration contract, canonical Pkl ownership, generated manifest/plugin paths including `sce-bash-policy` + `sce-agent-trace`, TypeScript source ownership, and Claude generated settings boundary including Agent Trace hooks plus `PreToolUse` Bash policy hook registration through the missing-CLI install-guidance helper) -- `context/sce/pi-extension-runtime.md` (project-local Pi extension runtime: `config/lib/pi-plugin/sce-pi-extension.ts` emitted verbatim to `config/.pi/extensions/sce/index.ts`, Pi auto-discovery registration model with no manifest, implemented bash policy adapter delegating to `sce policy bash` with block-by-return `{ block, reason }` and fail-open behavior, implemented `message_end` conversation text capture piping mixed `message`/`message.part` batches (text + reasoning parts, `responseId`-or-random message IDs) to `sce hooks conversation-trace` fail-open, and implemented edit/write diff capture producing `git diff --no-index` unified diffs emitted as synthetic-message `patch` conversation parts plus normalized `sce hooks diff-trace` payloads with `tool_name: "pi"`, nullable `model_id`/`tool_version`, Rust-side `pi_` stored session-ID prefixing, and asset-pipeline shipping — whole-tree sync into `cli/assets/generated/config/pi/`, embedded install via `sce setup --pi`, and `sce doctor` `Pi extensions` health group) +- `context/sce/generated-opencode-plugin-registration.md` (canonical Pkl ownership and ephemeral OpenCode payload layout for `opencode.json`, `sce-bash-policy`, and `sce-agent-trace`, plus the Claude generated settings boundary) +- `context/sce/pi-extension-runtime.md` (project-local Pi extension runtime: `config/lib/pi-plugin/sce-pi-extension.ts` emitted verbatim to `config/.pi/extensions/sce/index.ts`, Pi auto-discovery registration model with no manifest, implemented bash policy adapter delegating to `sce policy bash` with block-by-return `{ block, reason }` and fail-open behavior, implemented `message_end` conversation text capture piping mixed `message`/`message.part` batches (text + reasoning parts, `responseId`-or-random message IDs) to `sce hooks conversation-trace` fail-open, and implemented edit/write diff capture producing `git diff --no-index` unified diffs emitted as synthetic-message `patch` conversation parts plus normalized `sce hooks diff-trace` payloads with `tool_name: "pi"`, nullable `model_id`/`tool_version`, Rust-side `pi_` stored session-ID prefixing, and asset-pipeline shipping — direct Pkl generation into Cargo `OUT_DIR` for repository builds, embedded install via `sce setup --pi`, and `sce doctor` `Pi extensions` health group) - `context/sce/opencode-agent-trace-plugin-runtime.md` (current OpenCode agent-trace plugin runtime behavior, including captured `message.updated` handoff with `summary.diffs` branching: when diffs exist sends one `-patch` mixed batch containing a synthetic parent message plus per-diff `message.part` patch items, when no diffs sends the original `message.updated` payload; in-memory dedup `Set` keyed by `"${sessionID}:${messageID}"`; captured `message.part.updated` handoff to `sce hooks conversation-trace` for `text`/`reasoning` parts with non-empty text plus completed `question` tool parts emitted as `part_type: "question"` with JSON-stringified `{ question, answer }[]`; existing user-message diff extraction for `{ sessionID, diff, time, model_id }`; session-scoped OpenCode client version capture from `session.created`/`session.updated`; and CLI handoff to `sce hooks diff-trace` over STDIN JSON with required `tool_name="opencode"` plus required nullable `tool_version`; Rust hook parsing and AgentTraceDb insertion persist `oc_`-prefixed session IDs plus required payload fields including `model_id`) -- `context/sce/cli-first-install-channels-contract.md` (current `sce` install/distribution contract covering supported Nix/Cargo/npm plus source-built Flatpak channel scope, implemented GitHub Release Flatpak source-manifest and source-built `.flatpak` bundle asset packaging, canonical `.version` release authority, manual GitHub Release `prerelease` checkbox behavior, Nix-owned build/release policy, Nix-owned Flatpak manifest generation via `pkgs.formats.yaml.generate` plus Nix-owned cargo-sources generation from `cli/Cargo.lock` plus dedicated Nix-built Bash validator scripts for static, version-parity, and local-manifest validation, thin imperative `packaging/flatpak/sce-flatpak.sh` orchestration around `flatpak-builder` / `flatpak build-bundle`, the reduced Linux flake app surface (`sce-flatpak`, `release-flatpak-package`, `release-flatpak-bundle`, plus `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers) with `flatpak-static-validation` / `flatpak-manifest-parity` / `cargo-sources-parity` checks, the implemented `packaging/flatpak/dev.crocoder.sce.yml` + AppStream/Cargo-source packaging surface as generated artifacts, and the `dev.crocoder.sce` host-git bridge decision) +- `context/sce/cli-first-install-channels-contract.md` (current Nix/Cargo/npm/source-built Flatpak channel contract, release authority and workflow topology, Nix-owned Flatpak manifest/cargo-source generation and validation, reduced Flatpak app surface, and host-git bridge decision) - `context/sce/cli-release-artifact-contract.md` (shared `sce` binary release artifact naming, checksum/manifest outputs, pre-archive staged-binary preparation including macOS `libiconv` install-name sanitization/ad-hoc re-signing, native portability audit app/check for forbidden `/nix/store/` runtime references, GitHub Releases as the canonical artifact publication surface, manual dispatch `prerelease` flag behavior, the current three-target Linux/macOS release workflow topology including pre-upload extracted-archive smoke/audit validation in each native lane, implemented Flatpak source-manifest and source-built `.flatpak` bundle package assets uploaded by `.github/workflows/release-sce.yml`, and Flatpak's explicit source-built non-binary exception) - `context/sce/cli-npm-distribution-contract.md` (implemented `sce` npm launcher package, release-manifest/checksum-verified native binary install flow, the supported darwin/arm64 plus linux x64+arm64 npm platform matrix, the prerequisite that npm-consumed native archives are portable and free of forbidden `/nix/store/` runtime references before upload, and dedicated `.github/workflows/publish-npm.yml` downstream npm publish-stage contract including prerelease publication via npm `next` dist-tag instead of `latest`) -- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io, git, and local checkout install guidance, dedicated crates.io publish workflow with semver prerelease guard, and ephemeral crate-local generated-asset mirror requirement for published builds) +- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io, git, and local checkout install guidance, dedicated crates.io publish workflow with semver prerelease guard, direct repository Pkl-to-`OUT_DIR` generation, and the deterministic checksummed packaging-only fallback used for Pkl-free downstream crate builds) - `context/sce/flake-build-performance.md` (current native-vs-release package split, release-only commit embedding, slim default/database devShell contract, normal-vs-expensive CI tiers, durable before/after benchmark summary, validation evidence, and remaining cold-build trade-offs) -- `context/sce/flatpak-distribution-patterns.md` (implementation conventions for the source-built `dev.crocoder.sce` Flatpak channel: manifest generation, flake app surface, local and release builds, release assets, runtime Git access via host-git bridge, and general distribution patterns) +- `context/sce/flatpak-distribution-patterns.md` (source-built Flatpak conventions, including Nix-side ephemeral fallback preparation for the Pkl-free build sandbox, manifest generation, local/release builds, release assets, and host-git bridge) Working areas: @@ -81,7 +81,8 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` -- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (current workflow-oriented generated target matrix; supersedes the 2026-02-28 paired-output inventory while retaining canonical Pkl ownership) +- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (current workflow-oriented target matrix and canonical Pkl ownership) +- `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes Cargo `OUT_DIR` generation plus crates.io/Flatpak packaging fallbacks) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) - `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md` (retire the checkout-scoped Agent Trace DB surface; `RepositoryAgentTraceDb` is the sole adapter, no `sce trace --legacy`, no global/checkout fallback path; pre-migration on-disk files are never touched and no longer inspectable via the CLI) diff --git a/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md b/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md new file mode 100644 index 00000000..92c0a672 --- /dev/null +++ b/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md @@ -0,0 +1,28 @@ +# Decision: Generate Pkl Payloads Ephemerally for Builds and Packages + +Date: 2026-07-27 +Status: Accepted +Plan: `context/plans/generate-cli-assets-in-cargo-out-dir.md` + +## Decision + +- Keep `config/pkl/` and referenced `config/lib/` files as the canonical authoring sources. +- Do not commit generated `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, or `cli/assets/generated` outputs. +- Repository and Nix/Crane Cargo builds evaluate `config/pkl/generate.pkl` directly into Cargo `OUT_DIR`; `cli/build.rs` stages non-Pkl hooks, schemas, and migrations there and production Rust embeds only from `OUT_DIR`. +- `nix run .#pkl-check-generated` validates metadata coverage, required outputs, forbidden repository paths, and deterministic two-pass temporary inventories rather than comparing committed snapshots. +- Published crates and source-built Flatpak packages may carry a checksummed packaging-only fallback generated from canonical Pkl in a temporary clean workspace. Downstream Pkl-free builds validate and copy that payload into their own `OUT_DIR`. + +## Rationale + +Committed target trees duplicated canonical Pkl ownership, made source filters and release helpers depend on snapshots, and allowed generated source artifacts to drift from the build that embedded them. Build-local generation keeps one authoring source and makes the exact payload part of each Cargo build. Packaging-only fallbacks preserve Pkl-free crates.io and Flatpak consumers without restoring repository mirrors or bundling a Pkl evaluator. + +## Consequences + +- Generated path names remain stable payload-relative install layouts, but they appear only under temporary generation roots, Cargo `OUT_DIR`, crate/Flatpak staging directories, and final `sce setup` destinations. +- Crane source filters include canonical Pkl, referenced plugin/extension sources, and static inputs; Pkl is a native build input for repository package/test/clippy derivations. +- Flatpak helpers prepare `cli-package-fallback/` before entering the sandbox, and manifests copy it to `cli/package-fallback` as a `type: dir` source. +- Contributor workflows inspect temporary output and must not run Pkl generation with repository root as the output directory. + +## Superseded scope + +This decision supersedes the checked-in generated-output ownership and snapshot-parity portions of `2026-07-27-workflow-oriented-pkl-generation.md`. That decision's workflow matrix, canonical Pkl ownership, renderer boundaries, and exact target inventory remain in force. diff --git a/context/glossary.md b/context/glossary.md index 03eb624c..7bfa1ace 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -1,12 +1,12 @@ # Glossary -- `pkl-check-generated`: Flake app command exposed as `nix run .#pkl-check-generated`; canonical lightweight parity entrypoint that evaluates the exact workflow-document inventory, compares complete generated OpenCode/Claude/Pi directories plus retained scalar/schema outputs, and rejects explicitly removed generated trees inside the Nix dev shell. +- `pkl-check-generated`: Flake app exposed as `nix run .#pkl-check-generated`; canonical ephemeral-generation check that rejects committed target/schema/mirror outputs, evaluates exact workflow-document coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. - `repo-level verification preference`: Current repository guidance that contributor-facing validation/check flows should prefer `nix flake check`; direct Cargo verification commands are secondary and used only when explicitly requested or for narrow targeted debugging, while `cargo fmt` remains the explicit autofix path. - lightweight post-task verification baseline: Required quick checks after each completed task in this repo: `nix run .#pkl-check-generated` and `nix flake check`. - disposable plan lifecycle: Policy where `context/plans/` holds active execution artifacts only; completed plans are disposable and durable outcomes must be reflected in current-state context files and/or `context/decisions/`. - important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. -- generated-owned outputs: Files materialized by `config/pkl/generate.pkl` under `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**`, including OpenCode plugin entrypoints and `opencode.json`, Claude hook/settings assets, Pi prompt/skill assets, and the Pi extension entrypoint at `config/.pi/extensions/sce/index.ts`; `config/automated/.opencode/**` is explicitly removed from generation ownership. +- ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, and `/validate` this way and has no generated agent-role prompts. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. @@ -15,16 +15,16 @@ - `checkout registry` (removed): The central JSON registry at `/sce/checkout-registry.json` was removed in the `remove-checkout-registry` plan. `sce trace db list` now discovers checkouts by scanning `/sce/agent-trace-*.db` files on disk. `checkout_id`, `database_path`, and `last_seen` (from file mtime) are derived from the filesystem; `path` and `remote_url` are no longer rendered. See `context/cli/checkout-identity.md`. - `generated OpenCode plugin registration contract`: Current generated-config contract where `config/.opencode/opencode.json` serializes the OpenCode `plugin` field from canonical Pkl sources for SCE-managed plugins only; the current registered paths are `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts`. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`. - `root Biome contract`: Repository-root formatting/linting contract owned by `biome.json`, currently scoped only to `npm/**` and the shared `config/lib/**` plugin package root with package-local `node_modules/**` excluded; the canonical execution path is the root Nix dev shell (`nix develop -c biome ...`). -- `cli flake checks`: Check derivations in root `flake.nix` (`checks..cli-tests`, `cli-clippy`, `cli-fmt`), plus `pkl-parity`, `workflow-actionlint`, split `npm/` JS checks (`npm-bun-tests`, `npm-biome-check`, `npm-biome-format`), split shared `config/lib/` JS checks (`config-lib-bun-tests`, `config-lib-biome-check`, `config-lib-biome-format`), and Linux-only Flatpak checks; invoked via `nix flake check` at repo root. +- `cli flake checks`: Check derivations in root `flake.nix` (`checks..cli-tests`, `cli-clippy`, `cli-fmt`), plus `pkl-generated`, `workflow-actionlint`, split npm/config-lib JS checks, and Linux-only Flatpak checks; invoked via `nix flake check` at repo root. - `npm JS flake checks`: The current `npm/` validation slice exposed by root `flake.nix`: `npm-bun-tests` runs only `bun test ./test/*.test.js`, `npm-biome-check` runs only Biome lint/check with formatter verification disabled, and `npm-biome-format` runs only Biome format verification with linter checks disabled. - `config-lib JS flake checks`: The current shared `config/lib/` validation slice exposed by root `flake.nix`: `config-lib-bun-tests` runs Bun-discovered tests from the copied shared `config/lib/` package source (including bash-policy plugin wrapper tests and tracked agent-trace plugin tests), with dependencies resolved from `config/lib/package.json` and `config/lib/bun.lock`, while `config-lib-biome-check` and `config-lib-biome-format` run Biome lint/check and format verification over the copied shared package source with formatter/linter halves disabled respectively. - `config-lib repo-shaped test source`: Root-flake source-layout contract where `config-lib-bun-tests`, `config-lib-biome-check`, and `config-lib-biome-format` run from `config/lib/` while their copied Nix source preserves repo-relative shared fixtures, currently `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden tests (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). - `config-lib shared package root`: Shared Bun/TypeScript package root at `config/lib/` for repository-owned OpenCode plugin support code. It owns `package.json`, `bun.lock`, and `tsconfig.json`, pins `@opencode-ai/plugin` to `1.15.4`, includes both `agent-trace-plugin/**/*.ts` and `bash-policy-plugin/**/*.ts` in strict TypeScript coverage, and excludes package-local `node_modules/` from both TypeScript and root Biome coverage. - `cli rust overlay toolchain`: Toolchain contract in root `flake.nix` that applies `rust-overlay.overlays.default`, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, uses that toolchain across both Crane package and check derivations, and keeps toolchain selection explicit rather than inheriting nixpkgs defaults. -- `cli Crane package pipeline`: Current root-flake packaging path in `flake.nix` where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage` against a filtered repo-root source that preserves the Cargo tree and the embedded config/assets required by `cli/build.rs`. +- `cli Crane package pipeline`: Root-flake packaging path where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage` against a filtered repo source containing the Cargo tree, canonical Pkl/referenced plugin inputs, and static build inputs; Pkl runs in `cli/build.rs` and embeds only from Cargo `OUT_DIR`. - `cli Crane check pipeline`: Current root-flake check path in `flake.nix` where `cli-tests`, `cli-clippy`, and `cli-fmt` run through `craneLib.cargoTest`, `craneLib.cargoClippy`, and `craneLib.cargoFmt`; test and clippy derivations reuse the shared `cargoArtifacts` dependency cache from the package pipeline. - `repo-root .version contract`: Repository packaging/version-source contract where `.version` stores the canonical semver string for flake-evaluated CLI package/check metadata and the approved release version authority for GitHub Releases, Cargo publication, and npm publication; `flake.nix` trims and reuses that value instead of hardcoding a version literal, and staged generated-config workflows must mirror it when Pkl renderers read the same path. -- `Flatpak source-manifest GitHub Release asset`: Implemented non-binary release asset set for the source-built `dev.crocoder.sce` Flatpak channel: `sce-v-flatpak-manifest.tar.gz`, `sce-v-flatpak-manifest.tar.gz.sha256`, and `sce-v-flatpak.json`, emitted by `nix run .#release-flatpak-package` and uploaded by `.github/workflows/release-sce.yml` from `dist/flatpak`. The tarball packages Flatpak manifest/support files (`dev.crocoder.sce.yml`, AppStream metadata, `cargo-sources.json`, and `git-host-bridge`) with the staged manifest pinned to the release commit; it is not a prebuilt `sce` binary, `.flatpak` bundle, OSTree repository, or Flathub publication. +- `Flatpak source-manifest GitHub Release asset`: Non-binary release asset set for source-built `dev.crocoder.sce`: the manifest tarball, checksum, and JSON metadata emitted by `nix run .#release-flatpak-package`. The tarball contains manifest/support files plus an ephemeral checksummed `cli-package-fallback/`; Flatpak copies that directory to `cli/package-fallback` before its offline Cargo source build, so no Pkl executable or prebuilt `sce` binary is bundled. - `Flatpak bundle GitHub Release asset`: Implemented source-built `.flatpak` bundle release asset set for the `dev.crocoder.sce` Flatpak channel: `sce-v-x86_64.flatpak`, `sce-v-aarch64.flatpak`, plus per-architecture `.sha256` and `.json` metadata, built from source inside Flatpak using `flatpak-builder` + `flatpak build-bundle`. The bundle is a source-built Flatpak app for direct install (`flatpak install --user `), not a prebuilt binary or Flathub submission. These assets coexist with the existing Flatpak source-manifest packaging metadata on GitHub Releases. The `release-bundle` command is implemented in `packaging/flatpak/sce-flatpak.sh` and the GitHub workflow upload is implemented in `.github/workflows/release-sce-linux.yml` / `release-sce-linux-arm.yml` (x86_64/aarch64), assembled by `release-sce.yml`. - `cli flake native package`: Root-flake package output exposed as `packages.sce` with `packages.default = packages.sce`, producing the **native** development `sce` binary (`scePackage`) via `nix build .#sce` / `nix build .#default`. - `cli flake release package`: Root-flake package output exposed as `packages.sce-release` (`sceReleasePackage`): the static-musl release binary (`scePackageMusl`) on Linux and a dedicated native-toolchain build (`sceReleasePackageNative`) on Darwin, built via `nix build .#sce-release`. On Linux it is a distinct store path from `packages.sce` and passes the native portability audit; on Darwin it is likewise distinct from `packages.sce` because it embeds the commit (see `release-only Git-commit embedding`). `nix run .#release-artifacts` builds through this output. @@ -64,7 +64,7 @@ - `DB connection-open retry policy`: Retry policy used by `TursoDb::new()` and `EncryptedTursoDb::new()` for local Turso open/connect, resolved at app startup from `policies.database_retry..connection_open` via the `DATABASE_RETRY_CONFIG` `OnceLock` with fallback to hardcoded defaults (`3` attempts, `1s` elapsed-attempt timeout, `25ms` initial backoff, `200ms` max backoff) through `run_with_retry_sync`; embedded migrations are not covered by this policy. - `DB query retry policy`: Retry policy used by `TursoDb::execute()`, `TursoDb::query()`, `TursoDb::query_map()`, `EncryptedTursoDb::execute()`, `EncryptedTursoDb::query()`, and `EncryptedTursoDb::query_map()` for local Turso operation retry, resolved from `policies.database_retry..query` via the `DATABASE_RETRY_CONFIG` `OnceLock` with fallback to hardcoded defaults (`5` attempts, `200ms` elapsed-attempt timeout, `25ms` initial backoff, `100ms` max backoff; default worst-case failure budget `<= 2_000ms`) through `run_with_retry_sync`. `query_map()` retries the initial query and row-fetch loop, then runs caller row mapping outside retry. - `__sce_migrations`: Per-database migration metadata table created by the shared `TursoConnectionCore` migration path behind public adapter `run_migrations()` methods; records applied migration IDs after successful execution so later setup/lifecycle initialization applies only migrations not yet recorded, while existing metadata-less DBs are brought forward by re-applying the current idempotent migration set and recording each ID. -- `CLI generated migration manifest`: Build-time Rust source at `cli/src/generated_migrations.rs` written by `cli/build.rs` from immediate `cli/migrations//*.sql` directories; constants are named from the database directory (for example `AGENT_TRACE_REPOSITORY_MIGRATIONS`, `AUTH_MIGRATIONS`), sorted by the numeric filename prefix before `_`, and embed SQL via `include_str!`. +- `CLI generated migration manifest`: Build-time Rust source at `OUT_DIR/generated_migrations.rs` written by `cli/build.rs` from immediate `cli/migrations//*.sql` directories after staging SQL under `OUT_DIR/static/migrations`; constants are named from the database directory (for example `AGENT_TRACE_REPOSITORY_MIGRATIONS`, `AUTH_MIGRATIONS`), sorted by the numeric filename prefix before `_`, and embed staged SQL via `include_str!`. - `sync command deferral`: Current plan/state note that a user-invocable `sce sync` command is not wired yet and is deferred to `0.4.0`; local DB bootstrap and setup-time repository-scoped Agent Trace DB initialization flow through lifecycle providers aggregated by the setup command, while hook runtime keeps a lazy repository Agent Trace DB fallback for repositories where setup has not run or schema metadata is incomplete, and DB health/repair flows through the doctor surface. - `CLI bounded resilience wrapper`: Shared policy in `cli/src/services/resilience.rs` (`RetryPolicy`, async `run_with_retry`, sync `run_with_retry_sync`) that applies deterministic retries/timeouts/capped backoff to transient operations, emits retry observability events, and returns actionable terminal failure guidance. The sync helper is currently wired into shared database constructors for local open/connect retry and into `TursoDb`/`EncryptedTursoDb` operation retry for `execute()`/`query()`/`query_map()`. - `setup service orchestration`: Setup execution logic in `cli/src/services/setup/command.rs` that resolves the repository root, derives a repo-root-scoped `AppContext` from the runtime command context, dispatches `setup` through the static lifecycle provider catalog (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive target selection for config asset installation, and emits deterministic success messaging per target. @@ -72,7 +72,7 @@ - `setup mode contract`: `cli/src/services/setup/mod.rs` model where `SetupMode::Interactive` is the default and `SetupMode::NonInteractive(SetupTarget)` is selected only when exactly one target flag is provided. - `setup interactive target prompt`: `inquire::Select` flow in `cli/src/services/setup/mod.rs` (`InquireSetupTargetPrompter`) that presents OpenCode, Claude, Pi, and All (OpenCode + Claude + Pi) when `sce setup` runs without target flags. - `setup dispatch outcome`: Execution model in `cli/src/services/setup/mod.rs` (`SetupDispatch`) where setup either proceeds with a selected/non-interactive target or exits as cancelled without file changes. -- `setup embedded asset manifest`: Compile-time generated file index emitted by `cli/build.rs` into `OUT_DIR/setup_embedded_assets.rs`, embedding bytes from `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `cli/assets/hooks/**` (via the synced `cli/assets/generated/config/{opencode,claude,pi}` mirrors) as deterministic normalized relative-path entries consumed by `cli/src/services/setup/mod.rs`; `OPENCODE_EMBEDDED_ASSETS`, `CLAUDE_EMBEDDED_ASSETS`, and `PI_EMBEDDED_ASSETS` all back live setup targets. +- `setup embedded asset manifest`: Compile-time generated file index emitted by `cli/build.rs` into `OUT_DIR/setup_embedded_assets.rs`, embedding bytes from Pkl-generated `OUT_DIR/pkl-generated/config/.{opencode,claude,pi}/**` plus staged `OUT_DIR/static/hooks/**` as deterministic normalized relative-path entries consumed by `cli/src/services/setup/mod.rs`; `OPENCODE_EMBEDDED_ASSETS`, `CLAUDE_EMBEDDED_ASSETS`, and `PI_EMBEDDED_ASSETS` all back live setup targets. - `setup required-hook embedded assets`: Setup-service accessors in `cli/src/services/setup/mod.rs` (`iter_required_hook_assets`, `get_required_hook_asset`) that expose canonical embedded templates for `pre-commit`, `commit-msg`, and `post-commit` without runtime config reads. - `setup required-hook install orchestration`: Setup-service flow in `cli/src/services/setup/mod.rs` (`install_required_git_hooks`) that resolves repository root + effective hooks directory via git truth, installs canonical required hooks with deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`), enforces executable permissions, and uses a unified remove-and-replace policy that removes existing hooks before swapping staged content with deterministic recovery guidance on swap failure. - `setup hooks CLI mode`: `sce setup` behavior activated by `--hooks` (with optional `--repo `), supporting both hooks-only runs and composable target+hooks runs in one invocation; implemented through `cli/src/services/setup/command.rs` + `cli/src/services/setup/mod.rs`, enforces deterministic compatibility validation (`--repo` requires `--hooks`; target flags remain mutually exclusive), and emits stable setup/hook status output. @@ -105,7 +105,7 @@ - `sce completion command surface`: Implemented top-level CLI command routed by `cli/src/app.rs` to `cli/src/services/completion/mod.rs` plus `cli/src/services/completion/command.rs`, requiring `--shell ` and returning a deterministic shell completion script on stdout. - `sce shared output-format contract`: Canonical parser contract in `cli/src/services/output_format.rs` (`OutputFormat`) that centralizes supported `--format` values (`text`, `json`) and emits command-specific actionable invalid-value guidance (`Run ' --help' ...`) for commands wired to dual-output rendering. - `sce shell completion contract`: Deterministic CLI completion contract where `sce completion --shell ` emits parser-aligned Bash/Zsh/Fish completion scripts for current top-level commands and supported options/subcommands. -- `CLI default path catalog`: Canonical production path-ownership contract in `cli/src/services/default_paths.rs`; it is the shared owner for non-test production CLI path definitions, covering per-user persisted paths plus repo-relative, embedded-asset, install, hook, and context-path definitions used by production CLI code. +- `CLI default path catalog`: Canonical production path-ownership contract in `cli/src/services/default_paths.rs`; it is the shared owner for non-test production CLI path definitions, covering per-user persisted paths plus repo-relative, install, hook, and context-path definitions used by production CLI code; build-time payload paths are `OUT_DIR`-owned and excluded. - `SCE web URL owner`: Rust service module at `cli/src/services/agent_trace.rs`; owns `SCE_WEB_BASE_URL = "https://sce.crocoder.dev"` and helper functions for SCE-owned URL construction, including Agent Trace conversation URLs, persisted Agent Trace trace URLs, Agent Trace session URLs, and setup-created config schema URLs. - `CLI capability traits`: Broad capability seam in `cli/src/services/capabilities.rs` consumed by the borrowed, compile-time-typed `AppContext`. `FsOps`/`StdFsOps` wrap filesystem operations and `GitOps`/`ProcessGitOps` wrap git process execution plus repository-root and hooks-directory resolution; current service internals do not consume them directly yet. - `FsOps`: Filesystem capability trait in `cli/src/services/capabilities.rs` with `read_file`, `write_file`, `metadata`, and `exists`, implemented in production by `StdFsOps`. @@ -117,7 +117,7 @@ - `config policy semantic validation seam`: Canonical ownership in `cli/src/services/config/policy.rs` for the CLI's bash-policy and attribution-hooks semantic validation, merge helpers, and policy rendering: built-in/custom bash-policy catalog types and OnceLock (`BuiltinBashPolicyCatalog`, `BuiltinBashPolicyPreset`, `BuiltinBashPolicyMatcher`, `BuiltinBashPolicyRedundancyWarning`, `BUILTIN_BASH_POLICY_CATALOG`, `BASH_POLICY_PRESET_CATALOG_JSON`), policy config types (`BashPolicyConfig`, `CustomBashPolicyEntry`), catalog accessors (`builtin_bash_policy_catalog`, `builtin_bash_policy_preset_ids`, `is_builtin_bash_policy_preset_id`), policy parsing and validation (`parse_bash_policy_presets`, `parse_custom_bash_policies`, `parse_custom_bash_policy_entry`, `parse_custom_bash_policy_match`, `parse_custom_bash_policy_argv_prefix`), policy resolution (`resolve_bash_policy_config`, `build_validation_warnings`), and policy rendering (`format_bash_policies_text`, `format_bash_policies_json`); `mod.rs` imports `BashPolicyConfig`, `build_validation_warnings`, `format_bash_policies_json`, `format_bash_policies_text`, and `resolve_bash_policy_config` from `policy` for resolution and rendering consumers. - `config runtime resolver seam`: Canonical ownership in `cli/src/services/config/resolver.rs` for config-file discovery, file-layer merging, env/flag/default precedence resolution, shared auth-key resolution (`workos_client_id`), observability runtime resolution, attribution-hooks gate resolution, and default-discovered invalid-file degradation; `cli/src/services/config/mod.rs` delegates `sce config show|validate` runtime resolution to this seam while facade re-exports preserve startup/auth/hooks callers through `services::config`. - `config render seam`: Canonical ownership in `cli/src/services/config/render.rs` for `sce config show` and `sce config validate` text/JSON output construction, including rendering-specific config-path formatting, resolved-value formatting, validation issue/warning rendering, and auth display-value redaction/abbreviation helpers; `cli/src/services/config/mod.rs` delegates rendering to this private submodule after resolver-owned runtime config resolution. -- `sce config schema artifact`: Canonical JSON Schema for global and repo-local `sce/config.json` files, authored in `config/pkl/base/sce-config-schema.pkl`, generated to `config/schema/sce-config.schema.json`, and embedded by `cli/src/services/config/schema.rs` for shared `sce config validate` and doctor config validation. The current schema accepts the canonical `$schema` declaration, flat logging keys (`log_level`, `log_format`, `log_file`, `log_file_mode`), existing auth/config keys, and enforces the schema-level dependency that `log_file_mode` requires `log_file`. +- `sce config schema artifact`: Canonical JSON Schema for global and repo-local `sce/config.json` files, authored in `config/pkl/base/sce-config-schema.pkl`, generated to payload-relative `config/schema/sce-config.schema.json` beneath Cargo `OUT_DIR` or packaging fallback roots, and embedded by `cli/src/services/config/schema.rs` for shared `sce config validate` and doctor config validation. The current schema accepts the canonical `$schema` declaration, flat logging keys (`log_level`, `log_format`, `log_file`, `log_file_mode`), existing auth/config keys, and enforces the schema-level dependency that `log_file_mode` requires `log_file`. - `bash tool policy config surface`: Nested repo config namespace under `.sce/config.json` at `policies.bash`, currently supporting unique built-in `presets` plus repo-owned `custom` argv-prefix rules with deterministic validation, merged global/local resolution, and first-class `sce config show|validate` reporting. - `attribution hooks gate`: Enabled-by-default local hook runtime gate resolved through shared config precedence in `cli/src/services/config/mod.rs` (with parsing in `schema.rs`): opt-out env `SCE_ATTRIBUTION_HOOKS_DISABLED` overrides repo/global config key `policies.attribution_hooks.enabled` with inverted semantics, and the current enabled path activates commit-msg-only attribution gated by the staged-diff AI-overlap preflight. - `StagedDiffAiOverlapResult`: Three-valued enum in `cli/src/services/hooks/mod.rs` returned by the staged-diff AI-overlap evidence check: `Overlap` (staged diff overlaps with at least one recent AI/editor diff trace), `NoOverlap` (no overlap found; staged diff and recent traces were both available but share no touched lines, or staged patch has no touched lines), `Error` (DB open failure, schema not ready, query error, staged diff read failure, or clock failure). Both `NoOverlap` and `Error` map to `ai_contribution_present = false` at the commit-msg policy seam; `Error` additionally triggers `sce.hooks.commit_msg.ai_overlap_error` logging. @@ -153,7 +153,7 @@ - `agent trace removed local-hook paths`: Current-state shorthand for the removed local-hook runtime behaviors that are no longer active: staged-checkpoint persistence, post-commit dual-write, post-rewrite remap ingestion, rewrite trace transformation, and retry replay. - `agent trace local hooks MVP contract and gap matrix`: T01 context artifact at `context/sce/agent-trace-local-hooks-mvp-contract-gap-matrix.md` that freezes local production boundaries/decisions for `agent-trace-local-hooks-production-mvp` and maps current seam-level code truth to required runtime completion tasks (`T02`..`T10`). - `sce install channel contract`: Current `sce` install/distribution scope captured in `context/sce/cli-first-install-channels-contract.md`: supported channels are repo-flake Nix, Cargo, npm, and source-built Flatpak with application ID `dev.crocoder.sce`; `Homebrew` is deferred from the active implementation stage. -- `Flatpak source-built channel`: Official `sce` distribution channel for application ID `dev.crocoder.sce` where `packaging/flatpak/dev.crocoder.sce.yml` builds the Rust CLI from source inside Flatpak rather than consuming Nix-built, GitHub Release, npm native, or other prebuilt `sce` artifacts. Both `packaging/flatpak/dev.crocoder.sce.yml` and `packaging/flatpak/cargo-sources.json` are checked-in generated artifacts: the manifest YAML is rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`, alpha-sorted block-style YAML produced via remarshal), and `cargo-sources.json` is produced from `cli/Cargo.lock` by a Nix derivation wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py`; both are guarded by `flatpak-manifest-parity` and `cargo-sources-parity` flake checks. The Nix manifest function exposes release-pin, local-checkout-override (Flatpak `type: dir`), and commit-pinned-for-release-package flavors; `packaging/flatpak/sce-flatpak.sh` is a thin imperative orchestrator around `flatpak-builder` and `flatpak build-bundle`, with no manifest text rewriting and no embedded Python. +- `Flatpak source-built channel`: Official `dev.crocoder.sce` channel where Flatpak compiles the Rust CLI from source rather than consuming a prebuilt binary. Nix generates and checks the manifest and Cargo source descriptor; before invoking the Pkl-free sandbox, `sce-flatpak.sh` prepares a temporary checksummed fallback that the manifest stages at `cli/package-fallback` through a `type: dir` source. Release-pin, local-checkout, and commit-pinned manifest flavors share this source-build contract. - `Flatpak host-git bridge`: Runtime Git access decision for the `sce` Flatpak package: `packaging/flatpak/git-host-bridge` is installed as `/app/bin/git` and delegates to `flatpak-spawn --host git`, with the Flatpak permission for `org.freedesktop.Flatpak` explicitly present in the manifest. - `Flatpak Nix orchestration apps`: Reduced Linux-only root-flake app surface for Flatpak: the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest --repo-root `, etc.), plus `release-flatpak-package` and `release-flatpak-bundle` for release asset emission, plus helper apps `regenerate-flatpak-manifest` and `regenerate-cargo-sources` for the checked-in generated artifacts. The previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed in favor of `sce-flatpak `. `flatpak-builder` and `flatpak build-bundle` invocations stay imperative (network + bubblewrap). - `flatpak-static-validation`: Linux-only root-flake check that runs the dedicated Nix-built Bash validator script (`nix/flatpak/static-validate.sh`) during default `nix flake check`; it uses static source-build assertions, generated-manifest validation, cargo-sources JSON checks, and AppStream metadata checks without running a full Flatpak build and without invoking the bash entrypoint or any inline `python3 - <<'PY'` heredoc. @@ -174,7 +174,8 @@ - `sce split platform release workflows`: CLI release automation topology where `.github/workflows/release-sce.yml` orchestrates reusable per-platform workflow files; the current reusable workflow set and active orchestrated release matrix are `release-sce-linux.yml`, `release-sce-linux-arm.yml`, and `release-sce-macos-arm.yml`, producing the current automated release target set `x86_64-unknown-linux-musl`, `aarch64-unknown-linux-musl`, and `aarch64-apple-darwin`. Each native reusable workflow validates the generated archive before native artifact upload by extracting it, smoke-running `bin/sce version --format json`, and invoking the native portability audit for the lane platform. - `publish-crates workflow`: Dedicated crates.io publish automation in `.github/workflows/publish-crates.yml` that runs after a GitHub release is published (or by manual dispatch), validates `.version`, `cli/Cargo.toml`, and the requested release tag remain aligned, supports a dry-run validation path, and requires `CARGO_REGISTRY_TOKEN` for real publication. - `clean publish workspace`: Temporary `.git`-free copy of the checked-out repository used by the crates.io publish workflow so ephemeral generated crate assets can be prepared locally without forcing Cargo publish to run with `--allow-dirty`. -- `cli generated asset mirror`: Ephemeral crate-local mirror under `cli/assets/generated/` created from canonical `config/` outputs just before Cargo packaging/builds so `cli/build.rs`, `cli/src/services/setup/mod.rs`, and `cli/src/services/config/mod.rs` can compile and package correctly without committing generated crate assets. +- `CLI OUT_DIR generated payload`: Build payload created by `cli/build.rs` under Cargo `OUT_DIR`: canonical Pkl outputs live under `pkl-generated/`, copied hooks/schemas/migrations under `static/`, and generated Rust setup/migration manifests at the output root. Repository builds produce it directly from canonical Pkl and static sources; packaged-crate builds populate the same shape from the validated packaging fallback. Production compile-time includes resolve only through this payload. +- `CLI package fallback`: Checksummed packaging-only payload created by `scripts/prepare-cli-generated-assets.sh` at its requested output path. It contains deterministic Pkl targets under `pkl-generated/`, static hooks/schemas/migrations under `static/`, and `SHA256SUMS`. Crates.io stages it at ignored `cli/package-fallback/`; Flatpak stages it as temporary `cli-package-fallback/` manifest support. Pkl-free `build.rs` validates and copies either packaged form into downstream `OUT_DIR`; repository builds with canonical sources do not consume it. - `banner gradient rendering`: Per-column right-to-left RGB color gradient applied to ASCII art banner lines in `cli/src/services/style.rs`; uses `owo-colors` truecolor support with cyan (0, 255, 255) on the right fading to magenta (255, 0, 255) on the left when color is enabled, and plain uncolored ASCII when color is disabled (non-TTY or `NO_COLOR`); spaces in the banner are left unstyled to avoid trailing-space ANSI artifacts - `SCE_BANNER_LINES`: ASCII art "SCE" logo constant in `cli/src/command_surface.rs` rendered at the top of `sce`, `sce help`, and `sce --help` output via `banner_with_gradient`; plain ASCII when color is disabled - `patch domain model`: Standalone `serde`-serializable domain types in `cli/src/services/patch.rs` (`ParsedPatch`, `PatchFileChange`, `FileChangeKind`, `PatchHunk`, `TouchedLine`, `TouchedLineKind`) for in-memory parsed unified-diff representation; captures only touched lines (added/removed) plus minimal per-file/per-hunk metadata, excludes non-hunk headers and unchanged context lines, and supports JSON round-trip fidelity with `snake_case` field naming diff --git a/context/overview.md b/context/overview.md index c2f05ff4..38ba5ad6 100644 --- a/context/overview.md +++ b/context/overview.md @@ -1,6 +1,6 @@ # Overview -This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. It validates that generated outputs stay deterministic and in sync via `nix run .#pkl-check-generated` and `nix flake check`. The generated target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. +This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. Generated target layouts are ephemeral: repository and Nix Cargo builds evaluate Pkl into Cargo `OUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` validates exact metadata coverage plus repeatable temporary inventories, and `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. It also includes a Rust CLI (`sce`) for Shared Context Engineering workflows: auth, config inspection, setup, doctor, agent-trace hooks, bash-policy evaluation, and trace database inspection. See `context/architecture.md` for module-level boundaries and `context/context-map.md` for the full domain file index. @@ -24,29 +24,29 @@ The CLI now also enforces a shared output-format parser contract in `cli/src/ser Agent Trace lifecycle setup now resolves repository storage, creates/reuses checkout identity for diagnostics, and initializes `/sce/repos//agent-trace.db` via `RepositoryAgentTraceDb`; hook runtime lazy initialization uses the same repository storage resolver when setup has not prepared the DB or schema metadata is incomplete. The CLI now also includes a shared text styling service in `cli/src/services/style.rs` that provides deterministic color enablement via `owo-colors`, automatic TTY detection, and `NO_COLOR` compliance for human-facing text output; stdout help/text surfaces, stderr diagnostics, and interactive prompt-adjacent text now reuse that shared styling policy while JSON, completion, and other non-interactive/machine-readable flows remain unstyled. The service exports color-detection, conditional styling, help/diagnostic/label/prompt styling, and `banner_with_gradient()` helpers for use across command surfaces while preserving pipe-safe output for non-interactive environments. The `setup` command includes an `inquire`-backed target-selection flow: default interactive selection for OpenCode/Claude/Pi/All with required-hook installation in the same run, explicit non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`), deterministic mutually-exclusive validation, and non-destructive cancellation exits; the former `--both` flag was removed in favor of `--all` (opencode+claude+pi). -The CLI now compiles an embedded setup asset manifest from `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `cli/assets/hooks/**` via `cli/build.rs`; `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths plus file bytes and target-scoped iteration without runtime reads from `config/`. The same build script also discovers `cli/migrations//*.sql` at compile time and writes `cli/src/generated_migrations.rs` constants sorted by numeric filename prefix for database migration consumers. +For repository Cargo builds, `cli/build.rs` evaluates the canonical `config/pkl/generate.pkl` model directly into Cargo `OUT_DIR/pkl-generated`, stages hook templates, the Agent Trace schema, and SQL migrations under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`. `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths, embedded bytes, and target-scoped iteration without runtime reads from `config/`; production setup, policy, config-schema, Agent Trace, and migration includes all resolve through `OUT_DIR`. Published crates instead carry an ignored, packaging-only fallback generated deterministically from the same canonical inputs before `cargo package`; unpacked downstream builds validate and copy that payload into their own `OUT_DIR` without requiring Pkl or parent repository paths. The setup service also provides repository-root install orchestration: it resolves the repository root, derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup uses a unified remove-and-replace policy for all write flows — it removes existing targets before swapping staged content and returns deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs` now separates install-flow logic from interactive prompt logic through focused support seams. The CLI now also applies baseline security hardening for reliability-driven automation: diagnostics/logging paths use deterministic secret redaction, `sce setup --hooks --repo ` canonicalizes and validates repository paths before execution, and setup write flows run explicit directory write-permission probes before staging/swap operations. -The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_file`, `log_file_mode`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config_root}/sce/config.json` then `.sce/config.json` with local override, where `config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_file_mode=truncate`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by` wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as `nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json` JSON Schema generated to `config/schema/sce-config.schema.json` and embedded by `cli/src/services/config/mod.rs` for both `sce config validate` and doctor-time config checks. Runtime startup config loading now keeps parity with that schema by accepting the canonical `"$schema": "https://sce.crocoder.dev/config.json"` declaration in repo-local and global config files, so startup commands such as `sce version` no longer fail before dispatch on that field. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for file logging; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/data/bash-policy-presets.json` and `context/sce/bash-tool-policy-enforcement-contract.md`. +The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_file`, `log_file_mode`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config_root}/sce/config.json` then `.sce/config.json` with local override, where `config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_file_mode=truncate`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by` wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as `nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json` JSON Schema generated beneath Cargo `OUT_DIR` and embedded by `cli/src/services/config/mod.rs` for both `sce config validate` and doctor-time config checks. Runtime startup config loading now keeps parity with that schema by accepting the canonical `"$schema": "https://sce.crocoder.dev/config.json"` declaration in repo-local and global config files, so startup commands such as `sce version` no longer fail before dispatch on that field. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for file logging; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/data/bash-policy-presets.json` and `context/sce/bash-tool-policy-enforcement-contract.md`. Invalid default-discovered config files now also degrade gracefully at startup: `sce` keeps running with degraded observability defaults, logs `sce.config.invalid_config` warnings, and reserves hard failures for explicit `--config` / `SCE_CONFIG_FILE` targets or other truly invalid runtime observability inputs. `cli/src/services/config/mod.rs` is now a module facade that declares focused config submodules (`types`, `schema`, `policy`, `resolver`, private `render`, `command`, and `lifecycle`), re-exporting `pub use types::*` and `pub(crate) use schema::validate_config_file`. Shared config primitive ownership is delegated to `cli/src/services/config/types.rs`; schema loading and file parsing to `cli/src/services/config/schema.rs`; bash-policy semantic validation and policy-specific formatting to `cli/src/services/config/policy.rs`; runtime discovery/precedence to `cli/src/services/config/resolver.rs`; and `sce config show` / `sce config validate` text+JSON output construction to `cli/src/services/config/render.rs`. Downstream modules continue importing through `services::config` unchanged. The CLI now has a generic borrowed `AppContext` dependency view in `cli/src/app.rs`; `AppRuntime` owns concrete production logger/telemetry/fs/git dependencies, and command execution receives context views that borrow those dependencies plus an optional `repo_root: Option`. `AppContext::with_repo_root(...)` / `ContextWithRepoRoot` derives repo-root-scoped views while preserving the borrowed runtime dependencies, and command execution is generic over associated-type narrow accessor traits where practical. The broad capability seam lives in `cli/src/services/capabilities.rs`, where `FsOps`/`StdFsOps` wrap filesystem operations and `GitOps`/`ProcessGitOps` wrap git process execution plus repository-root/hooks-directory resolution. -The shared default path service in `cli/src/services/default_paths.rs` is now the canonical owner for production CLI path definitions. It resolves per-user config/state/cache roots through a dedicated internal `roots` seam, exposes the current persisted-artifact inventory (global config and auth tokens), and also defines named DB paths (auth DB, local DB, Agent Trace DB) plus the repo-relative, embedded-asset, install, hook, and context-path accessors consumed across current CLI production code. Non-test production modules should consume this shared catalog instead of hardcoding owned path literals. No default cache-backed persisted artifact currently exists, so cache-root resolution remains available without speculative cache-path features and no legacy default-path fallback is supported. +The shared default path service in `cli/src/services/default_paths.rs` is now the canonical owner for production CLI path definitions. It resolves per-user config/state/cache roots through a dedicated internal `roots` seam, exposes the current persisted-artifact inventory (global config and auth tokens), and also defines named DB paths (auth DB, local DB, Agent Trace DB) plus the repo-relative, install, hook, and context-path accessors consumed across current CLI production code. Non-test production modules should consume this shared catalog instead of hardcoding owned path literals. No default cache-backed persisted artifact currently exists, so cache-root resolution remains available without speculative cache-path features and no legacy default-path fallback is supported. The Rust CLI also centralizes SCE-owned web URI construction in `cli/src/services/agent_trace.rs`, with `SCE_WEB_BASE_URL` as the single Rust owner for `https://sce.crocoder.dev` and helpers consumed by Agent Trace conversation URLs, Agent Trace persisted trace URLs, Agent Trace session URLs, and setup-created repo-local config schema URLs. The same config resolver now also owns the attribution-hooks gate used by local hook runtime: opt-out env `SCE_ATTRIBUTION_HOOKS_DISABLED` overrides `policies.attribution_hooks.enabled` with inverted semantics, and the gate defaults to enabled unless explicitly disabled. The config service split now includes `cli/src/services/config/resolver.rs` as the focused owner for config-file discovery, file-layer merging, env/flag/default precedence, auth-key resolution, observability resolution, attribution-hooks resolution, and default-discovered invalid-file degradation; `cli/src/services/config/mod.rs` remains the facade/rendering orchestration surface while preserving existing `services::config` imports. Generated config now includes repo-local OpenCode plugin assets: `sce-bash-policy.ts` plus `sce-agent-trace.ts` are emitted under `config/.opencode/plugins/`; the OpenCode agent-trace plugin extracts `{ sessionID, diff, time, model_id }` from user `message.updated` events with diffs, tracks per-session OpenCode client version from `session.created`/`session.updated`, and sends payloads to `sce hooks diff-trace` with `tool_name="opencode"` plus optional `tool_version`. Claude generated config now routes supported `PostToolUse Write|Edit|MultiEdit|NotebookEdit` events directly to `sce hooks diff-trace`; it no longer registers a `SessionStart` hook or calls `sce hooks session-model`. Rust handles extraction, validation, and persistence without a TypeScript intermediary; the former `config/.claude/plugins/sce-agent-trace.ts` Bun runtime was removed in T07 of the `claude-rust-diff-trace` plan. The Rust hook validates required fields, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and persists tool-prefixed `session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), `model_id`, `tool_name`, and nullable `tool_version` into `diff_traces` through AgentTraceDb. Bash-policy now delegates OpenCode enforcement to the Rust `sce policy bash` command: the generated OpenCode plugin at `config/.opencode/plugins/sce-bash-policy.ts` is a thin wrapper that calls `sce policy bash --input normalized --output json` via `spawnSync` and throws on deny decisions; it no longer contains independent TypeScript policy logic. The former `bash-policy/runtime.ts` TypeScript runtime has been removed. Preset... Claude bash-policy enforcement is also generated through `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`, so Claude and OpenCode both delegate to the Rust policy evaluator without a Claude TypeScript runtime. Pi bash-policy enforcement is delegated the same way through a project-local Pi extension (`config/lib/pi-plugin/sce-pi-extension.ts`, emitted to `config/.pi/extensions/sce/index.ts`) whose `tool_call` handler blocks denied bash commands via `sce policy bash` and fails open when the policy check cannot run (see `context/sce/pi-extension-runtime.md`). Local database bootstrap is now owned by `LocalDbLifecycle::setup` and `AgentTraceDbLifecycle::setup` aggregated by the setup command. Agent Trace setup creates/reuses the current checkout ID for diagnostics and initializes the repository-scoped `/sce/repos//agent-trace.db` with the repository schema; hook runtime lazily creates or upgrades that repository DB when setup has not run or schema metadata is incomplete. Doctor validates the repository-scoped DB path/health and can bootstrap missing parent directories; outside a Git repository it reports an actionable "requires a Git repository" diagnostic instead of probing a sentinel path. The `sce trace` group operates only on repository-scoped DBs for list/status/status-all/shell UX; the checkout-scoped `--legacy` surface was removed by the `retire-legacy-agent-trace-db` plan (see `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md`). Wiring a user-invocable `sce sync` command is deferred to `0.4.0`. -The repository-root flake (`flake.nix`) now applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline with filtered package sources for the Cargo tree plus required embedded config/assets, and runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed check derivations (`cargoTest`, `cargoClippy`, `cargoFmt`) that reuse the same filtered source/toolchain setup. +The repository-root flake (`flake.nix`) applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, and builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline whose filtered source contains the Cargo tree, canonical Pkl/plugin inputs, and required static assets. Crane package/test/clippy builds include Pkl and exercise direct generation into Cargo `OUT_DIR`; `cli-tests`, `cli-clippy`, and `cli-fmt` remain Crane-backed check derivations. The root flake splits native and release outputs: `packages.sce` and `packages.default` build the **native** development binary (`scePackage`), while `packages.sce-release` builds the release binary (`sceReleasePackage`: static musl on Linux, native on Darwin). So `nix build .#sce` / `.#default`, `nix run . -- --help`, `nix run .#sce -- --help`, and `nix profile install github:crocoder-dev/shared-context-engineering` target the native binary, and `nix build .#sce-release` / `nix run .#sce-release -- ...` (plus `nix run .#release-artifacts`, which builds `.#sce-release`) target the release binary. On Linux the native and release outputs are distinct store paths, and the release output passes the native portability audit. `packages..ci-checks` is the explicit long-running validation tier: `nix build .#ci-checks` builds the `.#sce-release` package and, on Linux, audits the real release binary for forbidden `/nix/store/` references, so the expensive work stays out of `nix flake check` (which never builds `.#sce-release`). Git-commit embedding is **release-only**: `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment applied only to the release derivations (`scePackageMusl` on Linux, `sceReleasePackageNative` on Darwin), not to `commonCargoArgs`. So native `.#sce`/`.#default` and every `nix flake check` derivation (`cli-tests`, `cli-clippy`, `cli-fmt`) build without the commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` still reports the real commit via `sce version`. `cli/build.rs` `emit_git_commit` emits `SCE_GIT_COMMIT` only when the env var is explicitly set — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` rerun watches. On Darwin the release now uses a distinct native-toolchain derivation (native toolchain + commit), so it diverges from `.#sce` to carry the commit while native stays commit-independent. The default development shell is slimmed for fast iteration: `devShells.default` no longer includes `scePackage` or `tursoPackage`, so `nix develop` compiles neither the CLI package nor the Turso CLI — it provides only the Rust toolchain and JS/pkl tooling for `cargo`/`biome`/`pkl` work. Turso stays available as `packages..turso` and through a new opt-in `devShells..database` shell (default tools + `tursoPackage`), entered via `nix develop .#database`. Both shells share `defaultDevShellPackages`/`defaultDevShellHook` `let` bindings so they cannot drift. The CLI Cargo package metadata now includes crates.io publication-ready fields with crate-local install guidance in `cli/README.md`; supported Cargo install paths are `cargo install shared-context-engineering --locked`, `cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked`, and local `cargo install --path cli --locked`. The published crate installs the `sce` binary. The crate also keeps `cargo clippy --manifest-path cli/Cargo.toml` warnings-denied through `cli/Cargo.toml` lint configuration, so an extra `-- -D warnings` flag is redundant. -The repository-root flake is now the single Nix entrypoint for both repo tooling and CLI packaging/checks, so root-level `nix flake check` evaluates the Crane-backed CLI checks (`cli-tests`, `cli-clippy`, `cli-fmt`), Linux-only `flatpak-static-validation`, `workflow-actionlint` (runs `actionlint` on all `.github/workflows/*.yml`), plus six split JavaScript check derivations: `npm-bun-tests`, `npm-biome-check`, `npm-biome-format`, `config-lib-bun-tests`, `config-lib-biome-check`, and `config-lib-biome-format`, without nested-flake indirection. The config-lib checks now consume `config/lib/` as the shared Bun/TypeScript package root for both `agent-trace-plugin/` and `bash-policy-plugin`, with dependencies resolved from `config/lib/package.json` and `config/lib/bun.lock`. For Cargo packaging/builds, the crate now compiles against a temporary `cli/assets/generated/` mirror prepared from canonical `config/` outputs during Nix builds and crates.io publish runs rather than from a committed crate-local snapshot. +The repository-root flake is the single Nix entrypoint for repo tooling and CLI packaging/checks, so root-level `nix flake check` evaluates the Crane-backed CLI checks (`cli-tests`, `cli-clippy`, `cli-fmt`), the ephemeral `pkl-generated` inventory check, Linux-only Flatpak checks, `workflow-actionlint`, and the split npm/config-lib JavaScript checks without nested-flake indirection. Ordinary repository and Crane Cargo builds generate canonical Pkl outputs directly into Cargo `OUT_DIR`; crates.io packaging prepares a self-contained Pkl-free fallback in a temporary clean workspace, and Flatpak helpers prepare the same payload beside generated manifests before the sandboxed source build. No general-purpose `cli/assets/generated/` mirror or committed generated target tree remains. Config-lib JS flake checks execute from `config/lib/`, but the copied Nix check source is repo-shaped when tests require shared repo fixtures; the current Claude agent-trace golden tests are fully Rust-owned in `cli/src/services/structured_patch/fixtures` (Claude TypeScript plugin test removed in T07). Local developer Nix tuning guidance now lives in `AGENTS.md`, including optional user-level `~/.config/nix/nix.conf` recommendations for `max-jobs` and `cores` plus an explicit system-level-only note for `auto-optimise-store`. The Pkl authoring layer owns generated OpenCode plugin registration for SCE-managed plugins: `config/pkl/base/opencode.pkl` defines the canonical plugin entries, `config/pkl/renderers/common.pkl` re-exports the shared plugin list for renderer use, and generated `config/.opencode/opencode.json` registers `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts` through OpenCode's `plugin` field. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook routed through `.claude/hooks/run-sce-or-show-install-guidance.sh` before running `sce policy bash`. -The current CLI install/distribution contract for `sce` includes repo-flake Nix, Cargo, npm, and source-built Flatpak (`dev.crocoder.sce`) as supported channels, while `Homebrew` remains deferred from the current implementation stage. Nix-managed build/release entrypoints are the source of truth for existing binary rollout surfaces, npm consumes Nix-produced release artifacts, and repo-root `.version` is the canonical checked-in release version source that release packaging and downstream Cargo/npm publication must match. Flatpak is the approved source-built exception to binary artifact reuse: its package must build the Rust CLI from source inside Flatpak, use a Flathub-style release-source manifest plus a Nix-generated local checkout override for local builds, prepare generated CLI assets from checked-in `config/` inputs, and provide Git access through a `/app/bin/git` wrapper delegating to `flatpak-spawn --host git` with the required `org.freedesktop.Flatpak` permission. The active Flatpak release contract approves GitHub Release source-manifest assets (manifest tarball, checksum, and JSON metadata) and source-built `.flatpak` bundle assets (`sce-v-x86_64.flatpak` / `sce-v-aarch64.flatpak` plus `.sha256` / `.json`), with `.github/workflows/release-sce.yml` building/uploading those assets alongside CLI/npm assets, while still excluding automatic Flathub submission, prebuilt (non-source-built) Flatpak binaries/bundles, OSTree repositories, and release-version bumping. The shared release artifact foundation is now implemented through root-flake apps `release-artifacts` and `release-manifest`, which emit canonical `sce-v-.tar.gz` archives, SHA-256 checksum files, merged manifest outputs, and a detached `sce-v-release-manifest.json.sig` produced from a non-repo private signing key; the npm distribution surface is now implemented as a checked-in `npm/` launcher package plus root-flake `release-npm-package`, which packs `sce-v-npm.tgz`, refuses mismatched checked-in package metadata, and installs the native CLI by downloading the release manifest plus detached signature, verifying the manifest with the bundled npm public key, and only then checksum-verifying the matching GitHub release archive at npm `postinstall` time. GitHub Releases remain the canonical publication surface for binary release artifacts and approved Flatpak source-manifest package assets, while crates.io and npm registry publication are separate non-bumping publish stages under the approved release topology. GitHub CLI release automation now lives in dedicated `release-sce*.yml` workflows split by Linux, Linux ARM, and macOS ARM, and `.github/workflows/release-sce.yml` now orchestrates those three reusable platform lanes before assembling the signed release manifest, npm tarball, and GitHub release payload. The orchestrator tags/releases the checked-in `.version` directly and rejects version mismatches instead of generating a new semver during workflow execution; `.github/workflows/publish-crates.yml` and `.github/workflows/publish-npm.yml` own registry publication after release assets exist. +The current CLI install/distribution contract for `sce` includes repo-flake Nix, Cargo, npm, and source-built Flatpak (`dev.crocoder.sce`) as supported channels, while `Homebrew` remains deferred from the current implementation stage. Nix-managed build/release entrypoints are the source of truth for existing binary rollout surfaces, npm consumes Nix-produced release artifacts, and repo-root `.version` is the canonical checked-in release version source that release packaging and downstream Cargo/npm publication must match. Flatpak is the approved source-built exception to binary artifact reuse: its package builds the Rust CLI from source inside Flatpak, uses a Flathub-style release-source manifest plus a Nix-generated local checkout override, and receives an ephemeral checksummed package fallback prepared by the Nix-side helper because Pkl is unavailable in the Flatpak build sandbox. Runtime Git access still uses a `/app/bin/git` wrapper delegating to `flatpak-spawn --host git` with the required `org.freedesktop.Flatpak` permission. The active Flatpak release contract approves GitHub Release source-manifest assets (manifest tarball, checksum, and JSON metadata) and source-built `.flatpak` bundle assets (`sce-v-x86_64.flatpak` / `sce-v-aarch64.flatpak` plus `.sha256` / `.json`), with `.github/workflows/release-sce.yml` building/uploading those assets alongside CLI/npm assets, while still excluding automatic Flathub submission, prebuilt (non-source-built) Flatpak binaries/bundles, OSTree repositories, and release-version bumping. The shared release artifact foundation is now implemented through root-flake apps `release-artifacts` and `release-manifest`, which emit canonical `sce-v-.tar.gz` archives, SHA-256 checksum files, merged manifest outputs, and a detached `sce-v-release-manifest.json.sig` produced from a non-repo private signing key; the npm distribution surface is now implemented as a checked-in `npm/` launcher package plus root-flake `release-npm-package`, which packs `sce-v-npm.tgz`, refuses mismatched checked-in package metadata, and installs the native CLI by downloading the release manifest plus detached signature, verifying the manifest with the bundled npm public key, and only then checksum-verifying the matching GitHub release archive at npm `postinstall` time. GitHub Releases remain the canonical publication surface for binary release artifacts and approved Flatpak source-manifest package assets, while crates.io and npm registry publication are separate non-bumping publish stages under the approved release topology. GitHub CLI release automation now lives in dedicated `release-sce*.yml` workflows split by Linux, Linux ARM, and macOS ARM, and `.github/workflows/release-sce.yml` now orchestrates those three reusable platform lanes before assembling the signed release manifest, npm tarball, and GitHub release payload. The orchestrator tags/releases the checked-in `.version` directly and rejects version mismatches instead of generating a new semver during workflow execution; `.github/workflows/publish-crates.yml` and `.github/workflows/publish-npm.yml` own registry publication after release assets exist. The Linux root flake now also exposes `nix run .#release-flatpak-package -- --version --out-dir `, delegating to `packaging/flatpak/sce-flatpak.sh release-package` to emit deterministic Flatpak source-manifest tarball/checksum/JSON release assets from checked-in packaging source while running the Nix-built version-parity validator script across `.version`, `cli/Cargo.toml`, `npm/package.json`, and AppStream release metadata; `.github/workflows/release-sce.yml` runs that app into `dist/flatpak` and uploads `*.tar.gz`, `*.sha256`, and `*.json` Flatpak assets to the GitHub Release. Linux root flake also exposes `nix run .#release-flatpak-bundle -- --version --arch --out-dir `, delegating to `sce-flatpak.sh release-bundle` to build a source-built `.flatpak` bundle from the checkout using imperative `flatpak-builder` + `flatpak build-bundle` (network + bubblewrap, kept out of pure Nix), emitting per-architecture `.flatpak`/`.sha256`/`.json` files; `.github/workflows/release-sce-linux.yml` and `.github/workflows/release-sce-linux-arm.yml` build and upload x86_64/aarch64 bundles respectively, assembled by `.github/workflows/release-sce.yml`. The checked-in Flatpak packaging surface lives under `packaging/flatpak/` with Nix-owned generation: `dev.crocoder.sce.yml` is rendered from a Nix expression (`nix/flatpak/manifest.nix`) via the standard nixpkgs YAML formatter (`pkgs.formats.yaml.generate`) and regenerated by `nix run .#regenerate-flatpak-manifest`; `cargo-sources.json` is generated from `cli/Cargo.lock` by a Nix derivation wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py` and regenerated by `nix run .#regenerate-cargo-sources`; both are guarded by `flatpak-manifest-parity` and `cargo-sources-parity` flake checks. Static manifest validation is Bash-owned (`nix/flatpak/static-validate.sh`), and release-version parity validation is Bash-owned (`nix/flatpak/version-parity.sh`). AppStream metadata and the host-git wrapper source remain checked in, and `sce-flatpak.sh` is a thin imperative orchestrator (no manifest text rewriting, no embedded Python) around `flatpak-builder` and `flatpak build-bundle`, consumed by the reduced flake app surface and by Flatpak source-manifest release packaging. The current supported automated release target matrix is `x86_64-unknown-linux-musl`, `aarch64-unknown-linux-musl`, and `aarch64-apple-darwin`; npm launcher platform support remains a separate current-state surface documented in the npm distribution contract and launcher code. @@ -71,20 +71,20 @@ The setup command parser/dispatch now also supports composable setup+hooks runs - Author the three SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi, OpenCode, and Claude consume this model directly. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. -- Generate derived artifacts into `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**` (Pi prompts/skills plus the Pi extension at `config/.pi/extensions/sce/index.ts`) via `config/pkl/generate.pkl`. -- Treat generated outputs as build artifacts, not primary editing surfaces. +- Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. +- Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. ## Ownership boundaries -- Generation-owned paths are authored config artifacts under `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**` (agents, commands, skills, shared runtime libraries, OpenCode plugin files, generated OpenCode `opencode.json`, Claude hook/settings assets, Pi prompt/skill assets, and the Pi extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts`). +- Canonical ownership lives under `config/pkl/**` and the referenced `config/lib/**` plugin/extension sources. The generated path names are payload-relative install layouts, not committed directories. - Runtime/install artifacts are not generation-owned (for example `node_modules`, lockfiles, install outputs). -- Code and behavior changes must be made in canonical sources and renderer metadata, then regenerated. +- Code and behavior changes must be made in canonical sources and renderer metadata, then verified through ephemeral generation. ## Core commands -- Regenerate outputs in place: `nix develop -c pkl eval -m . config/pkl/generate.pkl` -- Verify generated outputs are current: `nix run .#pkl-check-generated` -- Run repository flake checks (CLI tests, clippy, fmt, pkl-parity, workflow-actionlint): `nix flake check` +- Generate a temporary preview: `nix run .#pkl-generate -- "$(mktemp -d)"` +- Verify deterministic ephemeral outputs and forbidden repository paths: `nix run .#pkl-check-generated` +- Run repository flake checks (CLI tests, clippy, fmt, `pkl-generated`, workflow-actionlint): `nix flake check` Lightweight post-task verification baseline (required after each completed task): run `nix run .#pkl-check-generated` and `nix flake check`. @@ -96,7 +96,7 @@ Lightweight post-task verification baseline (required after each completed task) - For active plan execution state: `context/plans/` - For architecture decisions: `context/decisions/` -- No dedicated generated-parity workflow is currently checked in; local/generated-output parity is enforced through `nix run .#pkl-check-generated` and the root `nix flake check` `pkl-parity` derivation. GitHub Actions workflow lint is enforced through the root `nix flake check` `workflow-actionlint` derivation (all `.github/workflows/*.yml`). +- No generated snapshot-parity workflow is checked in; deterministic ephemeral generation is enforced through `nix run .#pkl-check-generated` and the root `nix flake check` `pkl-generated` derivation. GitHub Actions workflow lint is enforced through the root `nix flake check` `workflow-actionlint` derivation (all `.github/workflows/*.yml`). - PR validation runs through `.github/workflows/pr-ci.yml` on `pull_request`, `push` to `main`, and `workflow_dispatch` and now defines two matrix jobs. A workflow-level concurrency group (`${{ github.workflow }}-${{ github.ref }}`, `cancel-in-progress: true`) cancels superseded runs on the same ref, and every matrix job installs Nix via `DeterminateSystems/nix-installer-action@v22`, enables `DeterminateSystems/magic-nix-cache-action@v14` immediately after, runs on an `ubuntu-latest` + `macos-latest` matrix (`fail-fast: false`), and has a `timeout-minutes: 90` guard. The `nix-ci` job (name `Nix CI (ubuntu-latest)` / `Nix CI (macos-latest)`, for required branch protection checks) runs timed `nix flake check --print-build-logs`, then builds and smoke-tests the **native** package via timed `nix build .#sce --out-link result --print-build-logs` plus `./result/bin/sce --help` / `./result/bin/sce version` — it no longer builds the musl release (`.#default`/`.#sce` is native since the flake-speedup split). A separate `release-validation` job (name `Release validation (ubuntu-latest)` / `Release validation (macos-latest)`) builds `nix build .#ci-checks --out-link result-ci-checks --print-build-logs` on every commit, which forces the `.#sce-release` static-musl build and, on Linux, the real-binary portability audit guarded inside `ciChecks`; macOS builds the native-on-Darwin release package. This always-on release coverage on every PR/push (no path filters) is the intentional trade-off recorded in the plan Decisions section. The Nix store cache is the only cache layer; no separate Cargo/Bun/npm/`node_modules` caches. Release-publish workflows (`release-sce*.yml`) build the release binary via `nix run .#release-artifacts` (which targets `.#sce-release`), not `.#default`. ## Cross-target parity diff --git a/context/patterns.md b/context/patterns.md index 82d8713b..35c826ad 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -75,12 +75,11 @@ - Use `config/pkl/generate.pkl` as the single generation module for authored config outputs. Flatten self-contained workflow skill documents as `{skill slug}/{package-relative path}` so nested references are emitted deterministically without sibling-package dependencies. - Use `config/pkl/README.md` as the contributor-facing runbook for prerequisites, ownership boundaries, regeneration steps, and troubleshooting. -- Run multi-file generation with `nix develop -c pkl eval -m . config/pkl/generate.pkl` to emit to repository-root mapped paths. -- Run stale-output detection through the flake app entrypoint `nix run .#pkl-check-generated`; it wraps `nix develop -c ./config/pkl/check-generated.sh`, evaluates exact inventory coverage, regenerates into a temporary directory, compares complete generated directories plus scalar outputs, and fails on missing, changed, extra, or explicitly forbidden removed paths. -- Keep generated-output parity anchored to `nix run .#pkl-check-generated` and the root `nix flake check` `pkl-parity` derivation; removed target paths must be treated as forbidden stale outputs rather than generated inventory. +- Run multi-file generation only into an explicit temporary output root, for example `nix run .#pkl-generate -- "$(mktemp -d)"`; never evaluate with `-m .`. +- Run ephemeral generation validation through `nix run .#pkl-check-generated`; it wraps the dev-shell script, rejects committed target/schema/mirror outputs, evaluates exact metadata coverage, generates twice into temporary directories, and compares sorted SHA-256 inventories while requiring all supported target roots. +- Keep this contract anchored to the root `nix flake check` `pkl-generated` derivation. Removed target paths are forbidden repository artifacts even though the same path names remain valid inside temporary payload roots. - Treat `nix run .#pkl-check-generated` and `nix flake check` as the lightweight post-task verification baseline and run both after each completed task. -- For non-destructive verification during development, run `nix develop -c pkl eval -m context/tmp/t04-generated config/pkl/generate.pkl` and inspect emitted paths under `context/tmp/`. -- Keep `output.files` limited to generated-owned paths only (`config/.opencode/{agent,command,skills,lib,plugins,opencode.json}`, `config/.claude/{commands,skills,hooks,settings.json}` with no Claude agents, `config/.pi/{prompts,skills,extensions}`, and the generated schema). Do not emit `config/automated/.opencode`. +- Keep `output.files` limited to payload-relative paths (`config/.opencode/{agent,command,skills,lib,plugins,opencode.json}`, `config/.claude/{commands,skills,hooks,settings.json}` with no Claude agents, `config/.pi/{prompts,skills,extensions}`, and the generated schema). Do not emit `config/automated/.opencode`. - For OpenCode pre-execution bash-policy hooks, keep the generated plugin entrypoint thin (`plugins/sce-bash-policy.ts`) and delegate policy evaluation to the Rust `sce policy bash --input normalized --output json` command so OpenCode and Claude share one evaluator. ## Internal subagent parity mapping @@ -114,8 +113,8 @@ - For interactive setup flows, isolate prompt handling behind a service-layer prompter seam so selection mapping and cancellation behavior can be tested without a live TTY. - When setup or path-catalog modules grow dense, extract focused internal support seams (for example install-flow, prompt-flow, or root-resolution helpers) before adding new behavior so orchestration files stay navigable without changing command contracts. - Treat setup prompt cancellation/interrupt as a non-destructive exit path with explicit user messaging (no file mutations and no partial side effects). -- For setup install prep, generate compile-time embedded asset manifests from `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `cli/assets/hooks/**` in `cli/build.rs`, keep relative paths normalized to forward-slash form, and expose target-scoped iterators/lookups from the setup service layer for installer wiring. -- For CLI database migration prep, keep SQL files under immediate `cli/migrations//` directories named `NNN_description.sql`; `cli/build.rs` discovers those files at compile time, sorts by the numeric prefix before `_`, and writes deterministic `cli/src/generated_migrations.rs` constants with `include_str!` references for service `DbSpec` consumers. +- For repository setup-asset build prep, have `cli/build.rs` evaluate `config/pkl/generate.pkl` directly into Cargo `OUT_DIR`, normalize embedded relative paths to forward slashes, stage non-Pkl hook/schema inputs under `OUT_DIR/static`, and generate the setup manifest in `OUT_DIR`; production Rust includes must not point back into `config/`, `cli/assets/`, or another source-tree generated mirror. +- For CLI database migration prep, keep SQL files under immediate `cli/migrations//` directories named `NNN_description.sql`; `cli/build.rs` stages those files under `OUT_DIR/static/migrations`, sorts by the numeric prefix before `_`, and writes deterministic `OUT_DIR/generated_migrations.rs` constants with `include_str!` references for service `DbSpec` consumers. - For setup install execution, write selected embedded assets into a per-target staging directory first, then remove the existing target and swap staged content into place; on swap failure, clean temporary staging paths and return deterministic recovery guidance (recover from version control). No backup artifacts are created. - For required-hook setup execution, resolve repository root and effective hooks directory from git (`rev-parse --show-toplevel`, `rev-parse --git-path hooks`), then apply deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`) with staged writes, executable-bit enforcement, and remove-and-replace behavior that removes existing hooks before swapping staged content. - For hook setup CLI UX, allow `--hooks` as both hooks-only and composable target+hooks execution (optional `--repo `), enforce deterministic option compatibility (`--repo` requires `--hooks`; target flags stay mutually exclusive), and emit stable section-ordered setup/hook status lines for automation-friendly logs. @@ -147,12 +146,15 @@ - For hosted reconciliation observability, publish run-level mapped/unmapped counts, confidence histogram buckets, runtime timing, and normalized error-class labels so retry/quality drift can be monitored without requiring a full dashboard surface. - Keep crate-local onboarding docs in `cli/README.md` and sanity-check command examples against actual `sce` output whenever command messaging changes. - Keep Rust verification in flake checks under stable named derivations re-exported by the root flake: `checks..cli-tests`, `checks..cli-clippy`, `checks..cli-fmt`, and `checks..workflow-actionlint`. -- Keep cheap flake-check sources as narrow as their behavior allows: formatting checks should not depend on package-only generated assets, and parity/static checks should copy only the authoring inputs and committed outputs they inspect. -- Keep Rust package/check sources as narrow as behavior allows: package builds should include the Cargo tree plus required embedded config/schema assets, not unrelated config authoring or plugin sources that are not read by `cli/build.rs`. +- Keep cheap flake-check sources as narrow as their behavior allows: formatting checks should not depend on generated payloads, and ephemeral/static checks should copy only the canonical inputs and forbidden paths they inspect. +- Keep Rust package/check sources as narrow as behavior allows: repository builds include the Cargo tree, canonical Pkl and referenced plugin/extension sources, plus static inputs read by `cli/build.rs`; they must not include committed generated target trees. - In `flake.nix`, select the Rust toolchain via an explicit Rust overlay (`rust-overlay`) and thread that toolchain through Crane package/check derivations so CLI builds and checks do not rely on implicit nixpkgs Rust defaults. - For installable CLI surfaces in the root flake, expose an explicit named package plus default alias (`packages.sce` and `packages.default = packages.sce`, the **native** development package) and pair it with a runnable app output (`apps.sce`) that points to the packaged binary path; keep the static-musl release binary a distinct output (`packages.sce-release`) rather than folding it into the default package. - For root-flake CLI release metadata, source the package/check version from repo-root `.version` and trim it at eval time so packaged outputs stay aligned without hardcoded semver strings in `flake.nix`. - For Cargo CLI distribution, keep crate metadata publication-ready, document the supported Cargo install paths in `cli/README.md` (`cargo install shared-context-engineering --locked`, git install with `--locked`, and local `cargo install --path cli --locked`), and verify at least the repo-local build/check path through the Nix-managed validation baseline. +- Keep Pkl-free fallback payloads packaging-only and Git-ignored: generate them from canonical Pkl in a temporary clean workspace or manifest-support directory, stage all required static inputs, reject nondeterministic generation, and include an exact checksum inventory. Crates.io embeds this payload in the crate; Flatpak stages it as a manifest `type: dir` source before entering the Pkl-free sandbox. +- In `cli/build.rs`, choose direct canonical Pkl generation whenever repository sources exist; use the validated package fallback only when those sources are absent, copy either input mode into the same `OUT_DIR` shape, and fail actionably rather than silently switching modes after a direct-generation error. +- Anchor Cargo `package.include` patterns at the crate root so similarly named files in obsolete source trees cannot enter the `.crate`; inspect `cargo package --list` and build the unpacked archive with Pkl absent when changing the fallback inventory. ## Unit testing in Nix sandbox diff --git a/context/plans/generate-cli-assets-in-cargo-out-dir.md b/context/plans/generate-cli-assets-in-cargo-out-dir.md new file mode 100644 index 00000000..c9ccf913 --- /dev/null +++ b/context/plans/generate-cli-assets-in-cargo-out-dir.md @@ -0,0 +1,84 @@ +# Plan: generate-cli-assets-in-cargo-out-dir + +## Change summary + +Remove the committed generated target trees at `config/.opencode`, `config/.claude`, and `config/.pi`. Repository builds will evaluate the canonical Pkl model directly into Cargo's ephemeral `OUT_DIR`; `build.rs` will stage the remaining required static inputs there, and Rust will include generated source and static payloads only from `OUT_DIR`. + +Generated target files will no longer be repository artifacts or parity snapshots. Published crates remain self-contained through a packaging-only payload generated from Pkl in a temporary clean workspace before `cargo package`/`cargo publish`; downstream builds copy that packaged payload into their own `OUT_DIR` and do not require Pkl. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [ ] AC1: `config/.opencode`, `config/.claude`, and `config/.pi` are absent from the repository, and generated workflow, skill, entry-point, plugin, settings, extension, and config-schema outputs exist only in temporary generation/build/package locations. + - Validate: `test ! -e config/.opencode && test ! -e config/.claude && test ! -e config/.pi`; run the generation check and inspect `git status --short` to confirm it does not recreate them. +- [ ] AC2: A repository CLI build runs the canonical Pkl generator into Cargo `OUT_DIR`, stages required non-Pkl inputs there, and writes no generated Rust or static files into `cli/src/`, `cli/assets/`, or `config/`. + - Validate: `nix develop -c sh -c 'cd cli && cargo clean && cargo build'`; inspect `cli/target/debug/build/shared-context-engineering-*/out/` and run `git status --short cli/src cli/assets config`. +- [ ] AC3: The built CLI embeds the deterministic OpenCode, Claude, Pi, hook, policy, schema, and migration payloads expected by setup and runtime consumers. + - Validate: `nix develop -c sh -c 'cd cli && cargo test setup && cargo test config && cargo test agent_trace && cargo test auth_db'` and the ephemeral Pkl inventory check. +- [ ] AC4: A staged crates.io package embeds a packaging-only Pkl-generated payload, and the unpacked crate builds without Pkl, the repository-level Pkl sources, or parent-directory `config/` paths. + - Validate: prepare a temporary clean repository copy, run the package-preparation and `cargo package` flow, inspect `cargo package --list`, unpack the `.crate`, remove Pkl from `PATH`, and build it with Cargo. +- [ ] AC5: Nix package/check builds and Flatpak source builds consume direct `OUT_DIR` generation or an explicitly prepared ephemeral fallback without relying on committed generated target trees. + - Validate: `nix flake check`; on Linux, `nix run .#sce-flatpak -- validate`; inspect Nix, Flatpak, and release definitions for references to removed `config/.opencode`, `config/.claude`, or `config/.pi` trees. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Add a decision record superseding the checked-in generated-target ownership portions of `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` while preserving its workflow matrix and canonical Pkl ownership decisions. +- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` to describe ephemeral Pkl generation, removed generated target trees, `OUT_DIR`-only Rust embedding, and the crates.io fallback payload. +- Update `context/sce/generated-opencode-plugin-registration.md`, `context/sce/pi-extension-runtime.md`, `context/sce/shared-turso-db.md`, `context/cli/config-precedence-contract.md`, and `context/sce/cli-cargo-distribution-contract.md` where they currently identify checked-in generated paths or source-tree build artifacts. + +## Constraints and non-goals + +- **In scope:** canonical Pkl generation output routing; removal of `config/.opencode`, `config/.claude`, and `config/.pi`; ephemeral generation/inventory checks; `cli/build.rs`; Rust compile-time includes for setup assets, policy data, schemas, and migration manifests; Cargo package staging; Nix/Crane inputs; crates.io publishing; Flatpak preparation; focused regression coverage and contributor documentation. +- **Out of scope:** Changing workflow/skill/entry-point content, changing the OpenCode/Claude/Pi target matrix, changing runtime setup destinations, changing database migration SQL, or removing canonical Pkl and `config/lib` authoring sources. +- **Constraints:** Repository/Nix builds generate canonical Pkl outputs directly into Cargo `OUT_DIR`; all Rust compile-time generated source and static-data includes resolve from `OUT_DIR`; no generated target tree is committed; generation stays deterministic and exact-inventory checked; published crates build without Pkl or repository-external paths; normal verification remains Nix-managed. +- **Non-goal:** Bundling a Pkl executable/evaluator into the published Rust crate or preserving the removed generated directories as compatibility paths. + +## Assumptions + +- The previously approved crates.io exception remains in force: publication may create a temporary Pkl-generated payload inside the staged crate, but that payload is never committed and downstream `build.rs` copies it into the consumer's `OUT_DIR`. +- `nix run .#pkl-check-generated` may retain its command name for compatibility while changing from committed-output parity comparison to ephemeral generation, exact-inventory validation, determinism checking, and rejection of the removed target directories. +- Non-Pkl inputs required at compile time, such as hook templates, the Agent Trace schema, and SQL migrations, remain canonical source files and are copied by `build.rs` into `OUT_DIR`. + +## Task stack + +- [x] T01: `Generate and embed CLI build artifacts from OUT_DIR` (status:complete) + - Task ID: T01 + - Goal: Refactor `cli/build.rs` and Rust consumers so repository builds run Pkl into `OUT_DIR`, copy remaining static inputs there, generate setup-asset and migration Rust manifests there, and resolve every production compile-time payload through `OUT_DIR`. + - Boundaries (in/out of scope): In — build-script source/tool discovery, deterministic Pkl invocation, rerun directives, staging of hooks/schemas/migrations, generated Rust manifests, setup/policy/config/Agent Trace include call sites, removal of `cli/src/generated_migrations.rs`, and focused embedding tests. Out — deleting committed generated target trees or changing publication/release orchestration. + - Dependencies: none + - Done when: A Nix-dev-shell Cargo build generates the complete target payload under its build-script `OUT_DIR`, leaves source directories unchanged, all production static includes resolve through `OUT_DIR`, and targeted setup/config/policy/Agent Trace/migration tests pass. + - Verification notes (commands or checks): `nix develop -c sh -c 'cd cli && cargo clean && cargo test setup && cargo test config && cargo test agent_trace && cargo test auth_db'`; inspect `cli/target/debug/build/shared-context-engineering-*/out/`; `git status --short cli/src cli/assets config`. + - Implementation evidence: `cli/build.rs` now evaluates `config/pkl/generate.pkl` into `OUT_DIR/pkl-generated`, stages hooks, Agent Trace schema, and migrations under `OUT_DIR/static`, and generates both Rust manifests in `OUT_DIR`; production setup, policy, config-schema, Agent Trace, and migration includes now resolve from `OUT_DIR`, and the source-tree migration manifest was removed. + - Verification evidence: The documented clean targeted test command passed (setup 7, config 22, agent_trace 44, auth_db 2); the post-change focused setup suite passed 8 tests including generated-target/static-hook inventory coverage; `cargo clippy --all-targets -- -D warnings` passed; inspection confirmed generated target/static/manifest files under `cli/target/debug/build/shared-context-engineering-*/out/` and no build-created changes under `cli/assets` or `config`. + +- [x] T02: `Embed a self-contained generated payload in published crates` (status:complete) + - Task ID: T02 + - Goal: Make crates.io packaging generate a complete fallback payload from canonical Pkl sources in a temporary clean workspace and embed only that payload in the staged crate for Pkl-free downstream builds. + - Boundaries (in/out of scope): In — package-preparation script, dedicated ignored package-staging path, `cli/Cargo.toml` include inventory, build-script fallback selection and diagnostics, crates.io publish workflow, clean-copy package verification, and deterministic fallback inventory checks. Out — requiring downstream Cargo users to install Pkl or retaining `cli/assets/generated/` as a normal repository-build input. + - Dependencies: T01 + - Done when: `cargo package` contains exactly the required generated/static fallback files, an unpacked package builds with no Pkl and no parent Pkl/config tree, missing or incomplete fallback data fails actionably, and repository builds continue to prefer direct Pkl generation into `OUT_DIR`. + - Verification notes (commands or checks): prepare a temporary clean repository copy; run the updated package-preparation script and `nix develop -c cargo package --manifest-path /cli/Cargo.toml --locked --allow-dirty`; inspect `cargo package --list`; unpack and build the `.crate` with Cargo/Rust available but Pkl absent. + - Implementation evidence: The package-preparation script now evaluates canonical Pkl twice into an ignored `cli/package-fallback/`, rejects nondeterminism, stages hooks, schemas, and migrations, and writes an exact SHA-256 inventory; `cli/build.rs` prefers repository Pkl sources but validates and copies that fallback into `OUT_DIR` for packaged crates, while `cli/Cargo.toml` and the crates.io workflow include and prepare only the packaging payload. + - Verification evidence: A clean temporary repository copy prepared and packaged 296 files successfully; package-list inspection found 81 fallback entries and no legacy `assets/`, `migrations/`, or parent `config/` inputs; the unpacked crate built successfully with Pkl removed from `PATH`; deleting a fallback file produced the expected actionable inventory-mismatch failure; repository `cargo test setup` passed 8 tests and `cargo clippy --all-targets -- -D warnings` passed. + +- [x] T03: `Remove committed generated targets and align build channels` (status:complete) + - Task ID: T03 + - Goal: Delete the generated OpenCode, Claude, and Pi config trees; replace committed-output parity with ephemeral deterministic inventory validation; and align Nix, Flatpak, and release builds with direct Pkl generation or packaging-only fallback preparation. + - Boundaries (in/out of scope): In — removal of `config/.opencode`, `config/.claude`, and `config/.pi`; `config/pkl/check-generated.sh`; `pkl-parity`; source filters and build inputs in `flake.nix`; removal of `cli/assets/generated/` preparation; Flatpak manifest source and static validation; generated Flatpak manifest regeneration; release/package helper call sites; obsolete path constants/tests; and contributor documentation. Out — changing canonical workflow content, target inventories, install destinations, release artifact formats, or supported channels. + - Dependencies: T02 + - Done when: No generated target directory or general-purpose CLI generated mirror remains in the repository, the generation check proves repeatable exact output in temporary directories and rejects legacy paths, Crane builds run the Pkl-to-`OUT_DIR` path, Flatpak has an explicit ephemeral fallback path when Pkl is unavailable, and all targeted Nix/Flatpak checks pass. + - Verification notes (commands or checks): `test ! -e config/.opencode && test ! -e config/.claude && test ! -e config/.pi`; run `nix run .#pkl-check-generated` twice and compare its temporary inventories; `nix flake check`; on Linux, `nix run .#regenerate-flatpak-manifest` followed by `nix run .#sce-flatpak -- validate`; search active build definitions for removed generated paths. + - Implementation evidence: Removed the committed OpenCode, Claude, Pi, generated SCE schema, and legacy `cli/assets/generated` outputs; replaced parity snapshots with two-pass ephemeral SHA-256 inventory validation; routed Crane source builds through canonical Pkl inputs and `OUT_DIR`; removed obsolete source-tree asset path helpers; and changed Flatpak manifests/helpers to stage a temporary packaging fallback before entering the Pkl-free Flatpak build sandbox. + - Verification evidence: Two consecutive `nix run .#pkl-check-generated` runs reported the same 73-file inventory digest (`605e7d406bd56047f76b8eecff3f53e4226e208133166225c34d868de032faae`); legacy-path and diff checks passed; `nix run .#regenerate-flatpak-manifest` and `nix run .#sce-flatpak -- validate` passed; a release Flatpak source package contained the fallback inventory and representative generated payload; and `nix flake check` passed all checks. + +## Open questions + +None. The user explicitly chose ephemeral `OUT_DIR` generation and removal of all three committed generated target trees, while retaining the earlier packaging requirement for a self-contained crates.io artifact. diff --git a/context/sce/agent-trace-embedded-schema-validation.md b/context/sce/agent-trace-embedded-schema-validation.md index 66379cdb..81cbfa6d 100644 --- a/context/sce/agent-trace-embedded-schema-validation.md +++ b/context/sce/agent-trace-embedded-schema-validation.md @@ -10,7 +10,7 @@ Current internal validation seam for Agent Trace JSON in the Rust CLI. ## Current behavior -- The CLI embeds the schema at compile time via `include_str!` from the crate-local mirror at `assets/generated/config/schema/agent-trace.schema.json`, which is prepared during Nix builds (via `flake.nix postUnpack`) and publish-prep (via `scripts/prepare-cli-generated-assets.sh`). The canonical source remains at `config/schema/agent-trace.schema.json`. Validation does not read the schema from disk at runtime. +- The canonical schema remains at `config/schema/agent-trace.schema.json`. For repository builds, `cli/build.rs` copies it to `OUT_DIR/static/schema/agent-trace.schema.json`, and the CLI embeds that staged file at compile time via `include_str!`. Validation does not read the schema from disk at runtime; channel-specific package fallback preparation remains a distribution concern. - `agent_trace_schema_validator()` compiles the embedded schema once and caches the `jsonschema::Validator` in a `OnceLock`. - `validate_agent_trace_value(&serde_json::Value)` validates already-parsed JSON values against the embedded schema. - `validate_agent_trace_json(&str)` parses a JSON string and then validates it against the embedded schema. diff --git a/context/sce/bash-policy-satisfied-by-wrapper-exemption.md b/context/sce/bash-policy-satisfied-by-wrapper-exemption.md index 3690f5f5..b2148b1b 100644 --- a/context/sce/bash-policy-satisfied-by-wrapper-exemption.md +++ b/context/sce/bash-policy-satisfied-by-wrapper-exemption.md @@ -53,7 +53,7 @@ The design point: policies declaring no `satisfied_by` cannot be laundered by wr - `cli/src/services/bash_policy.rs` (`NormalizedSegment`, `normalize_segment`, `policy_is_satisfied_by_wrapper`, `select_matching_policy`) - `cli/src/services/config/policy.rs` (`CustomBashPolicyEntry.satisfied_by`, `parse_custom_bash_policy_satisfied_by`, text-summary rendering) - `cli/src/services/config/schema.rs` (`ParsedCustomBashPolicyEntryDocument.satisfied_by`) -- `config/pkl/base/sce-config-schema.pkl` and generated `config/schema/sce-config.schema.json` + `cli/assets/generated/config/schema/sce-config.schema.json` +- `config/pkl/base/sce-config-schema.pkl`, with repository builds generating and embedding `OUT_DIR/pkl-generated/config/schema/sce-config.schema.json` - `.sce/config.json` (all ten `use-nix-for-*` custom entries now declare their `nix shell nixpkgs#` satisfying wrapper) - `context/sce/bash-tool-policy-enforcement-contract.md` (parent contract) diff --git a/context/sce/cli-cargo-distribution-contract.md b/context/sce/cli-cargo-distribution-contract.md index 48c6fb8d..91a63de9 100644 --- a/context/sce/cli-cargo-distribution-contract.md +++ b/context/sce/cli-cargo-distribution-contract.md @@ -4,17 +4,20 @@ This file captures the implemented Cargo distribution slice from `context/plans/ ## Package posture -- The published crate name is `sce`. +- The published crate name is `shared-context-engineering`; it installs the `sce` binary. - `cli/Cargo.toml` keeps crates.io-facing metadata enabled for publication. - `cli/README.md` is the crate-facing install guidance source referenced by Cargo/crates.io surfaces. -- `cli/assets/generated/` is an ephemeral crate-local mirror of generated setup/config assets prepared from canonical `config/` outputs before Cargo packaging/builds; `cli/build.rs` and `cli/src/services/config/mod.rs` consume that mirror instead of relying on committed crate snapshots or workspace-external generated paths. +- Repository Cargo builds evaluate canonical Pkl inputs directly into Cargo `OUT_DIR` and do not consume `cli/assets/generated/` or the packaging fallback. +- Before packaging, `scripts/prepare-cli-generated-assets.sh` evaluates canonical Pkl twice, rejects nondeterministic output, stages generated targets plus hooks, schemas, and migrations under ignored `cli/package-fallback/`, and writes `SHA256SUMS` for the exact payload. +- Published crates include only the packaging fallback, Rust sources, and crate metadata. In an unpacked crate, `cli/build.rs` validates the fallback inventory and copies it into the consumer's `OUT_DIR`; downstream Cargo builds do not require Pkl or parent repository paths. +- Missing or changed fallback files fail the build with guidance to recreate the package through the preparation script. When canonical repository Pkl sources exist, `build.rs` always prefers direct generation and does not silently fall back when Pkl execution fails. ## Publish workflow - `.github/workflows/publish-crates.yml` is the dedicated crates.io publish workflow. - It triggers from `release.published` and from manual `workflow_dispatch`. - It validates parity across the requested release tag (`v`), repo-root `.version`, and `cli/Cargo.toml` before any publish step runs. -- It copies the checked-out repository into a temporary clean workspace, prepares the ephemeral `cli/assets/generated/` mirror there from canonical `config/` outputs, and runs Cargo packaging/publish from that clean workspace. +- It copies the checked-out repository into a temporary clean workspace and runs the package-fallback preparation script from that copy's Nix dev shell before Cargo packaging or publication. - Manual dispatch supports `dry_run: true` by default so maintainers can verify packaging without publishing. - Manual dispatch also supports `prerelease: true`; GitHub prerelease events are treated as prerelease publish runs automatically. - When a publish run is marked prerelease, the workflow requires `.version` to include semver prerelease metadata such as `-alpha.1`, `-beta.1`, or `-rc.1` before publishing. Crates.io has no npm-style dist-tag channel, so the semver prerelease version is the crate prerelease marker. @@ -22,8 +25,8 @@ This file captures the implemented Cargo distribution slice from `context/plans/ ## Supported Cargo install paths -- crates.io: `cargo install sce` -- Git repository: `cargo install --git https://github.com/crocoder-dev/shared-context-engineering sce --locked` +- crates.io: `cargo install shared-context-engineering --locked` +- Git repository: `cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked` - Local checkout: `cargo install --path cli --locked` ## Scope notes diff --git a/context/sce/cli-first-install-channels-contract.md b/context/sce/cli-first-install-channels-contract.md index 010c4ca2..fb13d9a3 100644 --- a/context/sce/cli-first-install-channels-contract.md +++ b/context/sce/cli-first-install-channels-contract.md @@ -38,7 +38,7 @@ No other install channels are in scope for the current implementation stage. - The Flatpak application ID is `dev.crocoder.sce`. - The Flatpak manifest model is a Flathub-style release-source manifest plus a Nix-generated local checkout-source manifest/override for local builds from the current checkout. -- The Flatpak build must use the standard source-build pattern for Rust CLI applications, including the Freedesktop SDK Rust extension, offline Cargo dependency sources generated from `cli/Cargo.lock`, and build-time preparation of `cli/assets/generated/config/**` from checked-in `config/` inputs. +- The Flatpak build uses the Freedesktop SDK Rust extension and offline Cargo dependency sources generated from `cli/Cargo.lock`. Because Pkl is unavailable in the sandbox, Nix-side helpers prepare a temporary checksummed fallback from canonical Pkl/static inputs and the manifest stages it into `cli/package-fallback` before the Cargo source build. - Runtime Git access uses a host `git` bridge: install `/app/bin/git` as a wrapper that delegates to `flatpak-spawn --host git`, with the required Flatpak permission for `org.freedesktop.Flatpak`. - Nix-provided Flatpak commands/checks are orchestration only: they may provide `flatpak-builder`, AppStream validation, Flatpak linting, wrapper scripts, and generated local manifests/overrides, but they must not bypass the Flatpak source build with a Nix-built `sce` binary. diff --git a/context/sce/flatpak-distribution-patterns.md b/context/sce/flatpak-distribution-patterns.md index beac968b..f190c833 100644 --- a/context/sce/flatpak-distribution-patterns.md +++ b/context/sce/flatpak-distribution-patterns.md @@ -15,7 +15,7 @@ Implementation conventions for the source-built `dev.crocoder.sce` Flatpak chann - The checked-in YAML is a generated artifact regenerated by `nix run .#regenerate-flatpak-manifest` and guarded by `flatpak-manifest-parity`. - Generate `packaging/flatpak/cargo-sources.json` from `cli/Cargo.lock` via a Nix derivation wrapping `flatpak-builder-tools`/`flatpak-cargo-generator.py`, guarded by `cargo-sources-parity`. - Keep Flatpak validation in dedicated Nix-built validator scripts under `nix/flatpak/`: static manifest validation, release-version parity, and local-manifest validation are Bash-owned. No `python3 - <<'PY'` heredoc in `sce-flatpak.sh`. -- Keep checked-in Flatpak packaging under `packaging/flatpak/`: source-build manifest (generated), AppStream metadata, host-git wrapper source, Cargo source descriptor (generated), and a thin imperative `sce-flatpak.sh` with no manifest text rewriting and no embedded Python. +- Keep checked-in Flatpak packaging under `packaging/flatpak/`: source-build manifest (generated), AppStream metadata, host-git wrapper source, Cargo source descriptor (generated), and a thin imperative `sce-flatpak.sh`. Generated assistant payloads are not checked in. ## Flake app surface @@ -25,12 +25,13 @@ Implementation conventions for the source-built `dev.crocoder.sce` Flatpak chann ## Local and release builds -- For local builds, preserve the release-source manifest plus local-checkout override model (produced by the same Nix manifest function) so the canonical manifest remains suitable for Flathub review while checkout builds remain ergonomic. +- For local builds, preserve the release-source manifest plus local-checkout override model produced by the same Nix manifest function. +- Flatpak's sandbox does not provide Pkl. Before generating a local or release manifest, `sce-flatpak.sh` runs the canonical package-fallback preparer on the host/Nix side into a temporary `cli-package-fallback/` support directory. The manifest declares that directory as a `type: dir` source with destination `cli/package-fallback`; sandboxed Cargo then validates and copies it into `OUT_DIR`. - Keep default-flake validation static/AppStream-only, deterministic, and offline; full `flatpak-builder` source builds are invoked only through `release-flatpak-bundle` (CI) or `sce-flatpak ` (developer opt-in). ## Release assets -- For GitHub Release source-manifest assets, package only source-manifest metadata/support files (`dev.crocoder.sce.yml`, AppStream metadata, `cargo-sources.json`, and `git-host-bridge`) into `sce-v-flatpak-manifest.tar.gz` plus checksum/JSON metadata. +- For GitHub Release source-manifest assets, package the manifest, AppStream metadata, Cargo sources, host-git bridge, and ephemeral checksummed `cli-package-fallback/` support directory into `sce-v-flatpak-manifest.tar.gz` plus checksum/JSON metadata. This remains source-built: the fallback contains generated source/static payloads, not a compiled `sce` binary. - When staging a Flatpak source-manifest release package, pin the packaged manifest's git source to the release commit without mutating the checked-in file. - For GitHub Release bundle assets, build the `.flatpak` bundle from source inside Flatpak using `flatpak-builder` + `flatpak build-bundle`, emit per-architecture bundle files (`sce-v-x86_64.flatpak` / `sce-v-aarch64.flatpak`) plus SHA-256 checksum and JSON metadata with `asset_type: flatpak-bundle`. - Do not add Flatpak publication beyond the approved GitHub Release source-manifest and bundle asset upload, automatic Flathub submission, prebuilt Flatpak binaries/bundles, OSTree repositories, or workflow-side release-version bumps. @@ -46,7 +47,7 @@ Implementation conventions for the source-built `dev.crocoder.sce` Flatpak chann - Expose shared CLI release packaging through root-flake apps (`release-artifacts`, `release-manifest`, `release-npm-package`, `release-flatpak-package`, `release-flatpak-bundle`). - Keep GitHub Releases as the canonical publication surface. - Keep crates.io and npm registry publication as separate downstream publish stages that consume already-versioned checked-in package metadata. -- For Cargo publish, prepare generated setup/config payload into an ephemeral crate-local mirror (`cli/assets/generated/**`), publish from a clean workspace when `--allow-dirty` would otherwise be required. +- For Cargo publish, prepare the checksummed payload under ignored `cli/package-fallback/` in a temporary clean workspace; never restore `cli/assets/generated/**`. - For npm, download the merged release manifest plus detached signature, verify with the bundled npm public key before trusting any checksum, then download the already-built native release archive. See also: [cli-first-install-channels-contract.md](cli-first-install-channels-contract.md), [cli-release-artifact-contract.md](cli-release-artifact-contract.md), [cli-npm-distribution-contract.md](cli-npm-distribution-contract.md), [cli-cargo-distribution-contract.md](cli-cargo-distribution-contract.md), [../patterns.md](../patterns.md), [../context-map.md](../context-map.md). diff --git a/context/sce/generated-opencode-plugin-registration.md b/context/sce/generated-opencode-plugin-registration.md index 470445c6..f07d46ec 100644 --- a/context/sce/generated-opencode-plugin-registration.md +++ b/context/sce/generated-opencode-plugin-registration.md @@ -17,7 +17,7 @@ The generated-config pipeline now has one canonical Pkl-authored source for Open ## OpenCode generated outputs - `config/pkl/renderers/opencode-content.pkl` renders the `opencodeConfig` artifact with the shared plugin registration. -- `config/pkl/generate.pkl` writes that artifact to `config/.opencode/opencode.json`. +- `config/pkl/generate.pkl` writes that artifact to payload-relative `config/.opencode/opencode.json` beneath the selected temporary/`OUT_DIR` root. - The generated OpenCode profile serializes `plugin: ["./plugins/sce-bash-policy.ts", "./plugins/sce-agent-trace.ts"]`. - The registered generated plugin files are `config/.opencode/plugins/sce-bash-policy.ts` and `config/.opencode/plugins/sce-agent-trace.ts`. The removed `config/automated/.opencode` profile has no plugin manifest or generated plugin copies. @@ -32,15 +32,13 @@ The generated-config pipeline now has one canonical Pkl-authored source for Open ## Ownership and edit policy -- Treat `config/.opencode/opencode.json` and the corresponding generated plugin files under `config/.opencode/plugins/` as generated-owned artifacts. -- When OpenCode plugin registration changes, edit canonical sources under `config/pkl/` (`config/pkl/base/opencode.pkl`, `config/pkl/renderers/common.pkl`, the OpenCode renderer modules, and `config/pkl/generate.pkl` when ownership wiring changes) instead of patching generated manifests directly. +- Treat the `config/.opencode/opencode.json` and `config/.opencode/plugins/` names as ephemeral payload layouts. The repository must not contain those generated paths. +- When OpenCode plugin registration changes, edit canonical sources under `config/pkl/` and `config/lib/`, then inspect a temporary generation or Cargo `OUT_DIR` rather than patching generated manifests. - Do not broaden this contract to third-party or user-supplied plugins without an explicit plan/task that defines new ownership and scope rules. ## Verification -- Inspect `config/.opencode/opencode.json` for the generated `plugin` field. -- Inspect `config/.opencode/plugins/sce-bash-policy.ts` and `config/.opencode/plugins/sce-agent-trace.ts` for the generated plugin implementations. -- Assert `config/automated/.opencode` is absent. -- Verify `config/.claude/settings.json` contains the generated `PreToolUse` `Bash` policy hook, verify `config/.claude/hooks/run-sce-or-show-install-guidance.sh` contains the missing-CLI guidance path, and verify `config/.claude/` still contains no Claude bash-policy TypeScript runtime files. +- Run `nix run .#pkl-check-generated` and inspect an explicit temporary generation root when field-level review is needed. +- Verify the temporary OpenCode manifest/plugin files and Claude settings/hook helper, while asserting repository `config/.opencode`, `config/.claude`, and `config/.pi` paths remain absent. See also: [../overview.md](../overview.md), [../architecture.md](../architecture.md), [../glossary.md](../glossary.md) diff --git a/context/sce/pi-extension-runtime.md b/context/sce/pi-extension-runtime.md index d6d87560..f1d48603 100644 --- a/context/sce/pi-extension-runtime.md +++ b/context/sce/pi-extension-runtime.md @@ -2,9 +2,9 @@ Project-local Pi extension that wires the Pi coding agent into SCE runtime systems. Source of truth: `config/lib/pi-plugin/sce-pi-extension.ts`, emitted -verbatim by `config/pkl/generate.pkl` to `config/.pi/extensions/sce/index.ts` -(same source-to-generated pattern as the OpenCode plugins under -`config/lib/{bash-policy-plugin,agent-trace-plugin}/`). +verbatim by `config/pkl/generate.pkl` to payload-relative +`config/.pi/extensions/sce/index.ts` beneath Cargo `OUT_DIR`, temporary previews, +or packaging fallbacks. ## Registration model @@ -80,10 +80,10 @@ verbatim by `config/pkl/generate.pkl` to `config/.pi/extensions/sce/index.ts` ## Verification -- `nix develop -c ./config/pkl/check-generated.sh` covers - `config/.pi/extensions` in its parity paths. -- Regeneration must be diff-clean; edit the `config/lib/pi-plugin/` source, - never the generated copy. +- `nix run .#pkl-check-generated` requires `config/.pi/extensions/sce/index.ts` + in both temporary inventories and rejects a committed `config/.pi` tree. +- Edit `config/lib/pi-plugin/` and inspect temporary output when needed; never + create or edit a repository generated copy. ## Rust-side session provenance @@ -95,11 +95,12 @@ unprefixed. ## Asset pipeline, install, and doctor coverage -- `scripts/prepare-cli-generated-assets.sh` copies the whole `config/.pi` tree - (including `extensions/sce/index.ts`) into - `cli/assets/generated/config/pi/`; `cli/build.rs` embeds that tree wholesale +- For repository builds, `cli/build.rs` evaluates the canonical Pkl model into + `OUT_DIR/pkl-generated` and embeds the generated `config/.pi` tree wholesale as `PI_EMBEDDED_ASSETS`, so `sce setup --pi` installs the extension to repo-root `.pi/extensions/sce/index.ts` with no per-asset enumeration. + Pkl-free package fallback preparation is owned by the Cargo distribution + path rather than this runtime contract. - `sce doctor` buckets embedded Pi assets under `extensions/` into a `Pi extensions` integration group (`collect_pi_integration_groups()` in `cli/src/services/doctor/inspect.rs`, `pi_asset::EXTENSIONS_DIR`), reporting diff --git a/context/sce/setup-githooks-hook-asset-packaging.md b/context/sce/setup-githooks-hook-asset-packaging.md index a926c606..c9b1056d 100644 --- a/context/sce/setup-githooks-hook-asset-packaging.md +++ b/context/sce/setup-githooks-hook-asset-packaging.md @@ -12,7 +12,7 @@ Task `sce-setup-githooks-any-repo` `T02` defines how required git-hook templates - `commit-msg` - `post-commit` -These templates are emitted into `OUT_DIR/setup_embedded_assets.rs` as `HOOK_EMBEDDED_ASSETS` with deterministic sorted relative paths. +The build script copies these templates to `OUT_DIR/static/hooks/`, then emits them into `OUT_DIR/setup_embedded_assets.rs` as `HOOK_EMBEDDED_ASSETS` with deterministic sorted relative paths. Production Rust includes therefore resolve through `OUT_DIR` rather than back into `cli/assets/`. All three templates are POSIX `sh` scripts with `set -eu`. Before invoking `sce`, each checks `command -v sce`; when the CLI is unavailable, it prints branded, multiline installation guidance to stderr and exits successfully so Git operations are not blocked solely by a missing local CLI installation. ANSI styling is emitted only when stderr is a terminal; redirected output remains plain text. Failures from an available `sce` command continue to propagate through `exec`. diff --git a/context/sce/setup-repo-local-config-bootstrap.md b/context/sce/setup-repo-local-config-bootstrap.md index 60b377aa..c6ff4150 100644 --- a/context/sce/setup-repo-local-config-bootstrap.md +++ b/context/sce/setup-repo-local-config-bootstrap.md @@ -38,4 +38,4 @@ After config asset installation succeeds for a non-interactive target (`--openco - The git-repo gate (`ensure_git_repository`) was introduced in T01 of the same plan. - Local bootstrap (repo config + local DB init) is independent of config install and hook install; it runs before both. -- The bootstrap payload matches the `$schema` declaration accepted by the config service's startup config loading and the Pkl-authored JSON Schema at `config/schema/sce-config.schema.json`. +- The bootstrap payload matches the `$schema` declaration accepted by startup config loading and the Pkl-authored JSON Schema embedded from Cargo `OUT_DIR`. diff --git a/context/sce/shared-turso-db.md b/context/sce/shared-turso-db.md index 0b0a2b8a..3952ce61 100644 --- a/context/sce/shared-turso-db.md +++ b/context/sce/shared-turso-db.md @@ -8,7 +8,7 @@ - `db_name()` returns a human-readable diagnostic name. - `db_path()` resolves the canonical database file path. - `migrations()` returns ordered embedded migration `(id, sql)` pairs. -- `cli/build.rs` scans immediate `cli/migrations//*.sql` directories at compile time and writes `cli/src/generated_migrations.rs` with database-named migration constants (`AGENT_TRACE_REPOSITORY_MIGRATIONS`, `AUTH_MIGRATIONS`, etc.). Generated entries use the filename stem as the migration ID, embed SQL with `include_str!`, and are sorted by the numeric prefix before the first `_`. +- `cli/build.rs` scans immediate `cli/migrations//*.sql` directories at compile time, copies them into `OUT_DIR/static/migrations`, and writes `OUT_DIR/generated_migrations.rs` with database-named migration constants (`AGENT_TRACE_REPOSITORY_MIGRATIONS`, `AUTH_MIGRATIONS`, etc.). Generated entries use the filename stem as the migration ID, embed the staged SQL with `include_str!`, and are sorted by the numeric prefix before the first `_`. - `TursoDb`: generic unencrypted adapter that owns: - tokio current-thread runtime creation - Turso local database open/connect flow using `turso::Builder::new_local()` with `experimental_multiprocess_wal(true)` so concurrent `sce` processes can safely access the same local database without WAL lock contention diff --git a/flake.nix b/flake.nix index 59512b3a..65cf8ef1 100644 --- a/flake.nix +++ b/flake.nix @@ -136,11 +136,11 @@ tursoCraneLib = (crane.mkLib pkgs).overrideToolchain (_: tursoToolchain); workspaceRoot = ./.; - generatedConfigFileset = pkgs.lib.fileset.unions [ - (pkgs.lib.fileset.maybeMissing ./config/.opencode) - (pkgs.lib.fileset.maybeMissing ./config/.claude) - (pkgs.lib.fileset.maybeMissing ./config/.pi) - ./config/schema/sce-config.schema.json + cliBuildInputFileset = pkgs.lib.fileset.unions [ + ./config/pkl + ./config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts + ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts + ./config/lib/pi-plugin/sce-pi-extension.ts ./config/schema/agent-trace.schema.json ]; workspaceSrc = pkgs.lib.fileset.toSource { @@ -153,7 +153,7 @@ (pkgs.lib.fileset.maybeMissing ./cli/src/services/patch/fixtures) (pkgs.lib.fileset.maybeMissing ./cli/src/services/structured_patch/fixtures) (pkgs.lib.fileset.maybeMissing ./cli/migrations) - generatedConfigFileset + cliBuildInputFileset (pkgs.lib.fileset.maybeMissing ./cli/assets/hooks) ]; }; @@ -197,18 +197,18 @@ ]; }; - pklParitySrc = pkgs.lib.fileset.toSource { + pklGeneratedCheckSrc = pkgs.lib.fileset.toSource { root = workspaceRoot; fileset = pkgs.lib.fileset.unions [ ./config/pkl + ./config/lib/pi-plugin/sce-pi-extension.ts + ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts + ./config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts (pkgs.lib.fileset.maybeMissing ./config/.opencode) (pkgs.lib.fileset.maybeMissing ./config/.claude) (pkgs.lib.fileset.maybeMissing ./config/.pi) - (pkgs.lib.fileset.maybeMissing ./config/automated/.opencode) (pkgs.lib.fileset.maybeMissing ./config/schema/sce-config.schema.json) - ./config/lib/pi-plugin/sce-pi-extension.ts - ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts - ./config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts + (pkgs.lib.fileset.maybeMissing ./cli/assets/generated) ]; }; @@ -274,16 +274,9 @@ commonCargoArgs = cargoBaseArgs // { pname = "sce"; src = workspaceSrc; + nativeBuildInputs = cargoBaseArgs.nativeBuildInputs ++ [ pkgs.pkl ]; postUnpack = '' - mkdir -p "$sourceRoot/cli/assets/generated/config" - cp -R ${./config/.opencode} "$sourceRoot/cli/assets/generated/config/opencode" - cp -R ${./config/.claude} "$sourceRoot/cli/assets/generated/config/claude" - cp -R ${./config/.pi} "$sourceRoot/cli/assets/generated/config/pi" - mkdir -p "$sourceRoot/cli/assets/generated/config/schema" - cp ${./config/schema/sce-config.schema.json} "$sourceRoot/cli/assets/generated/config/schema/sce-config.schema.json" - cp ${./config/schema/agent-trace.schema.json} "$sourceRoot/cli/assets/generated/config/schema/agent-trace.schema.json" - cd "$sourceRoot/cli" sourceRoot="." ''; @@ -452,7 +445,7 @@ echo "- tsc: $(version_of tsc)" echo "- tsserver-lsp: $(version_of typescript-language-server)" echo "- rust: $(version_of rustc)" - echo "- pkl-generate: nix run .#pkl-generate" + echo "- pkl-generate: nix run .#pkl-generate -- " echo "- pkl-check-generated: nix run .#pkl-check-generated" echo "- release-artifacts: nix run .#release-artifacts -- --help" echo "- native-portability-audit: nix run .#native-portability-audit -- --help" @@ -500,7 +493,15 @@ repo_root="$(pwd)" fi - exec nix develop "''${repo_root}" -c pkl eval -m "''${repo_root}" "''${repo_root}/config/pkl/generate.pkl" + if [ "$#" -ne 1 ]; then + printf 'Usage: pkl-generate \n' >&2 + exit 2 + fi + + output_dir="$1" + mkdir -p "''${output_dir}" + output_dir="$(cd "''${output_dir}" && pwd)" + exec nix develop "''${repo_root}" -c pkl eval -m "''${output_dir}" "''${repo_root}/config/pkl/generate.pkl" ''; }; @@ -1025,6 +1026,7 @@ pkgs.git pkgs.gnutar pkgs.gzip + pkgs.pkl pkgs.python3 ] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ @@ -1084,6 +1086,7 @@ export SCE_FLATPAK_COMMIT_MANIFEST_TEMPLATE="${flatpakManifest.commitManifestTemplate}" export SCE_FLATPAK_LOCAL_PATH_PLACEHOLDER="${flatpakManifest.localPathPlaceholder}" export SCE_FLATPAK_COMMIT_PLACEHOLDER="${flatpakManifest.commitPlaceholder}" + export SCE_FLATPAK_FALLBACK_SOURCE_DIRECTORY="${flatpakManifest.fallbackSourceDirectory}" export SCE_FLATPAK_STATIC_CHECK="${flatpakStaticCheckApp}/bin/flatpak-static-check" export SCE_FLATPAK_VERSION_PARITY_CHECK="${flatpakVersionParityCheckApp}/bin/flatpak-version-parity-check" export SCE_FLATPAK_LOCAL_MANIFEST_CHECK="${flatpakLocalManifestCheckApp}/bin/flatpak-local-manifest-check" @@ -1130,100 +1133,26 @@ mkdir -p "$out" ''; - pklParityCheck = - pkgs.runCommand "pkl-parity-check" + pklGeneratedCheck = + pkgs.runCommand "pkl-generated-check" { nativeBuildInputs = [ - pkgs.git + pkgs.coreutils + pkgs.diffutils pkgs.pkl ]; } '' set -euo pipefail - # Copy only the Pkl authoring inputs and generated outputs that - # this parity check reads, so unrelated repository changes do not - # invalidate the cheap generated-output drift check. - cp -r "${pklParitySrc}" ./repo + cp -r "${pklGeneratedCheckSrc}" ./repo chmod -R u+w ./repo cd ./repo - export GIT_PAGER=cat - - tmp_dir="$(mktemp -d)" - cleanup() { - rm -rf "$tmp_dir" - } - trap cleanup EXIT - - pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null - pkl eval -m "$tmp_dir" config/pkl/generate.pkl >/dev/null - - paths=( - "config/.opencode/agent" - "config/.opencode/command" - "config/.opencode/skills" - "config/.opencode/lib" - "config/.opencode/plugins" - "config/.opencode/opencode.json" - "config/.claude/commands" - "config/.claude/skills" - "config/.claude/hooks" - "config/.claude/settings.json" - "config/.pi/prompts" - "config/.pi/skills" - "config/.pi/extensions" - "config/schema/sce-config.schema.json" - ) - - forbidden_paths=( - "config/automated/.opencode" - "config/.claude/agents" - ) - - stale=0 - for path in "''${paths[@]}"; do - if [[ ! -e "$tmp_dir/$path" ]]; then - stale=1 - printf 'Generator did not emit required output at %s\n' "$path" - continue - fi - - if [[ ! -e "$path" ]]; then - stale=1 - printf 'Required generated output is missing at %s\n' "$path" - continue - fi - - if ! git diff --no-index --exit-code -- "$tmp_dir/$path" "$path" >/dev/null 2>&1; then - stale=1 - printf 'Generated output drift detected at %s\n' "$path" - git diff --no-index -- "$tmp_dir/$path" "$path" || true - fi - done - - for path in "''${forbidden_paths[@]}"; do - if [[ -e "$tmp_dir/$path" ]]; then - stale=1 - printf 'Generator emitted removed output at %s\n' "$path" - fi - if [[ -e "$path" ]]; then - stale=1 - printf 'Removed generated output still exists at %s\n' "$path" - fi - done - - if [[ "$stale" -ne 0 ]]; then - cat <<'EOF' - Generated files are stale. - - Regenerate with: - nix develop -c pkl eval -m . config/pkl/generate.pkl - EOF - exit 1 - fi + export IN_NIX_SHELL=1 + export SCE_REPO_ROOT="$PWD" + ${pkgs.bash}/bin/bash ./config/pkl/check-generated.sh - printf 'Generated outputs are up to date.\n' mkdir -p "$out" ''; @@ -1513,7 +1442,7 @@ } ); - pkl-parity = pklParityCheck; + pkl-generated = pklGeneratedCheck; npm-bun-tests = npmTests; npm-biome-check = npmBiomeCheck; diff --git a/nix/flatpak/local-manifest-validate.sh b/nix/flatpak/local-manifest-validate.sh index 2126ef3a..018cb8b7 100644 --- a/nix/flatpak/local-manifest-validate.sh +++ b/nix/flatpak/local-manifest-validate.sh @@ -56,6 +56,10 @@ if [[ "$manifest" == *"nix build .#sce"* || "$manifest" == *"nix build .#default errors+=("local manifest references a Nix-built sce binary") fi +if [[ "$manifest" != *"path: cli-package-fallback"* || "$manifest" != *"dest: cli/package-fallback"* ]]; then + errors+=("local manifest does not stage the ephemeral package fallback") +fi + if [[ "$manifest" != *"cargo --offline build --release --manifest-path cli/Cargo.toml --bin sce"* ]]; then errors+=("local manifest no longer runs the Flatpak Cargo source build") fi diff --git a/nix/flatpak/manifest.nix b/nix/flatpak/manifest.nix index fcd9e6eb..6fc6534f 100644 --- a/nix/flatpak/manifest.nix +++ b/nix/flatpak/manifest.nix @@ -14,6 +14,7 @@ let localPathPlaceholder = "__SCE_LOCAL_REPO_PATH__"; commitPlaceholder = "__SCE_RELEASE_COMMIT__"; + fallbackSourceDirectory = "cli-package-fallback"; releaseGitSource = commit: { type = "git"; @@ -51,7 +52,6 @@ let }; }; build-commands = [ - ''bash ./scripts/prepare-cli-generated-assets.sh "$PWD"'' "cargo --offline build --release --manifest-path cli/Cargo.toml --bin sce" "install -Dm755 cli/target/release/sce /app/bin/sce" "install -Dm755 packaging/flatpak/git-host-bridge /app/bin/git" @@ -59,6 +59,11 @@ let ]; sources = [ sceSource + { + type = "dir"; + path = fallbackSourceDirectory; + dest = "cli/package-fallback"; + } { type = "file"; path = "dev.crocoder.sce.metainfo.xml"; @@ -147,5 +152,6 @@ in parityCheck localPathPlaceholder commitPlaceholder + fallbackSourceDirectory ; } diff --git a/nix/flatpak/static-validate.sh b/nix/flatpak/static-validate.sh index 12cf7897..b6890c71 100644 --- a/nix/flatpak/static-validate.sh +++ b/nix/flatpak/static-validate.sh @@ -58,8 +58,13 @@ require_contains() { require_contains "id: dev.crocoder.sce" "manifest app ID is not dev.crocoder.sce" require_contains "command: sce" "manifest command is not sce" require_contains "org.freedesktop.Sdk.Extension.rust-stable" "Rust SDK extension is missing" -require_contains "bash ./scripts/prepare-cli-generated-assets.sh \"\$PWD\"" "generated-asset preparation command is missing" +require_contains "path: cli-package-fallback" "ephemeral package-fallback source is missing" +require_contains "dest: cli/package-fallback" "package-fallback source destination is missing" require_contains "cargo --offline build --release --manifest-path cli/Cargo.toml --bin sce" "offline Cargo source-build command is missing" + +if [[ "$manifest" == *"prepare-cli-generated-assets.sh"* ]]; then + errors+=("manifest attempts to run Pkl fallback preparation inside Flatpak") +fi require_contains "install -Dm755 cli/target/release/sce /app/bin/sce" "sce install command is missing" require_contains "install -Dm755 packaging/flatpak/git-host-bridge /app/bin/git" "host git bridge install command is missing" require_contains "--talk-name=org.freedesktop.Flatpak" "host Flatpak permission is missing" diff --git a/packaging/flatpak/dev.crocoder.sce.yml b/packaging/flatpak/dev.crocoder.sce.yml index cf120e4b..292d647c 100644 --- a/packaging/flatpak/dev.crocoder.sce.yml +++ b/packaging/flatpak/dev.crocoder.sce.yml @@ -7,7 +7,6 @@ finish-args: id: dev.crocoder.sce modules: - build-commands: - - bash ./scripts/prepare-cli-generated-assets.sh "$PWD" - cargo --offline build --release --manifest-path cli/Cargo.toml --bin sce - install -Dm755 cli/target/release/sce /app/bin/sce - install -Dm755 packaging/flatpak/git-host-bridge /app/bin/git @@ -24,6 +23,9 @@ modules: - commit: b7f0fa002fca5f5320791ff5e4abfaadfcddf187 type: git url: https://github.com/crocoder-dev/shared-context-engineering.git + - dest: cli/package-fallback + path: cli-package-fallback + type: dir - dest: packaging/flatpak path: dev.crocoder.sce.metainfo.xml type: file diff --git a/packaging/flatpak/sce-flatpak.sh b/packaging/flatpak/sce-flatpak.sh index 23f7a425..0f8a626c 100755 --- a/packaging/flatpak/sce-flatpak.sh +++ b/packaging/flatpak/sce-flatpak.sh @@ -59,6 +59,18 @@ require_command() { command -v "$1" >/dev/null 2>&1 || die "$1 is required. $2" } +prepare_flatpak_fallback() { + local repo_root="$1" support_dir="$2" + local fallback_source_directory="${SCE_FLATPAK_FALLBACK_SOURCE_DIRECTORY:-}" + [ -n "${fallback_source_directory}" ] \ + || die "prepare_flatpak_fallback: fallback source directory not available; run via 'nix run .#sce-flatpak'" + require_file "${repo_root}/scripts/prepare-cli-generated-assets.sh" + + mkdir -p "${support_dir}" + bash "${repo_root}/scripts/prepare-cli-generated-assets.sh" \ + "${repo_root}" "${support_dir}/${fallback_source_directory}" >&2 +} + ensure_flatpak_user_remote() { printf 'Ensuring Flatpak user remote %s is configured for SDK/runtime dependencies.\n' "${FLATHUB_REMOTE_NAME}" flatpak --user remote-add --if-not-exists --from "${FLATHUB_REMOTE_NAME}" "${FLATHUB_REMOTE_URL}" @@ -90,6 +102,7 @@ generate_local_manifest() { cp "${flatpak_dir}/${METAINFO_NAME}" "${out_dir}/${METAINFO_NAME}" cp "${flatpak_dir}/git-host-bridge" "${out_dir}/git-host-bridge" cp "${flatpak_dir}/cargo-sources.json" "${out_dir}/cargo-sources.json" + prepare_flatpak_fallback "${repo_root}" "${out_dir}" local abs_repo_root; abs_repo_root="$(cd "${repo_root}" && pwd -P)" substitute_placeholder "${SCE_FLATPAK_LOCAL_PATH_PLACEHOLDER}" "${abs_repo_root}" \ "${SCE_FLATPAK_LOCAL_MANIFEST_TEMPLATE}" > "${out_dir}/${MANIFEST_NAME}" @@ -151,12 +164,14 @@ emit_source_manifest_metadata() { "packaged_support_files": [ "${METAINFO_NAME}", "cargo-sources.json", + "cli-package-fallback/", "git-host-bridge" ], "packaged_files": [ "${MANIFEST_NAME}", "${METAINFO_NAME}", "cargo-sources.json", + "cli-package-fallback/", "git-host-bridge" ] } @@ -280,6 +295,7 @@ cmd_release_package() { cp "${flatpak_dir}/${METAINFO_NAME}" "${stage_dir}/${METAINFO_NAME}" cp "${flatpak_dir}/cargo-sources.json" "${stage_dir}/cargo-sources.json" cp "${flatpak_dir}/git-host-bridge" "${stage_dir}/git-host-bridge" + prepare_flatpak_fallback "${repo_root}" "${stage_dir}" chmod 0644 "${stage_dir}/${MANIFEST_NAME}" "${stage_dir}/${METAINFO_NAME}" "${stage_dir}/cargo-sources.json" chmod 0755 "${stage_dir}/git-host-bridge" diff --git a/scripts/prepare-cli-generated-assets.sh b/scripts/prepare-cli-generated-assets.sh old mode 100644 new mode 100755 index a9c88563..30447ac3 --- a/scripts/prepare-cli-generated-assets.sh +++ b/scripts/prepare-cli-generated-assets.sh @@ -5,34 +5,84 @@ repo_root="${1:-}" if [ -z "${repo_root}" ]; then repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" fi +repo_root="$(cd "${repo_root}" && pwd)" -source_opencode="${repo_root}/config/.opencode" -source_claude="${repo_root}/config/.claude" -source_pi="${repo_root}/config/.pi" -source_schema="${repo_root}/config/schema/sce-config.schema.json" -source_agent_trace_schema="${repo_root}/config/schema/agent-trace.schema.json" -target_root="${repo_root}/cli/assets/generated/config" +target_root="${2:-${repo_root}/cli/package-fallback}" +case "${target_root}" in + /*) ;; + *) target_root="$(pwd)/${target_root}" ;; +esac -if [ ! -d "${source_opencode}" ] || [ ! -d "${source_claude}" ] || [ ! -d "${source_pi}" ] || [ ! -f "${source_schema}" ] || [ ! -f "${source_agent_trace_schema}" ]; then +generator="${repo_root}/config/pkl/generate.pkl" +config_lib="${repo_root}/config/lib" + +if [ ! -f "${generator}" ] || [ ! -d "${config_lib}" ]; then cat >&2 </dev/null 2>&1; then + cat >&2 <<'EOF' +pkl is required to prepare the CLI crate fallback payload. +Run this script from the repository Nix dev shell: + nix develop -c ./scripts/prepare-cli-generated-assets.sh [repo-root] [output-dir] +EOF + exit 1 +fi + +for path in \ + "${repo_root}/cli/assets/hooks" \ + "${repo_root}/cli/migrations" \ + "${repo_root}/config/schema/agent-trace.schema.json"; do + if [ ! -e "${path}" ]; then + printf 'Missing static input required for CLI crate packaging: %s\n' "${path}" >&2 + exit 1 + fi +done + +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT + +generate_payload() { + destination="$1" + mkdir -p "${destination}/pkl-generated" "${destination}/static/schema" + ( + cd "${repo_root}" + pkl eval -m "${destination}/pkl-generated" "${generator}" >/dev/null + ) + cp -R "${repo_root}/cli/assets/hooks" "${destination}/static/hooks" + cp -R "${repo_root}/cli/migrations" "${destination}/static/migrations" + cp "${repo_root}/config/schema/agent-trace.schema.json" \ + "${destination}/static/schema/agent-trace.schema.json" +} + +generate_payload "${tmp_root}/first" +generate_payload "${tmp_root}/second" + +if ! diff -qr "${tmp_root}/first" "${tmp_root}/second" >/dev/null; then + printf 'CLI crate fallback generation is not deterministic.\n' >&2 + diff -r "${tmp_root}/first" "${tmp_root}/second" >&2 || true + exit 1 +fi + +rm -rf "${target_root}" +mv "${tmp_root}/first" "${target_root}" + +( + cd "${target_root}" + find pkl-generated static -type f -print \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "${path}" + done > SHA256SUMS +) -printf 'Prepared cli/assets/generated from config/ inputs.\n' +printf 'Prepared deterministic packaging-only fallback at %s\n' "${target_root}" From 58899e01d35a793e91ffb268e84fb9bcc1a82788 Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 20:55:59 +0200 Subject: [PATCH 06/21] config: Generate root OpenCode and Claude workflows Materialize the canonical workflow packages at the repository root for local OpenCode and Claude use while removing superseded agents, commands, and skills from those trees. --- .claude/agents/shared-context-code.md | 60 --- .claude/agents/shared-context-plan.md | 66 ---- .claude/commands/change-to-plan.md | 181 ++++++++- .claude/commands/commit.md | 42 -- .claude/commands/handover.md | 15 - .claude/commands/next-task.md | 208 +++++++++- .claude/commands/validate.md | 148 ++++++- .claude/skills/sce-atomic-commit/SKILL.md | 104 ----- .claude/skills/sce-bootstrap-context/SKILL.md | 57 --- .claude/skills/sce-context-load/SKILL.md | 129 ++++++ .../references/context-brief.yaml | 153 ++++++++ .claude/skills/sce-context-sync/SKILL.md | 93 ----- .claude/skills/sce-handover-writer/SKILL.md | 48 --- .claude/skills/sce-plan-authoring/SKILL.md | 369 ++++++++++++++---- .../references/authoring-contract.yaml | 256 ++++++++++++ .../references/plan-summary.md | 94 +++++ .../references/plan-template.md | 170 ++++++++ .claude/skills/sce-plan-context-sync/SKILL.md | 309 +++++++++++++++ .../references/sync-report.md | 142 +++++++ .claude/skills/sce-plan-review/SKILL.md | 230 +++++++---- .../references/readiness-contract.yaml | 246 ++++++++++++ .claude/skills/sce-task-context-sync/SKILL.md | 311 +++++++++++++++ .../references/sync-report.md | 133 +++++++ .claude/skills/sce-task-execution/SKILL.md | 295 +++++++++++--- .../references/execution-contract.yaml | 306 +++++++++++++++ .../references/implementation-gate.md | 69 ++++ .claude/skills/sce-validation/SKILL.md | 227 +++++++++-- .../references/validation-report.md | 84 ++++ .../references/validation-result.md | 186 +++++++++ .opencode/agent/Shared Context Code.md | 57 +-- .opencode/agent/Shared Context Plan.md | 61 +-- .opencode/command/change-to-plan.md | 184 ++++++++- .opencode/command/commit.md | 45 --- .opencode/command/handover.md | 18 - .opencode/command/next-task.md | 211 ++++++++-- .opencode/command/validate.md | 149 ++++++- .opencode/skills/sce-atomic-commit/SKILL.md | 104 ----- .../skills/sce-bootstrap-context/SKILL.md | 57 --- .opencode/skills/sce-context-load/SKILL.md | 129 ++++++ .../references/context-brief.yaml | 153 ++++++++ .opencode/skills/sce-context-sync/SKILL.md | 93 ----- .opencode/skills/sce-handover-writer/SKILL.md | 48 --- .opencode/skills/sce-plan-authoring/SKILL.md | 369 ++++++++++++++---- .../references/authoring-contract.yaml | 256 ++++++++++++ .../references/plan-summary.md | 94 +++++ .../references/plan-template.md | 170 ++++++++ .../skills/sce-plan-context-sync/SKILL.md | 309 +++++++++++++++ .../references/sync-report.md | 142 +++++++ .opencode/skills/sce-plan-review/SKILL.md | 230 +++++++---- .../references/readiness-contract.yaml | 246 ++++++++++++ .../skills/sce-task-context-sync/SKILL.md | 311 +++++++++++++++ .../references/sync-report.md | 133 +++++++ .opencode/skills/sce-task-execution/SKILL.md | 295 +++++++++++--- .../references/execution-contract.yaml | 306 +++++++++++++++ .../references/implementation-gate.md | 69 ++++ .opencode/skills/sce-validation/SKILL.md | 227 +++++++++-- .../references/validation-report.md | 84 ++++ .../references/validation-result.md | 186 +++++++++ 58 files changed, 7891 insertions(+), 1576 deletions(-) delete mode 100644 .claude/agents/shared-context-code.md delete mode 100644 .claude/agents/shared-context-plan.md delete mode 100644 .claude/commands/commit.md delete mode 100644 .claude/commands/handover.md delete mode 100644 .claude/skills/sce-atomic-commit/SKILL.md delete mode 100644 .claude/skills/sce-bootstrap-context/SKILL.md create mode 100644 .claude/skills/sce-context-load/SKILL.md create mode 100644 .claude/skills/sce-context-load/references/context-brief.yaml delete mode 100644 .claude/skills/sce-context-sync/SKILL.md delete mode 100644 .claude/skills/sce-handover-writer/SKILL.md create mode 100644 .claude/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 .claude/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 .claude/skills/sce-plan-authoring/references/plan-template.md create mode 100644 .claude/skills/sce-plan-context-sync/SKILL.md create mode 100644 .claude/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 .claude/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 .claude/skills/sce-task-context-sync/SKILL.md create mode 100644 .claude/skills/sce-task-context-sync/references/sync-report.md create mode 100644 .claude/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 .claude/skills/sce-task-execution/references/implementation-gate.md create mode 100644 .claude/skills/sce-validation/references/validation-report.md create mode 100644 .claude/skills/sce-validation/references/validation-result.md delete mode 100644 .opencode/command/commit.md delete mode 100644 .opencode/command/handover.md delete mode 100644 .opencode/skills/sce-atomic-commit/SKILL.md delete mode 100644 .opencode/skills/sce-bootstrap-context/SKILL.md create mode 100644 .opencode/skills/sce-context-load/SKILL.md create mode 100644 .opencode/skills/sce-context-load/references/context-brief.yaml delete mode 100644 .opencode/skills/sce-context-sync/SKILL.md delete mode 100644 .opencode/skills/sce-handover-writer/SKILL.md create mode 100644 .opencode/skills/sce-plan-authoring/references/authoring-contract.yaml create mode 100644 .opencode/skills/sce-plan-authoring/references/plan-summary.md create mode 100644 .opencode/skills/sce-plan-authoring/references/plan-template.md create mode 100644 .opencode/skills/sce-plan-context-sync/SKILL.md create mode 100644 .opencode/skills/sce-plan-context-sync/references/sync-report.md create mode 100644 .opencode/skills/sce-plan-review/references/readiness-contract.yaml create mode 100644 .opencode/skills/sce-task-context-sync/SKILL.md create mode 100644 .opencode/skills/sce-task-context-sync/references/sync-report.md create mode 100644 .opencode/skills/sce-task-execution/references/execution-contract.yaml create mode 100644 .opencode/skills/sce-task-execution/references/implementation-gate.md create mode 100644 .opencode/skills/sce-validation/references/validation-report.md create mode 100644 .opencode/skills/sce-validation/references/validation-result.md diff --git a/.claude/agents/shared-context-code.md b/.claude/agents/shared-context-code.md deleted file mode 100644 index b56786a0..00000000 --- a/.claude/agents/shared-context-code.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: shared-context-code -description: Use when the user wants to execute one approved SCE task and sync context. -model: inherit -color: green -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. diff --git a/.claude/agents/shared-context-plan.md b/.claude/agents/shared-context-plan.md deleted file mode 100644 index c81866e7..00000000 --- a/.claude/agents/shared-context-plan.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: shared-context-plan -description: Use when the user needs to create or update an SCE plan before implementation. -model: inherit -color: blue -tools: ["Read", "Glob", "Grep", "Edit", "Write", "Skill", "AskUserQuestion", "Task", "Bash"] ---- - -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. diff --git a/.claude/commands/change-to-plan.md b/.claude/commands/change-to-plan.md index 310ebb5b..556c578e 100644 --- a/.claude/commands/change-to-plan.md +++ b/.claude/commands/change-to-plan.md @@ -1,17 +1,176 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md deleted file mode 100644 index 1192e4f5..00000000 --- a/.claude/commands/commit.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/.claude/commands/handover.md b/.claude/commands/handover.md deleted file mode 100644 index 0e91be08..00000000 --- a/.claude/commands/handover.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/.claude/commands/next-task.md b/.claude/commands/next-task.md index b74c996a..a52e26ff 100644 --- a/.claude/commands/next-task.md +++ b/.claude/commands/next-task.md @@ -1,24 +1,192 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/.claude/commands/validate.md b/.claude/commands/validate.md index ece8cebc..bbaeca4f 100644 --- a/.claude/commands/validate.md +++ b/.claude/commands/validate.md @@ -1,15 +1,145 @@ --- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -Load and follow the `sce-validation` skill. +SCE VALIDATE `$ARGUMENTS` -Input: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/.claude/skills/sce-atomic-commit/SKILL.md b/.claude/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 0d7a3cf4..00000000 --- a/.claude/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: claude ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/.claude/skills/sce-bootstrap-context/SKILL.md b/.claude/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index 2981a743..00000000 --- a/.claude/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: claude ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/.claude/skills/sce-context-load/SKILL.md b/.claude/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..67e569b8 --- /dev/null +++ b/.claude/skills/sce-context-load/SKILL.md @@ -0,0 +1,129 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +compatibility: claude +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/.claude/skills/sce-context-load/references/context-brief.yaml b/.claude/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/.claude/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/.claude/skills/sce-context-sync/SKILL.md b/.claude/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 199413fc..00000000 --- a/.claude/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: claude ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/.claude/skills/sce-handover-writer/SKILL.md b/.claude/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 07a14634..00000000 --- a/.claude/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: claude ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/.claude/skills/sce-plan-authoring/SKILL.md b/.claude/skills/sce-plan-authoring/SKILL.md index 3f1af5d9..1b34665e 100644 --- a/.claude/skills/sce-plan-authoring/SKILL.md +++ b/.claude/skills/sce-plan-authoring/SKILL.md @@ -1,89 +1,290 @@ --- name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. compatibility: claude --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml b/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/.claude/skills/sce-plan-authoring/references/plan-summary.md b/.claude/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/.claude/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/.claude/skills/sce-plan-authoring/references/plan-template.md b/.claude/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/.claude/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/.claude/skills/sce-plan-context-sync/SKILL.md b/.claude/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..96127523 --- /dev/null +++ b/.claude/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,309 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +compatibility: claude +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.claude/skills/sce-plan-context-sync/references/sync-report.md b/.claude/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/.claude/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.claude/skills/sce-plan-review/SKILL.md b/.claude/skills/sce-plan-review/SKILL.md index 69cf6ba0..a55fee1d 100644 --- a/.claude/skills/sce-plan-review/SKILL.md +++ b/.claude/skills/sce-plan-review/SKILL.md @@ -1,91 +1,149 @@ --- name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. compatibility: claude --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/.claude/skills/sce-plan-review/references/readiness-contract.yaml b/.claude/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/.claude/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/.claude/skills/sce-task-context-sync/SKILL.md b/.claude/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..437585c2 --- /dev/null +++ b/.claude/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,311 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +compatibility: claude +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.claude/skills/sce-task-context-sync/references/sync-report.md b/.claude/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..7d5acb94 --- /dev/null +++ b/.claude/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,133 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/.claude/skills/sce-task-execution/SKILL.md b/.claude/skills/sce-task-execution/SKILL.md index d90a14fb..da53bb98 100644 --- a/.claude/skills/sce-task-execution/SKILL.md +++ b/.claude/skills/sce-task-execution/SKILL.md @@ -1,58 +1,247 @@ --- name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. compatibility: claude --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/.claude/skills/sce-task-execution/references/execution-contract.yaml b/.claude/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/.claude/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.claude/skills/sce-task-execution/references/implementation-gate.md b/.claude/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/.claude/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/.claude/skills/sce-validation/SKILL.md b/.claude/skills/sce-validation/SKILL.md index 22068f7f..ddb04f99 100644 --- a/.claude/skills/sce-validation/SKILL.md +++ b/.claude/skills/sce-validation/SKILL.md @@ -1,47 +1,190 @@ --- name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. compatibility: claude --- -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/.claude/skills/sce-validation/references/validation-report.md b/.claude/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/.claude/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/.claude/skills/sce-validation/references/validation-result.md b/.claude/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/.claude/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. diff --git a/.opencode/agent/Shared Context Code.md b/.opencode/agent/Shared Context Code.md index d5edcd48..c88395a2 100644 --- a/.opencode/agent/Shared Context Code.md +++ b/.opencode/agent/Shared Context Code.md @@ -25,60 +25,9 @@ permission: "*": ask "sce-plan-review": allow "sce-task-execution": allow - "sce-context-sync": allow + "sce-task-context-sync": allow "sce-validation": allow - "sce-atomic-commit": allow + "sce-plan-context-sync": allow --- -You are the Shared Context Code agent. - -Mission -- Implement exactly one approved task from an existing plan. -- Validate behavior and keep `context/` aligned with the resulting code. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- One task per session unless the human explicitly approves multi-task execution. -- Do not change plan structure or reorder tasks without approval. -- If scope expansion is required, stop and ask. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Confirm this session targets one approved plan task. -2) Proceed using the Procedure below. - -Procedure -- Load `sce-plan-review` and follow it exactly. -- Ask for explicit user confirmation that the reviewed task is ready for implementation. -- After confirmation, load `sce-task-execution` and follow it exactly. -- After implementation, load `sce-context-sync` and follow it. -- Wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light task-level checks/lints, run a build if it is light/fast, and run `sce-context-sync` again. -- If this is the final plan task, load `sce-validation` and follow it. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- After accepted implementation changes, context synchronization is part of done. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "I will run `sce-plan-review` first to confirm the next task and clarify acceptance criteria." -- "Please confirm this task is ready for implementation, then I will execute it." -- "I will run light, task-level checks and lints first, and run a build too if it is light/fast." -- "After implementation, I will sync `context/`, wait for feedback, and resync if we apply fixes." - -Definition of done -- Code changes satisfy task acceptance checks. -- Relevant tests/checks are executed with evidence. -- Plan task status is updated. -- Context and code have no unresolved drift for this task. +Route implementation work through `/next-task` and final plan validation through `/validate`. diff --git a/.opencode/agent/Shared Context Plan.md b/.opencode/agent/Shared Context Plan.md index 4499d961..23425736 100644 --- a/.opencode/agent/Shared Context Plan.md +++ b/.opencode/agent/Shared Context Plan.md @@ -23,65 +23,8 @@ permission: doom_loop: ask skill: "*": ask - "sce-bootstrap-context": allow + "sce-context-load": allow "sce-plan-authoring": allow --- -You are the Shared Context Plan agent. - -Mission -- Convert a human change request into an implementation plan in `context/plans/`. -- Keep planning deterministic and reviewable. - -Core principles -- The human owns architecture, risk, and final decisions. -- `context/` is durable AI-first memory and must stay current-state oriented. -- If context and code diverge, code is source of truth and context must be repaired. - -Hard boundaries -- Never modify application code. -- Never run shell commands. -- Only write planning and context artifacts. -- Planning does not imply execution approval. - -Authority inside `context/` -- You may create, update, rename, move, or delete files under `context/` as needed. -- You may create new top-level folders under `context/` when needed. -- Delete a file only if it exists and has no uncommitted changes. -- Use Mermaid when a diagram is needed. - -Startup -1) Check for `context/`. -2) If missing, ask once for approval to bootstrap. -3) If approved, load `sce-bootstrap-context` and follow it. -4) If not approved, stop. -5) Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` if present. -6) Before broad exploration, consult `context/context-map.md` for relevant context files. -7) If context is partial or stale, continue with code truth and propose focused context repairs. - -Procedure -- Load `sce-plan-authoring` and follow it exactly. -- Ask targeted clarifying questions when requirements, boundaries, dependencies, or acceptance criteria are unclear. -- Write or update `context/plans/{plan_name}.md`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat, if it's written to a subagent print it in the main agent. -- Prompt the user to start a new session to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. - -Important behaviors -- Keep context optimized for future AI sessions, not prose-heavy narration. -- Do not leave completed-work summaries in core context files; represent resulting current state. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not durable history. -- Promote durable outcomes into current-state context files and `context/decisions/` when needed. -- Long-term quality is measured by code quality and context accuracy. - -Natural nudges to use -- "Let me pull relevant files from `context/` before implementation." -- "Per SCE, chat-mode first, then implementation mode." -- "I will propose a plan with trade-offs first, then implement." -- "Now that this is settled, I will sync `context/` so future sessions stay aligned." - -Definition of done -- Plan has stable task IDs (`T01..T0N`). -- Each task has boundaries, done checks, and verification notes. -- Final task is always validation and cleanup. +Route plan creation and revision through `/change-to-plan`. diff --git a/.opencode/command/change-to-plan.md b/.opencode/command/change-to-plan.md index 1f2cd988..27cc07a2 100644 --- a/.opencode/command/change-to-plan.md +++ b/.opencode/command/change-to-plan.md @@ -1,20 +1,180 @@ --- -description: "Use `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +argument-hint: "" agent: "Shared Context Plan" -entry-skill: "sce-plan-authoring" +entry-skill: "sce-context-load" skills: + - "sce-context-load" - "sce-plan-authoring" --- -Load and follow the `sce-plan-authoring` skill. +SCE CHANGE TO PLAN `$ARGUMENTS` -Input change request: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; detailed clarification handling, plan-shape rules, and task-writing behavior stay owned by `sce-plan-authoring`. -- Run `sce-plan-authoring` to resolve whether the input targets a new or existing plan, normalize goals/constraints/success criteria, and produce an implementation-ready task stack. -- Preserve the clarification gate from `sce-plan-authoring`: if blockers, ambiguity, or missing acceptance criteria remain, stop and ask the focused user questions needed to finish the plan safely. -- Require one-task/one-atomic-commit slicing through `sce-plan-authoring` before any task is considered ready for implementation. -- When the plan is ready, write or update `context/plans/{plan_name}.md`, confirm the resolved `{plan_name}` and exact path, and return the ordered task list. -- Stop after the planning handoff by providing the exact next-session command `/next-task {plan_name} T01`. +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Invoke `sce-context-load` with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +`sce-plan-authoring` exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. +- Do not duplicate the internal instructions of invoked skills. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. diff --git a/.opencode/command/commit.md b/.opencode/command/commit.md deleted file mode 100644 index 384b7803..00000000 --- a/.opencode/command/commit.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -description: "Use `sce-atomic-commit` to propose atomic commit message(s) from staged changes" -agent: "Shared Context Code" -entry-skill: "sce-atomic-commit" -skills: - - "sce-atomic-commit" ---- - -Load and follow the `sce-atomic-commit` skill. - -Input: -`$ARGUMENTS` - -## Bypass path (`/commit oneshot` or `/commit skip`) - -If `$ARGUMENTS` starts with `oneshot` or `skip` (case-insensitive, first token only): - -- **Skip the staging confirmation prompt.** Do not ask the user to stage files or confirm staging. -- **Validate staged content exists.** Check that `git diff --cached` is non-empty. If no staged changes exist, stop with the error: "No staged changes. Stage changes before commit." Do not proceed. -- **Skip context-guidance gate classification.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Produce exactly one commit message.** Run `sce-atomic-commit` with these overrides: - - Produce exactly one commit message. Do not propose splits. Do not emit split guidance. - - When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. -- **Auto-execute `git commit`.** Use the produced commit message to run `git commit -m ""`. - - If `git commit` succeeds, report the commit hash and stop. - - If `git commit` fails, stop and report the failure. Do not invent fallback commits, retry, or amend. - -## Regular path (no arguments or non-bypass arguments) - -If `$ARGUMENTS` does not start with `oneshot` or `skip`: - -Behavior: -- If arguments are empty, treat input as unstated and infer commit intent from staged changes only. -- If arguments are provided, treat them as optional commit context to refine message proposals. -- Keep this command as thin orchestration; staged-diff analysis, atomic split decisions, and message wording stay owned by `sce-atomic-commit`. -- Before running `sce-atomic-commit`, explicitly stop and prompt the user: - - "Please run `git add ` for all changes you want included in this commit. - Atomic commits should only include intentionally staged changes. - Confirm once staging is complete." - -- After confirmation: - - Classify staged diff scope (`context/`-only vs mixed `context/` + non-`context/`) and apply the context-guidance gate from `sce-atomic-commit`. - - Run `sce-atomic-commit` to produce commit-message proposals and any needed split guidance. -- Do not create commits automatically; stop after returning proposed commit message(s) and split guidance when needed. diff --git a/.opencode/command/handover.md b/.opencode/command/handover.md deleted file mode 100644 index ce592cda..00000000 --- a/.opencode/command/handover.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -description: "Run `sce-handover-writer` to capture the current task for handoff" -agent: "Shared Context Code" -entry-skill: "sce-handover-writer" -skills: - - "sce-handover-writer" ---- - -Load and follow the `sce-handover-writer` skill. - -Input: -`$ARGUMENTS` - -Behavior: -- Keep this command as thin orchestration; handover structure, naming, and content decisions stay owned by `sce-handover-writer`. -- Run `sce-handover-writer` to gather current task state, decisions made and rationale, open questions or blockers, and the next recommended step. -- Let `sce-handover-writer` create the handover in `context/handovers/`, using task-aligned naming such as `context/handovers/{plan_name}-{task_id}-{timestamp}.md` when the inputs support it. -- If required details are missing, infer only from current repo state, label assumptions clearly, then stop after reporting the exact handover path. diff --git a/.opencode/command/next-task.md b/.opencode/command/next-task.md index 71a1f974..9c2ff4e3 100644 --- a/.opencode/command/next-task.md +++ b/.opencode/command/next-task.md @@ -1,30 +1,197 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-context-sync` for one approved SCE task" +description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +argument-hint: " [T0X] [approved]" agent: "Shared Context Code" entry-skill: "sce-plan-review" skills: - "sce-plan-review" - "sce-task-execution" - - "sce-context-sync" - - "sce-validation" + - "sce-task-context-sync" --- -Load and follow `sce-plan-review`, then `sce-task-execution`, then `sce-context-sync`. - -Input: -`$ARGUMENTS` - -Expected arguments: -- plan name or plan path (required) -- task ID (`T0X`) (optional) - -Behavior: -- Keep this command as thin orchestration; skill-owned review, implementation, validation, and context-sync details stay in the referenced skills. -- Run `sce-plan-review` first to resolve the plan target, choose the task, and report readiness. -- Apply the readiness confirmation gate from `sce-plan-review` before implementation: - - auto-pass only when both plan + task ID are provided and review reports no blockers, ambiguity, or missing acceptance criteria - - otherwise resolve the open points and ask the user to confirm the task is ready before continuing -- Run `sce-task-execution` next; keep the mandatory implementation stop, scoped edits, light checks/lints/build, and plan status updates skill-owned. -- After implementation, run `sce-context-sync` as the required done gate and wait for user feedback. -- If feedback requires in-scope fixes, apply the fixes, rerun light checks (and a light/fast build when applicable), then run `sce-context-sync` again. -- If this was the final plan task, run `sce-validation`; otherwise stop after prompting a new session with `/next-task {plan_name} T0X`. +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to `sce-plan-review`. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to `sce-task-execution`. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + +`sce-task-execution` exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not invoke context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not invoke context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of invoked skills. +- Do not ask for implementation confirmation outside "sce-task-execution". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve completed work and evidence when a later phase fails. diff --git a/.opencode/command/validate.md b/.opencode/command/validate.md index 3c128608..4b95c2ab 100644 --- a/.opencode/command/validate.md +++ b/.opencode/command/validate.md @@ -1,18 +1,149 @@ --- -description: "Run `sce-validation` to finish an SCE plan with validation and cleanup" +description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +argument-hint: "" agent: "Shared Context Code" entry-skill: "sce-validation" skills: - "sce-validation" + - "sce-plan-context-sync" --- -Load and follow the `sce-validation` skill. +SCE VALIDATE `$ARGUMENTS` -Input: -`$ARGUMENTS` +## Input -Behavior: -- Keep this command as thin orchestration; validation scope, command selection, cleanup, and evidence formatting stay owned by `sce-validation`. -- Run `sce-validation` to execute the full validation phase for the targeted plan or change, including required checks, evidence capture, and cleanup expected by the skill. -- Let `sce-validation` decide pass/fail status and record any residual risks or unmet criteria. -- Stop after reporting the validation outcome and the location of any written validation evidence. +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to `sce-validation` unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by `sce-validation` in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Invoke `sce-validation` with the plan name or path. + +`sce-validation` exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not invoke context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not invoke context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +`sce-plan-context-sync`. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result +from `sce-validation`. + +Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +`sce-plan-context-sync` owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +`sce-plan-context-sync` returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of invoked skills. +- Do not run final validation when implementation tasks remain; `sce-validation` + returns `blocked`, and this workflow stops. +- Invoke `sce-plan-context-sync` only when `sce-validation` returned + `Status: validated`. Do not invoke it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an invoked skill returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. diff --git a/.opencode/skills/sce-atomic-commit/SKILL.md b/.opencode/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 50c63fe8..00000000 --- a/.opencode/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: sce-atomic-commit -description: | - Write atomic, repo-style git commits from a change summary or diff. Use when preparing commit messages, splitting work into coherent commits, or reviewing whether a commit is too broad. -compatibility: opencode ---- - -## Goal - -Turn the current staged changes into atomic repository-style commit message proposals. - -For this workflow: -- analyze the staged diff to identify coherent change units -- propose one or more commit messages when staged changes mix unrelated goals -- keep each proposed message focused on a single coherent change -- stay proposal-only: do not create commits automatically -- in bypass mode (command-invoked), relax proposal-only, split guidance, context-guidance gate, and plan-citation ambiguity rules - -## Inputs - -Accept any of: -- staged diff (preferred) -- changed file list with notes -- PR/task summary -- before/after behavior notes - -## Output format - -Produce commit message proposals that follow: -- `scope: Subject` -- imperative verb (Fix/Add/Remove/Implement/Refactor/Simplify/Rename/Update/Ensure/Allow) -- no trailing period in subject -- body when context is needed (why/what changed/impact) -- issue references on their own lines (for example `Fixes #123`) - -When staged changes include `context/plans/*.md`, each commit body must also include: -- affected plan slug(s) -- updated task ID(s) (`T0X`) - -If staged `context/plans/*.md` changes do not expose the plan slug or updated task ID clearly enough to cite faithfully, stop and ask for clarification instead of inventing references. - -## Bypass mode - -When this skill is invoked by the `/commit` command in bypass mode (`/commit oneshot` or `/commit skip`), the command passes overrides that relax the standard rules below: - -- **Proposal-only → auto-commit allowed.** Do not block auto-commit; the command will execute `git commit` with the produced message. -- **Single message only.** Produce exactly one commit message. Do not propose splits. Do not emit split guidance. -- **Context-guidance gate skipped.** Do not classify staged diff scope as `context/`-only vs mixed. Do not apply context-file guidance gating. -- **Plan citations: best-effort only.** When staged changes include `context/plans/*.md`, make a best-effort inference to cite affected plan slug(s) and updated task ID(s). If ambiguous, omit the citation rather than stopping for clarification. - -When NOT in bypass mode, follow the standard rules in the Procedure and Context-file guidance gating sections below. - -## Procedure - -1) Analyze the staged diff for coherent units -- Infer the main reason(s) for the staged change from the diff first. -- Use optional notes only to refine wording, not to override the staged truth. -- Identify whether staged changes represent one coherent unit or multiple unrelated goals. - -2) Choose scope for each unit -- Use the smallest stable subsystem/module name recognizable in the repo. -- If unclear, use the primary directory/package of the change. - -3) Write subject for each unit -- Pattern: `: ` -- Keep concrete and targeted. - -4) Add body when needed -- Explain what was wrong/missing, why it matters, what changed conceptually, and impact. -- Add issue references on separate lines. - -5) In regular mode: apply the plan-update body rule when needed -- Check whether staged changes include `context/plans/*.md`. -- If yes, cite the affected plan slug(s) and updated task ID(s) in the body. -- If the staged plan diff is ambiguous, stop with actionable guidance asking the user to stage or clarify the plan/task reference explicitly. - -6) In regular mode: propose split guidance when appropriate -- If staged changes mix unrelated goals (for example: a feature change plus unrelated refactoring), propose separate commit messages for each coherent unit. -- Explain why the split is recommended and which files belong to each proposed commit. -- If staged changes represent one coherent unit, propose a single commit message. - -7) In regular mode: validate each proposed message -- Each message should describe its intended change faithfully. -- The subject should stay concise and technical. -- The body should add useful why/impact context instead of repeating the subject. -- Do not invent plan or task references. - -## Context-file guidance gating - -In regular mode: -- Check staged diff scope before proposing commit messaging guidance. -- If staged changes are context-only (`context/**`), context-file-focused guidance is allowed. -- If staged changes are mixed (`context/**` + non-`context/**`), avoid default context-file commit reminders and prioritize guidance that reflects the full staged scope. - -## Anti-patterns - -- vague subjects ("cleanup", "updates") -- body repeats subject without adding why -- playful tone in serious fixes/architecture changes -- mention `context/` sync activity in commit messages -- inventing plan slugs or task IDs for staged plan edits -- proposing splits for changes that are already coherent -- forcing unrelated changes into a single commit -- applying split guidance or plan-citation ambiguity stops when the command is in bypass mode diff --git a/.opencode/skills/sce-bootstrap-context/SKILL.md b/.opencode/skills/sce-bootstrap-context/SKILL.md deleted file mode 100644 index c0193c49..00000000 --- a/.opencode/skills/sce-bootstrap-context/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: sce-bootstrap-context -description: | - Creates the SCE (Shared Context Engineering) baseline `context/` directory structure — a set of markdown files and sub-folders used as shared project memory (overview, architecture, patterns, glossary, decisions, plans, handovers, and a temporary scratch space). Use when the `context/` folder is missing from the repository, when a user asks to initialise the project context, set up context, create baseline documentation structure, or when shared configuration files for project memory are absent. -compatibility: opencode ---- - -## When to use -- Use only when `context/` is missing. -- Ask for human approval before creating files. - -## Required baseline -Create these paths: -- `context/overview.md` -- `context/architecture.md` -- `context/patterns.md` -- `context/glossary.md` -- `context/context-map.md` -- `context/plans/` -- `context/handovers/` -- `context/decisions/` -- `context/tmp/` -- `context/tmp/.gitignore` - -Use the following commands to create the directory structure: -```bash -mkdir -p context/plans context/handovers context/decisions context/tmp -touch context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md -``` - -`context/tmp/.gitignore` content: -``` -* -!.gitignore -``` - -## Validation -After running the commands, verify all expected paths exist before proceeding: -```bash -ls context/overview.md context/architecture.md context/patterns.md context/glossary.md context/context-map.md context/plans context/handovers context/decisions context/tmp context/tmp/.gitignore -``` -If any path is missing, re-create it before moving on. - -## No-code bootstrap rule -- If the repository has no application code, keep `overview.md`, `architecture.md`, `patterns.md`, and `glossary.md` empty or placeholder-only. -- Do not invent implementation details. - -Example placeholder content for empty files in a no-code repo: -```markdown -# Overview - -> This section has not been populated yet. Add a high-level description of the project here. -``` - -## After bootstrapping -- Add baseline links in `context/context-map.md`. -- Tell the user that `context/` should be committed as shared memory. diff --git a/.opencode/skills/sce-context-load/SKILL.md b/.opencode/skills/sce-context-load/SKILL.md new file mode 100644 index 00000000..5e28b0ee --- /dev/null +++ b/.opencode/skills/sce-context-load/SKILL.md @@ -0,0 +1,129 @@ +--- +name: sce-context-load +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. +compatibility: opencode +--- + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Returning one structured context brief. + +Return a result matching: + +`references/context-brief.yaml` + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, return `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Return exactly one structured result: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching `references/context-brief.yaml` was returned. diff --git a/.opencode/skills/sce-context-load/references/context-brief.yaml b/.opencode/skills/sce-context-load/references/context-brief.yaml new file mode 100644 index 00000000..0def559b --- /dev/null +++ b/.opencode/skills/sce-context-load/references/context-brief.yaml @@ -0,0 +1,153 @@ +version: 1 +name: sce-context-load-result + +description: > + Output contract for sce-context-load. The skill returns exactly one YAML + document representing loaded or bootstrap_required. + +output_rules: + - Return exactly one result variant. + - The top-level status must be loaded or bootstrap_required. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - List every file that was read, and no file that was not. + - Report key_facts as durable statements the invoking workflow can act on, not + as summaries of what a file discusses. + - Do not include recommendations about how to plan or implement the focus. + - Do not report context edits. This skill never writes. + +variants: + + loaded: + meaning: > + The context root exists and the context relevant to the focus was read. + + required_fields: + - status + - context_root + - entry_points + - domain_context + - gaps + + optional_fields: + - drift + + field_rules: + - List entry_points with the read status of each, including entry points + that are absent. + - Include a domain_context entry only for a file that was actually read. + - Record a gap for any focus area with no durable context, and for any + absent entry point. + - Include drift only when recorded context contradicts the code. An + absence of drift means the checked claims held. + - An empty domain_context list is valid when the context root exists but + holds nothing relevant to the focus. Record the gap. + + shape: + status: loaded + + context_root: string + + entry_points: + - path: string + read: true | false + reason: string + + domain_context: + - path: string + relevance: string + key_facts: + - string + + gaps: + - area: string + detail: string + + drift: + - path: string + context_says: string + code_says: string + repair_needed: string + + example: + status: loaded + + context_root: context/ + + entry_points: + - path: context/context-map.md + read: true + - path: context/overview.md + read: true + - path: context/glossary.md + read: true + - path: context/architecture.md + read: false + reason: The focus does not change structure, boundaries, or data flow. + + domain_context: + - path: context/cli/styling-service.md + relevance: > + Owns the CLI banner rendering the focus changes. + + key_facts: + - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. + - The banner gradient is applied per column by services::style. + - owo-colors is the established styling dependency; no theme configuration surface exists. + + - path: context/cli/cli-command-surface.md + relevance: > + Owns which help surfaces render the banner. + + key_facts: + - The top-level banner is shared by sce, sce help, and sce --help. + - Command-local help does not render the banner. + + gaps: + - area: gradient regression coverage + detail: > + No durable context records how banner rendering is tested. + + drift: + - path: context/cli/styling-service.md + context_says: The banner gradient runs right to left in cyan and magenta. + code_says: > + services::style renders a left-to-right red gradient in the current + working tree. + repair_needed: > + Update the styling context to the implemented gradient direction and + endpoints. + + bootstrap_required: + meaning: > + The context root does not exist, so no durable context could be loaded. + Nothing was read and nothing was created. + + required_fields: + - status + - context_root + - reason + + field_rules: + - Report context_root as the path that was expected. + - Do not create the directory. Bootstrapping is owned by + `sce setup --bootstrap-context`, which the user runs. + + shape: + status: bootstrap_required + + context_root: string + + reason: string + + example: + status: bootstrap_required + + context_root: context/ + + reason: > + The repository has no context/ directory, so there is no durable memory + to load for this focus. diff --git a/.opencode/skills/sce-context-sync/SKILL.md b/.opencode/skills/sce-context-sync/SKILL.md deleted file mode 100644 index 16e27bf7..00000000 --- a/.opencode/skills/sce-context-sync/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: sce-context-sync -description: | - Use when user wants to update project documentation to reflect code changes, sync docs with code, refresh project context, or keep AI memory files accurate after completing an implementation task. Scans modified code, classifies the change significance, then updates or verifies Markdown context files under `context/` (overview, architecture, glossary, patterns, context-map, and domain files) so that durable AI memory stays aligned with current code truth. -compatibility: opencode ---- - -## Principle -- Context is durable AI memory and must reflect current-state truth. -- If context and code diverge, code is source of truth. - -## Mandatory sync pass (important-change gated) -For every completed implementation task, run a sync pass over these shared files: -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Classify whether the task is an important change before deciding to edit or verify root context files. - -## Root context significance gating -- **Root edits required** - task introduces cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology changes. -- **Verify-only** - task is localized to a single feature/domain with no root-level behavior, architecture, or terminology impact. Keep root files unchanged; capture details in domain files instead. -- Even when verify-only, still verify `context/overview.md`, `context/architecture.md`, and `context/glossary.md` against code truth before declaring done. - -## Step-by-step sync pass workflow - -1. **Classify the change** - Important change or verify-only (see [Classification Reference](#classification-reference) below). -2. **Read the affected code** - Review modified files to understand what actually changed. -3. **Verify root files** - Open `context/overview.md`, `context/architecture.md`, and `context/glossary.md`; confirm they match code truth. -4. **Edit or skip root files** - Important change: update relevant root files. Verify-only: leave root files unchanged. -5. **Create or update domain files** - Write or revise `context/{domain}/` files for feature-specific detail (see [Domain File Policy](#domain-file-creation-policy) below). -6. **Ensure feature existence** - Every newly implemented feature must have at least one durable canonical description discoverable from context (domain file or `context/overview.md` for cross-cutting features). -7. **Update `context/context-map.md`** - Add or refresh discoverability links to any new or changed context files. -8. **Add glossary entries** - For any new domain language introduced by the task. -9. **Final check** - Confirm all updated files are <= 250 lines, diagrams are present where needed, and links use relative paths. - -### Before/after example -A task adds a new `PaymentGateway` abstraction used only in the payments domain (verify-only - domain-local). - -**`context/glossary.md`** - unchanged (no new root-level terminology). - -**New file: `context/payments/payment-gateway.md`:** -```markdown -# PaymentGateway - -Abstraction over external payment processors (Stripe, Adyen). -Defined in `src/payments/gateway/`. - -## Contract -- `charge(amount, token): Result` -- `refund(chargeId): Result` - -See also: [overview.md](../overview.md), [context-map.md](../context-map.md) -``` - -**`context/context-map.md`** - updated with a link to `context/payments/payment-gateway.md`. - ---- - -## Classification Reference - -| Important change (root edits required) | Verify-only (root files unchanged) | -|---|---| -| New auth strategy replacing existing one - architecture + terminology | New field on an existing API response - localized, no architecture impact | -| Background job queue used across multiple domains - cross-cutting | Bug fix in a single service's retry logic - no new root-level behavior | -| Renaming a core concept (e.g., `Order` -> `Purchase`) - canonical terminology | New UI component added to an existing feature - no cross-cutting impact | - ---- - -## Domain File Creation Policy - -- Use `context/{domain}/` for detailed feature behavior. -- If a feature does not cleanly fit an existing domain file, create a new one - do not defer documentation. -- If the feature appears to be part of a larger future domain, document the implemented slice now in a focused file and link it to related context. -- Prefer a small, precise domain file over overloading `overview.md` with detail. -- If updates for the current feature/domain outgrow shared files, migrate detail into `context/{domain}/` files, keep concise pointers in shared files, and add discoverability links in `context/context-map.md`. - ---- - -## Final-task requirement -- In the final plan task (validation/cleanup), confirm feature existence documentation is present and linked. -- If a feature was implemented but not represented in context, add the missing entry before declaring the task done. - -## Quality constraints -- One topic per file. -- Prefer concise current-state documentation over narrative changelogs. -- Link related context files with relative paths. -- Include concrete code examples when needed to clarify non-trivial behavior. -- Every context file must stay at or below 250 lines; if it would exceed 250, split into focused files and link them. -- Add a Mermaid diagram when structure, boundaries, or flows are complex. -- Ensure major code areas have matching context coverage. diff --git a/.opencode/skills/sce-handover-writer/SKILL.md b/.opencode/skills/sce-handover-writer/SKILL.md deleted file mode 100644 index 43bb1238..00000000 --- a/.opencode/skills/sce-handover-writer/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: sce-handover-writer -description: | - Creates a structured handover document summarizing task context, decisions made, open questions, and recommended next steps — saved to `context/handovers/`. Use when a user wants to hand off, transition, or pass a task to someone else, create handover notes, write a task transition document, or capture current progress for a future session. Trigger phrases include "create a handover", "hand this off", "write handover notes", "pass this task on", or "document where I'm up to". -compatibility: opencode ---- - -## What I do -- Create a new handover file in `context/handovers/`. -- Capture: - - current task state - - decisions made and rationale - - open questions or blockers - - next recommended step - -## How to run this - -1. **Gather context** - review the current task, recent changes, and repo state. -2. **Create the file** - use task-aligned naming: `context/handovers/{plan_name}-{task_id}.md`. -3. **Fill each section** - follow the template below, labelling any inferred details as assumptions. -4. **Verify completeness** - confirm all four sections are populated before finishing. - -If key details are missing, infer from repo state and clearly label assumptions. - -## Handover document template - -```markdown -# Handover: {plan_name} - {task_id} - -## Current Task State -- What was being worked on and how far along it is. -- e.g. "Implementing OAuth login flow; token generation complete, redirect handling in progress." - -## Decisions Made -- Key choices and their rationale. -- e.g. "Chose JWT over session cookies for statelessness. Rejected library X due to licence constraints." - -## Open Questions / Blockers -- Unresolved issues or outstanding dependencies. -- e.g. "Awaiting confirmation on token expiry policy from product team." - -## Next Recommended Step -- The single most important action for whoever picks this up. -- e.g. "Complete the redirect handler in `src/auth/callback.ts`, then run the auth integration tests." -``` - -## Expected output -- A complete handover document in `context/handovers/` using task-aligned naming when possible. diff --git a/.opencode/skills/sce-plan-authoring/SKILL.md b/.opencode/skills/sce-plan-authoring/SKILL.md index 3632b0b8..fdc754a9 100644 --- a/.opencode/skills/sce-plan-authoring/SKILL.md +++ b/.opencode/skills/sce-plan-authoring/SKILL.md @@ -1,89 +1,290 @@ --- name: sce-plan-authoring -description: | - Creates or updates structured SCE (Shared Context Engine) implementation plans saved to `context/plans/{plan_name}.md`. Breaks a change request into scoped, atomic tasks with clear goals, boundaries, acceptance criteria, and verification steps. Use when a user wants to plan a new feature, refactor, or integration; needs a project plan, task breakdown, implementation roadmap, or work plan; or describes a change with success criteria that requires structured planning before execution. +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + YAML result: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. compatibility: opencode --- -## Goal -Turn a human change request into `context/plans/{plan_name}.md`. - -## Intake trigger -- If a request includes both a change description and success criteria, planning is mandatory before implementation. -- Planning does not imply execution approval. - -## Clarification gate (blocking) -- Before writing or updating any plan, run an ambiguity check. -- If any critical detail is unclear, ask 1-3 targeted questions and stop. -- Do not write or update `context/plans/{plan_name}.md` until the user answers. -- Critical details that must be resolved before planning include: - - scope boundaries and out-of-scope items - - success criteria and acceptance signals - - constraints and non-goals - - dependency choices (new libs/services, versions, and integration approach) - - domain ambiguity (unclear business rules, terminology, or ownership) - - architecture concerns (patterns, interfaces, data flow, migration strategy, and risk tradeoffs) - - task ordering assumptions and prerequisite sequencing -- Do not silently invent missing requirements. -- If the user explicitly allows assumptions, record them in an `Assumptions` section. -- Incorporate user answers into the plan before handoff. - -Example clarification questions (use this style - specific, blocking, targeted): -> 1. Should the new endpoint authenticate via the existing JWT middleware, or is a separate auth flow in scope? -> 2. Is database migration rollback a hard requirement, or is forward-only acceptable for this change? -> 3. Which service owns the `UserProfile` type - should this task modify that definition or only consume it? - -## Plan format -1) Change summary -2) Success criteria -3) Constraints and non-goals -4) Task stack (`T01..T0N`) -5) Open questions (if any) - -## Task format (required) -For each task include: -- Task ID -- Goal -- Boundaries (in/out of scope) -- Done when -- Verification notes (commands or checks) - -## Atomic task slicing contract (required) -- Author each executable task as one atomic commit unit by default. -- Every task must be scoped so one contributor can complete it and land it as one coherent commit without bundling unrelated changes. -- If a candidate task would require multiple independent commits (for example: refactor + behavior change + docs), split it into separate sequential tasks before finalizing the plan. -- Keep broad wrappers (`polish`, `finalize`, `misc updates`) out of executable tasks; convert them into specific outcomes with concrete acceptance checks. - -Example compliant skeleton: -- [ ] T0X: `[single intent title]` (status:todo) - - Task ID: T0X - - Goal: `[one outcome]` - - Boundaries (in/out of scope): `[tight scope]` - - Done when: `[clear acceptance for one coherent change]` - - Verification notes (commands or checks): `[targeted checks for this change]` - -Example filled-in task entry: -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In - route handler, token validation logic, response schema. Out - refresh token rotation policy (covered in T03), client-side storage changes. - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired/invalid token; unit tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. - -Use checkbox lines for machine-friendly progress tracking: -- `- [ ] T01: ... (status:todo)` - -## Complete plan example - -See `context/plans/PLAN_EXAMPLE.md` for a full annotated reference plan (JWT auth walkthrough covering all required sections and four task entries). - -## Required final task -- Final task is always validation and cleanup. -- It must include full checks and context sync verification. - -## Output contract -- Save plan under `context/plans/`. -- Confirm plan creation with `plan_name` and exact file path. -- Present the full ordered task list in chat. -- Prompt the user to start a new session with Shared Context Code agent to implement `T01`. -- Provide one canonical next command: `/next-task {plan_name} T01`. +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Returning one structured authoring result. + +Use the document format defined in: + +`references/plan-template.md` + +Return a result matching: + +`references/authoring-contract.yaml` + +The invoking workflow renders that result as the summary defined in: + +`references/plan-summary.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from `sce-context-load`. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not return `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Return `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in `references/plan-template.md`. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, return `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Return exactly one structured result: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Return `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Return `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml b/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml new file mode 100644 index 00000000..afd4ce0d --- /dev/null +++ b/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml @@ -0,0 +1,256 @@ +version: 1 +name: sce-plan-authoring-result + +description: > + Output contract for sce-plan-authoring. The skill returns exactly one YAML + document representing plan_ready, needs_clarification, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be plan_ready, needs_clarification, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.name as the plan file's base name without its extension, and + plan.path as the exact written path, so emitted commands are runnable. + - Report plan.completed_tasks and plan.total_tasks as they stand in the + written plan. + - Write a plan file only for plan_ready. needs_clarification and blocked mean + nothing was written or modified. + - Do not ask the user questions directly. Clarification questions belong in + the needs_clarification variant. + - Do not report a trailing validation, cleanup, or context-verification task. + The written plan states how it is validated in its acceptance criteria, and + /validate runs that phase after the last task. + - plan_ready always leaves at least one incomplete task and always names + next_task. A request that would add no incomplete task is not plan_ready; + return blocked with category no_actionable_work. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + plan_ready: + meaning: > + One plan was written or updated and its task stack is ready to enter the + review-and-implementation workflow. + + required_fields: + - status + - plan + - summary + - tasks + - next_task + - assumptions + + optional_fields: + - open_questions + + field_rules: + - Report summary as one or two sentences condensing the plan's Change + summary section: what changes, where, and why. It is what the user reads + to decide whether the plan understood the request at all. + - Write summary as the resulting behavior, not as a list of the tasks. The + task list is already carried by tasks. + - Set plan.action to created for a new plan file, or updated for an + existing one. + - List tasks in plan order, including tasks already complete on an + updated plan. + - Report next_task as the first unchecked task in plan order. It is always + present, because plan_ready requires at least one incomplete task. + - Include open_questions only for non-blocking questions recorded in the + plan. A blocking question requires needs_clarification instead. + - Record unresolved doubt about the change's value here: whether it is + worth building, whether it duplicates existing behavior, whether a + smaller version would do. Such a doubt does not block authoring, and + the invoking workflow surfaces it before handing off. + - Omit open_questions when there is nothing genuinely unresolved. Do not + manufacture a question to appear rigorous. An empty section is the + expected outcome for a well-specified change. + + shape: + status: plan_ready + + plan: + path: string + name: string + action: created | updated + completed_tasks: integer + total_tasks: integer + + summary: string + + tasks: + - id: string + title: string + status: todo | done + + next_task: + id: string + title: string + + assumptions: + - string + + open_questions: + - string + + example: + status: plan_ready + + plan: + path: context/plans/authentication.md + name: authentication + action: created + completed_tasks: 0 + total_tasks: 3 + + summary: > + Adds password authentication to the HTTP API: a login endpoint that + verifies credentials and issues a token, and refresh-token rotation + behind it. Registration and password reset are untouched. + + tasks: + - id: T01 + title: Add credential verifier + status: todo + - id: T02 + title: Add login endpoint + status: todo + - id: T03 + title: Add refresh-token rotation + status: todo + + next_task: + id: T01 + title: Add credential verifier + + assumptions: + - Use the error-response convention established by existing handlers. + + open_questions: + - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? + + needs_clarification: + meaning: > + A critical detail is unresolved, so no plan was written. The invoking + workflow must present the questions and stop. + + required_fields: + - status + - questions + + optional_fields: + - plan_target + + field_rules: + - Include one to three questions. Each must be specific, answerable, and + blocking. + - Include plan_target when the request clearly resolved to one new or + existing plan before the gate stopped authoring. + - Do not include a plan path unless that plan already exists on disk. + + shape: + status: needs_clarification + + plan_target: + name: string + action: created | updated + path: string + + questions: + - id: string + category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing + question: string + why_blocking: string + + example: + status: needs_clarification + + plan_target: + name: authentication + action: created + + questions: + - id: Q01 + category: architecture + + question: > + Should the new endpoint authenticate via the existing JWT + middleware, or is a separate auth flow in scope? + + why_blocking: > + The answer changes the task stack, the affected modules, and the + security boundary. + + - id: Q02 + category: scope + + question: > + Is database migration rollback a hard requirement, or is + forward-only acceptable for this change? + + why_blocking: > + Rollback support is a separate atomic task with its own + verification. + + blocked: + meaning: > + The plan target could not be resolved, or the request cannot be planned + safely. No plan was written. + + required_fields: + - status + - issues + + optional_fields: + - candidates + + field_rules: + - Include candidates only when the request matched more than one existing + plan and none could be selected safely. + - Use needs_clarification, not blocked, when the request is plannable once + the user answers a question. + - Use no_actionable_work when the request resolved to a plan but produced + no incomplete task, for example because the requested change is already + implemented or already covered by completed tasks. + + shape: + status: blocked + + candidates: + - string + + issues: + - id: string + category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other + problem: string + impact: string + decision_required: string + + example: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguous_plan_target + + problem: > + The change request matches more than one existing plan and none can + be selected safely. + + impact: > + Updating the wrong plan would reorder tasks unrelated to the + request. + + decision_required: > + Name the exact plan path to update, or state that a new plan should + be created. diff --git a/.opencode/skills/sce-plan-authoring/references/plan-summary.md b/.opencode/skills/sce-plan-authoring/references/plan-summary.md new file mode 100644 index 00000000..0261808d --- /dev/null +++ b/.opencode/skills/sce-plan-authoring/references/plan-summary.md @@ -0,0 +1,94 @@ +# SCE Plan Summary + +The user-facing summary shown after a plan is written. The invoking workflow +renders it from the `plan_ready` result, immediately before the continuation +block. + +This is chat output, not a file. Nothing here is written to the plan. + +## Layout + +``` +# Plan: {plan.name} + +Path: {plan.path} + +## Summary: +{plan summary} + +## Tasks: +1. {task.id} — {task.title} +2. {task.id} — {task.title} + +## Assumptions: +- {assumption} + +## Open questions: +- {open question} +``` + +## Field mapping + +Every value comes from the `plan_ready` result. Render nothing the result does +not carry. + +- `Plan:` — `plan.name`. Append ` (updated)` when `plan.action` is `updated`. + Render nothing extra when it is `created`. +- `Path:` — `plan.path`, exactly as returned, so it stays runnable. +- `Summary:` — `summary`, as prose. This is the only place the reader learns + what the plan actually does, so never omit it and never replace it with a + restatement of the task titles. +- `Tasks:` — one numbered line per entry in `tasks`, in plan order. Append + ` (done)` to any task whose `status` is `done`. +- `Assumptions:` — one line per entry in `assumptions`. +- `Open questions:` — one line per entry in `open_questions`. + +## Empty sections + +Never drop a section heading. An absent section reads as an oversight; an +explicit `None.` confirms nothing is pending. + +When `assumptions` is empty: + +``` +## Assumptions: +- None. +``` + +When `open_questions` is absent: + +``` +## Open questions: +- None. +``` + +## Rules + +- Render the sections in the order above. +- Keep task titles as authored. Do not reword, expand, or re-scope them. +- Do not restate goals, boundaries, done checks, or verification notes. The plan + file owns task detail; this summary orients the reader. +- Do not print the raw result, and do not wrap the summary in a code fence. +- Do not add commentary, recommendations, or a next step. The continuation block + that follows owns the handoff. + +## Example + +``` +# Plan: red-sce-banner + +Path: context/plans/red-sce-banner.md + +## Summary: +Renders the ASCII-art SCE banner at the top of `sce` help in red instead of the current gradient. Colour-disabled output is unchanged, and no other help surface is affected. + +## Tasks: +1. T01 — Render the SCE banner in red + +## Assumptions: +- "SCE letters" refers to the ASCII-art banner in top-level help. +- Red is uniform terminal red when colors are enabled; plain ASCII remains unchanged otherwise. + +## Open questions: +- None. +``` diff --git a/.opencode/skills/sce-plan-authoring/references/plan-template.md b/.opencode/skills/sce-plan-authoring/references/plan-template.md new file mode 100644 index 00000000..a13407fc --- /dev/null +++ b/.opencode/skills/sce-plan-authoring/references/plan-template.md @@ -0,0 +1,170 @@ +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. diff --git a/.opencode/skills/sce-plan-context-sync/SKILL.md b/.opencode/skills/sce-plan-context-sync/SKILL.md new file mode 100644 index 00000000..a59c57f8 --- /dev/null +++ b/.opencode/skills/sce-plan-context-sync/SKILL.md @@ -0,0 +1,309 @@ +--- +name: sce-plan-context-sync +description: > + Internal SCE workflow skill that accepts a successful Status: validated + Markdown result from sce-validation, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Invoke only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. +compatibility: opencode +--- + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete Markdown result returned by `sce-validation`. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be invoked for `failed` or `blocked` validation results. +Those are not success states. Same rule as `sce-task-context-sync`: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated Markdown result: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return YAML. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.opencode/skills/sce-plan-context-sync/references/sync-report.md b/.opencode/skills/sce-plan-context-sync/references/sync-report.md new file mode 100644 index 00000000..21ff3e3a --- /dev/null +++ b/.opencode/skills/sce-plan-context-sync/references/sync-report.md @@ -0,0 +1,142 @@ +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not invoked for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.opencode/skills/sce-plan-review/SKILL.md b/.opencode/skills/sce-plan-review/SKILL.md index da87e50e..cb98f485 100644 --- a/.opencode/skills/sce-plan-review/SKILL.md +++ b/.opencode/skills/sce-plan-review/SKILL.md @@ -1,91 +1,149 @@ --- name: sce-plan-review -description: | - Reviews an existing SCE plan file (a Markdown checklist in `context/plans/`) to identify the next unchecked task, surface blockers or ambiguous acceptance criteria, and produce an explicit readiness verdict before implementation begins. Use when the user wants to continue a plan, resume work, pick the next step, or check what remains in an active plan — e.g. "continue the plan", "what's next?", "resume work on the plan", "review my plan and prepare the next task". +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. compatibility: opencode --- -## What I do -- Continue execution from an existing plan in `context/plans/`. -- Read the selected plan and identify the next task from the first unchecked checkbox. -- Ask focused questions for anything not clear enough to execute safely. - -## How to run this -- Use this skill when the user asks to continue a plan or pick the next task. -- If `context/` is missing, ask once: "`context/` is missing. Bootstrap SCE baseline now?" - - If yes, create baseline with `sce-bootstrap-context` and continue. - - If no, stop and explain SCE workflows require `context/`. -- Read `context/context-map.md`, `context/overview.md`, and `context/glossary.md` before broad exploration. -- Resolve plan target: - - If plan path argument exists, use it. - - If multiple plans exist and no explicit path is provided, ask user to choose. -- Collect: - - completed tasks - - next task - - blockers, ambiguity, and missing acceptance criteria -- Prompt user to resolve unclear points before implementation. -- Confirm scope explicitly for this session: one task by default unless user requests multi-task execution. - -## Plan file format -SCE plans are Markdown files stored in `context/plans/`. Tasks are tracked as checkboxes: - -```markdown -# Plan: Add user authentication - -## Tasks -- [x] Scaffold auth module -- [x] Add password hashing utility -- [ ] Implement login endpoint <- next task (first unchecked) -- [ ] Write integration tests -- [ ] Update context/current-state.md -``` - -The first unchecked `- [ ]` item is the next task to review and prepare. - -## Rules -- Do not auto-mark tasks complete during review. -- Keep continuation state in the plan markdown itself. -- Treat `context/plans/` as active execution artifacts; completed plans are disposable and not a durable context source. -- If durable history is needed, record it in current-state context files and/or `context/decisions/` instead of completed plan files. -- Keep implementation blocked until decision alignment on unclear points. -- If plan context is stale or partial, continue with code truth and flag context updates. - -## Expected output - -Produce a structured readiness summary after review: - -``` -## Plan Review - [plan filename] - -**Completed tasks:** 2 of 5 -**Next task:** Implement login endpoint - -**Acceptance criteria:** -- POST /auth/login returns JWT on success -- Returns 401 on invalid credentials - -**Issues found:** -- Blocker: JWT secret source not specified (env var? config file?) -- Ambiguity: Should failed attempts be rate-limited in this task or a later one? - -**ready_for_implementation: no** - -**Required decisions before proceeding:** -1. Confirm JWT secret source -2. Confirm rate-limiting scope -``` - -When all issues are resolved: - -``` -**ready_for_implementation: yes** -Proceeding with: Implement login endpoint -``` - -- Explicit readiness verdict: `ready_for_implementation: yes|no`. -- If not ready, explicit issue categories: blockers, ambiguity, missing acceptance criteria. -- Explicit user-aligned decisions needed to proceed to implementation. -- Explicit user confirmation request that the task is ready for implementation when unresolved issues remain. - -## Related skills -- `sce-bootstrap-context` - creates the `context/` baseline required by this skill +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Returning one structured readiness result. + +Return a result matching: + +`references/readiness-contract.yaml` + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Return `plan_complete` when no incomplete tasks remain. + +Return `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Return `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Return exactly one structured result: + +- `ready` +- `blocked` +- `plan_complete` + +Return only the structured result. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Invoke task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching `references/readiness-contract.yaml` was + returned. diff --git a/.opencode/skills/sce-plan-review/references/readiness-contract.yaml b/.opencode/skills/sce-plan-review/references/readiness-contract.yaml new file mode 100644 index 00000000..4d65e94e --- /dev/null +++ b/.opencode/skills/sce-plan-review/references/readiness-contract.yaml @@ -0,0 +1,246 @@ +version: 1 +name: sce-plan-review-result + +description: > + Output contract for sce-plan-review. The skill returns exactly one YAML + document representing ready, blocked, or plan_complete. + +output_rules: + - Return exactly one result variant. + - The top-level status must be ready, blocked, or plan_complete. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Report plan.name as the plan file's base name without its extension. It is + required by the ready variant, which renders the implementation gate. + - Do not request implementation confirmation. + - Do not include implementation results. + - Do not include context synchronization results. + - Do not include final validation results. + +variants: + + ready: + meaning: > + One task has been selected and contains enough information to enter + the implementation-confirmation phase. + + required_fields: + - status + - plan + - task + - relevant_files + - relevant_context + - assumptions + + shape: + status: ready + + plan: + path: string + name: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + goal: string + + in_scope: + - string + + out_of_scope: + - string + + done_checks: + - string + + dependencies: + - id: string + status: complete + + verification: + - string + + relevant_files: + - string + + relevant_context: + - string + + assumptions: + - string + + example: + status: ready + + plan: + path: context/plans/authentication.md + name: authentication + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + goal: > + Add an endpoint that authenticates a user and returns the existing + token response type. + + in_scope: + - Add the login request handler. + - Reuse the existing credential verifier. + - Add tests for valid and invalid credentials. + + out_of_scope: + - Refresh-token support. + - Password reset. + - Changes to user registration. + + done_checks: + - Valid credentials return the existing token response type. + - Invalid credentials return the standard authentication error. + - Targeted authentication tests pass. + + dependencies: + - id: T02 + status: complete + + verification: + - npm test -- tests/auth/login.test.ts + + relevant_files: + - src/auth/credentials.ts + - src/auth/token.ts + - tests/auth/login.test.ts + + relevant_context: + - context/authentication/overview.md + + assumptions: + - Use the error-response convention established by existing authentication handlers. + + blocked: + meaning: > + A plan could not be resolved, or a task cannot safely enter implementation + because a material decision, dependency, scope boundary, or completion + condition is unresolved. + + required_fields: + - status + - issues + + optional_fields: + - plan + - task + - candidates + - executable_tasks_remaining + + field_rules: + - Include plan whenever exactly one plan was resolved. + - Include candidates only when plan resolution was ambiguous or failed. + - Include task only when one task was selected before blocking. + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + candidates: + - string + + task: + id: string + title: string + + issues: + - id: string + category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope + problem: string + impact: string + decision_required: string + + executable_tasks_remaining: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + issues: + - id: B01 + category: missing_decision + + problem: > + The plan does not specify whether authentication uses sessions + or tokens. + + impact: > + The decision changes persistence behavior, endpoint responses, + and the security model. + + decision_required: > + Choose session-based or token-based authentication. + + executable_tasks_remaining: true + + example_plan_unresolved: + status: blocked + + candidates: + - context/plans/authentication.md + - context/plans/authentication-refresh.md + + issues: + - id: B01 + category: ambiguity + + problem: > + The supplied plan name matches more than one plan and none can be + selected safely. + + impact: > + Reviewing the wrong plan would select an unrelated task. + + decision_required: > + Name the exact plan path to review. + + plan_complete: + meaning: > + The selected plan contains no incomplete implementation tasks. + + required_fields: + - status + - plan + + shape: + status: plan_complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + example: + status: plan_complete + + plan: + path: context/plans/authentication.md + completed_tasks: 5 + total_tasks: 5 diff --git a/.opencode/skills/sce-task-context-sync/SKILL.md b/.opencode/skills/sce-task-context-sync/SKILL.md new file mode 100644 index 00000000..3b3b5d80 --- /dev/null +++ b/.opencode/skills/sce-task-context-sync/SKILL.md @@ -0,0 +1,311 @@ +--- +name: sce-task-context-sync +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from sce-task-execution, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Invoke only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. +compatibility: opencode +--- + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Returning one Markdown synchronization report. + +Use the report format in: + +`references/sync-report.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by `sce-task-execution`. + +The execution result must have: + +```yaml +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be invoked for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Return exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style YAML result. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.opencode/skills/sce-task-context-sync/references/sync-report.md b/.opencode/skills/sce-task-context-sync/references/sync-report.md new file mode 100644 index 00000000..7d5acb94 --- /dev/null +++ b/.opencode/skills/sce-task-context-sync/references/sync-report.md @@ -0,0 +1,133 @@ +# Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input execution status is always `complete` and does not need to be repeated +as a separate workflow state. + +## Synced variant + +# Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required synchronization.} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against implementation and execution evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Context impact + +**Classification:** none + +{Explain why the completed implementation did not introduce durable, +non-obvious repository knowledge requiring an update.} + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with implementation and execution evidence.} + +--- + +## Blocked variant + +# Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` +**Task:** `{task id} — {task title}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which context synchronization should run +again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. A root pass + with a file missing from the list reads as a file that was never checked. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Omit **Feature existence** only when the task implemented no feature. +- Describe durable truth, not implementation-session chronology. +- Keep evidence concise and factual. +- Do not claim final validation passed. +- Do not determine whether the plan is complete. +- Do not recommend a next implementation task. diff --git a/.opencode/skills/sce-task-execution/SKILL.md b/.opencode/skills/sce-task-execution/SKILL.md index 2e13a754..267f608c 100644 --- a/.opencode/skills/sce-task-execution/SKILL.md +++ b/.opencode/skills/sce-task-execution/SKILL.md @@ -1,58 +1,247 @@ --- name: sce-task-execution -description: | - Executes a single planned implementation task with a mandatory approval gate, scope guardrails, and evidence capture. Use when a user wants to implement, run, or execute a specific task from a project plan — such as coding a feature, applying a patch, or making targeted file changes — while enforcing explicit scope boundaries, a pre-implementation confirmation prompt, test/lint verification, and status tracking in context/plans/{plan_id}.md. +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one YAML result: declined, + blocked, incomplete, or complete. Accepts a ready result from + sce-plan-review. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. compatibility: opencode --- -## Scope rule -- Execute exactly one task per session by default. -- If multi-task execution is requested, confirm explicit human approval. - -## Mandatory implementation stop -- Before writing or modifying any code, pause and prompt the user. -- The prompt must explain: - - task goal - - boundaries (in/out of scope) - - done checks - - expected files/components to change - - key approach, trade-offs, and risks -- Then ask explicitly whether to continue. -- Do not edit files, generate code, or apply patches until the user confirms. - -**Example mandatory stop prompt:** -``` -Task goal: Add input validation to the user registration endpoint. -In scope: src/routes/register.ts, src/validators/user.ts -Out of scope: Auth logic, database schema, frontend forms -Done checks: All existing tests pass; new validation tests cover empty/invalid email and short passwords -Expected changes: ~2 files modified, no new dependencies -Approach: Use the existing `validateSchema` helper; add a Zod schema for registration payload -Trade-offs: Zod adds minor overhead; keeps validation consistent with other routes -Risks: Existing callers that omit optional fields may start failing validation - -Continue with implementation now? (yes/no) -``` - -## Required sequence -1) Restate task goal, boundaries, done checks, and expected file touch scope. -2) Propose approach, trade-offs, and risks. -3) Stop and ask: "Continue with implementation now?" (yes/no). -4) Implement minimal in-scope changes. -5) Run light task-level tests/checks and lints first, and run a build when the build is light/fast (targeted over full-suite unless requested), then capture evidence. -6) Record whether the implementation is an important change for context sync (root-edit required) or verify-only (no root edits expected). -7) Keep session-only scraps in `context/tmp/`. -8) Update task status in `context/plans/{plan_id}.md`. - -**Example task status update (`context/plans/{plan_id}.md`):** -```markdown -## Task: Add input validation to registration endpoint -- **Status:** done -- **Completed:** 2025-06-10 -- **Files changed:** src/routes/register.ts, src/validators/user.ts -- **Evidence:** 14/14 tests passed, lint clean, build succeeded (12s) -- **Notes:** Zod schema added; no breaking changes to existing callers -``` - -## Scope expansion rule -- If out-of-scope edits are needed, stop and ask for approval. +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Returning one terminal YAML result. + +Use the gate defined in: + +`references/implementation-gate.md` + +Return a final result matching: + +`references/execution-contract.yaml` + +## Input + +The invoking workflow provides: + +- The complete `ready` result from `sce-plan-review`. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, return `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/implementation-gate.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return YAML, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and return `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise return `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, return `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Return `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Return `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Return `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Return `declined` when the user rejected implementation. + +Return `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by `references/execution-contract.yaml`. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return YAML + +After the skill reaches a terminal state, return exactly one YAML document +matching `references/execution-contract.yaml`. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal YAML result matching `references/execution-contract.yaml` + was returned. diff --git a/.opencode/skills/sce-task-execution/references/execution-contract.yaml b/.opencode/skills/sce-task-execution/references/execution-contract.yaml new file mode 100644 index 00000000..cf45b58a --- /dev/null +++ b/.opencode/skills/sce-task-execution/references/execution-contract.yaml @@ -0,0 +1,306 @@ +version: 1 +name: sce-task-execution-result + +description: > + Output contract for sce-task-execution. The skill returns exactly one YAML + document representing declined, blocked, incomplete, or complete. + +output_rules: + - Return exactly one result variant. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields relevant to the selected status. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. An empty list is a valid + value for a required list field. + - Report plan.completed_tasks and plan.total_tasks as they stand when the + result is returned. + - Do not serialize the implementation gate. The gate is user-facing prose + defined by implementation-gate.md, and no result is returned until the + user has answered it. + - Do not select or describe the next task. + - Do not include context synchronization results. + - Do not include final plan validation results. + +variants: + + declined: + meaning: > + The user declined implementation and no implementation changes were made. + + required_fields: + - status + - plan + - task + + shape: + status: declined + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + example: + status: declined + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocked: + meaning: > + The task cannot continue without a material decision or authorization. + + required_fields: + - status + - plan + - task + - blocker + - work_preserved + + optional_fields: + - changes + - verification + + shape: + status: blocked + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + blocker: + category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other + problem: string + impact: string + decision_required: string + + changes: + files_changed: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + work_preserved: boolean + + example: + status: blocked + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + blocker: + category: dependency + problem: The implementation requires adding a new token-signing package. + impact: The task does not authorize a new production dependency. + decision_required: Approve the dependency or choose an existing repository implementation. + + work_preserved: true + + incomplete: + meaning: > + In-scope implementation work was completed, but one or more task done + checks remain unsatisfied. + + required_fields: + - status + - plan + - task + - changes + - verification + - remaining_work + + optional_fields: + - satisfied_done_checks + - unsatisfied_done_checks + - reason + + shape: + status: incomplete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed | failed | not_run + summary: string + + satisfied_done_checks: + - string + + unsatisfied_done_checks: + - string + + remaining_work: + - string + + reason: string + + example: + status: incomplete + + plan: + path: context/plans/authentication.md + completed_tasks: 2 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login handler. + - Added valid-credential coverage. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: failed + summary: Invalid-credential response does not match the expected error format. + + satisfied_done_checks: + - Valid credentials return a token. + + unsatisfied_done_checks: + - Invalid credentials return the standard authentication error. + + remaining_work: + - Correct invalid-credential error mapping. + - Rerun targeted authentication tests. + + reason: Completing the correction requires clarification of the expected error mapping. + + complete: + meaning: > + The selected task was implemented, verified, and marked complete in + the plan with evidence. + + required_fields: + - status + - plan + - task + - changes + - verification + - done_checks + - plan_update + - context_impact + + shape: + status: complete + + plan: + path: string + completed_tasks: integer + total_tasks: integer + + task: + id: string + title: string + + changes: + files_changed: + - string + summary: + - string + + verification: + - command: string + outcome: passed + summary: string + + done_checks: + - check: string + evidence: string + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: none | local | domain | root + affected_areas: + - string + reason: string + + example: + status: complete + + plan: + path: context/plans/authentication.md + completed_tasks: 3 + total_tasks: 5 + + task: + id: T03 + title: Add login endpoint + + changes: + files_changed: + - src/auth/login.ts + - tests/auth/login.test.ts + summary: + - Added the login request handler. + - Reused the existing credential verifier and token response. + - Added focused success and failure tests. + + verification: + - command: npm test -- tests/auth/login.test.ts + outcome: passed + summary: 8 authentication tests passed. + + done_checks: + - check: Valid credentials return a token. + evidence: Covered by the successful login test. + - check: Invalid credentials return the standard authentication error. + evidence: Covered by the invalid-credential test. + - check: Targeted authentication tests pass. + evidence: npm test -- tests/auth/login.test.ts exited successfully. + + plan_update: + task_marked_complete: true + evidence_recorded: true + + context_impact: + classification: domain + affected_areas: + - authentication + reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.opencode/skills/sce-task-execution/references/implementation-gate.md b/.opencode/skills/sce-task-execution/references/implementation-gate.md new file mode 100644 index 00000000..d4ad836c --- /dev/null +++ b/.opencode/skills/sce-task-execution/references/implementation-gate.md @@ -0,0 +1,69 @@ +# Implementation gate + +Always show this gate at the start of `sce-task-execution`, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. diff --git a/.opencode/skills/sce-validation/SKILL.md b/.opencode/skills/sce-validation/SKILL.md index 9391ee6d..a2dc559d 100644 --- a/.opencode/skills/sce-validation/SKILL.md +++ b/.opencode/skills/sce-validation/SKILL.md @@ -1,47 +1,190 @@ --- name: sce-validation -description: | - Runs the final validation phase of a project plan by executing the full test suite, lint and format checks, removing temporary scaffolding, and writing a structured validation report with command outputs and success-criteria evidence to `context/plans/{plan_name}.md`. Use when the user wants to verify a completed implementation, confirm all success criteria are met, wrap up a plan, finalize a feature or fix, or sign off on a change before closing it out. +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one Markdown result (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. compatibility: opencode --- -## When to use -- Use for the plan's final validation task after implementation is complete. -- Triggered by requests like "validate the plan", "run final checks", "confirm everything passes", "wrap up the task", or "sign off on this change". - -## Validation checklist -1) **Run full test suite** - discover and run the project's primary test command (e.g., `pytest`, `npm test`, `go test ./...`, `cargo test`, `make test`). Check `package.json`, `Makefile`, `pyproject.toml`, or CI config files to find the right command. -2) **Run lint/format checks** - discover and run the project's lint and format tools (e.g., `eslint`, `ruff`, `golangci-lint`, `cargo clippy`, `make lint`). Check project config files such as `.eslintrc`, `pyproject.toml`, or `.golangci.yml`. -3) **Remove temporary scaffolding** - delete any debug code, temporary files, or intermediate artifacts introduced during the change. -4) **Verify context reflects final implemented behavior** - confirm that plan context and notes match the actual final state of the implementation. -5) **Confirm each success criterion has evidence** - for every success criterion defined in the plan, record concrete evidence (command output, exit code, screenshot reference, or file path). - -### If checks fail -- **Fixable failures**: fix the issue, re-run the failing check, and update the report with the corrected output. -- **Non-trivial failures**: document the failure, the attempted fix, and the blocker in the report under "Failed checks and follow-ups". Escalate to the user before closing out. -- **Lint/format auto-fixes**: if the tool supports auto-fix (e.g., `ruff --fix`, `eslint --fix`), apply it, then re-run to confirm clean output. - -## Validation report -Write to `context/plans/{plan_name}.md` including: -- Commands run -- Exit codes and key outputs -- Failed checks and follow-ups -- Success-criteria verification summary -- Residual risks, if any - -### Example report entry -``` -## Validation Report - -### Commands run -- `npm test` -> exit 0 (42 tests passed, 0 failed) -- `eslint src/` -> exit 0 (no warnings) -- Removed: `src/debug_patch.js` (temporary scaffolding) - -### Success-criteria verification -- [x] All API endpoints return 200 for valid input -> confirmed via test output line 34 -- [x] Error responses include structured JSON -> confirmed via `test_error_format.js` - -### Residual risks -- None identified. -``` +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Returning one Markdown validation result. + +Return a result matching: + +`references/validation-result.md` + +Write plan-file evidence matching: + +`references/validation-report.md` + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs `sce-plan-context-sync` only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, return `blocked`. + +When multiple plans match and none can be selected safely, return `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Return `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Return `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + `references/validation-report.md`. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so `sce-plan-context-sync` can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the Markdown result + +Return exactly one Markdown result: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/validation-result.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Return only the Markdown report. Do not add explanatory prose before or after +it. Do not return YAML. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a YAML result. +- Invoke plan context sync. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid Markdown result matching `references/validation-result.md` was + returned. diff --git a/.opencode/skills/sce-validation/references/validation-report.md b/.opencode/skills/sce-validation/references/validation-report.md new file mode 100644 index 00000000..877095ec --- /dev/null +++ b/.opencode/skills/sce-validation/references/validation-report.md @@ -0,0 +1,84 @@ +# Plan-file Validation Report + +The Markdown section `sce-validation` appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +`sce-validation` writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. diff --git a/.opencode/skills/sce-validation/references/validation-result.md b/.opencode/skills/sce-validation/references/validation-result.md new file mode 100644 index 00000000..569ec235 --- /dev/null +++ b/.opencode/skills/sce-validation/references/validation-result.md @@ -0,0 +1,186 @@ +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. From 6cb1a4fa940afef2676961757bd9e72720416c4b Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 22:04:38 +0200 Subject: [PATCH 07/21] context: Canonicalize workflow execution rules Define durable rules for context loading, planning, implementation approval, task synchronization, and final validation. Link the new contract from the context map and align existing workflow guidance with it. Plan: canonicalize-context-workflow-rules (T01) --- context/context-map.md | 1 + .../2026-03-03-plan-code-agent-separation.md | 2 +- .../canonicalize-context-workflow-rules.md | 88 +++++++++++ context/sce/context-workflow-rules.md | 139 ++++++++++++++++++ context/sce/shared-context-plan-workflow.md | 4 +- 5 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 context/plans/canonicalize-context-workflow-rules.md create mode 100644 context/sce/context-workflow-rules.md diff --git a/context/context-map.md b/context/context-map.md index 40284d19..a78331bd 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -24,6 +24,7 @@ Feature/domain context: - `context/sce/cli-observability-contract.md` (implemented config-backed runtime observability contract for the flat logging config-file shape with env-over-config fallback, concrete logger/telemetry runtime behavior plus logger and object-safe telemetry trait boundaries, AppContext observability wiring, generic `RunOutcome` final rendering, runtime-classified repeated telemetry action protection, operator-facing `sce config show` observability reporting, and the trimmed `sce config validate` status-only validation surface) - `context/sce/shared-context-code-workflow.md` - `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, and one-task/one-atomic-commit task-slicing policy) +- [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) - `context/sce/plan-code-overlap-map.md` (current overlap matrix for thin OpenCode Plan/Code routing agents, the three workflow commands, and their phase-skill ownership boundaries) - `context/sce/dedup-ownership-table.md` (current canonical owner-vs-consumer matrix for the three workflow packages, seven phase skills, shared sync skeleton, and thin OpenCode agents) diff --git a/context/decisions/2026-03-03-plan-code-agent-separation.md b/context/decisions/2026-03-03-plan-code-agent-separation.md index 49f204f9..b75dc382 100644 --- a/context/decisions/2026-03-03-plan-code-agent-separation.md +++ b/context/decisions/2026-03-03-plan-code-agent-separation.md @@ -27,7 +27,7 @@ Task: `T05` - Keep one canonical shared baseline block for cross-agent principles (`human owns decisions`, `context as durable memory`, `code truth wins`, and `context/` authority rules). - Keep role-specific mission, hard boundaries, and procedures local to each agent and phase-owning skills. -- Keep `/next-task` concise and orchestration-focused, delegating detailed contracts to `sce-plan-review`, `sce-task-execution`, and `sce-context-sync`. +- Keep `/next-task` concise and orchestration-focused, delegating detailed contracts to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. ## Consequences for follow-up tasks diff --git a/context/plans/canonicalize-context-workflow-rules.md b/context/plans/canonicalize-context-workflow-rules.md new file mode 100644 index 00000000..0aa2e494 --- /dev/null +++ b/context/plans/canonicalize-context-workflow-rules.md @@ -0,0 +1,88 @@ +# Plan: canonicalize-context-workflow-rules + +## Change summary + +Move the durable rules currently supplied in root-level `context-rules.md` into a focused, discoverable document under `context/`. Reconcile its obsolete bootstrap and singular synchronization descriptions with the canonical Pkl workflows, index the resulting document, and remove the stale root copy so there is one current source of durable guidance. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: The bootstrap, maintenance, and synchronization rules from `context-rules.md` have a canonical current-state-oriented home under `context/`, remain at most 250 lines, and are discoverable from `context/context-map.md` through relative links. + - Validate: Inspect the new context document and `context/context-map.md`; confirm the document covers bootstrap, ongoing invariants, task/plan synchronization, and feature-existence documentation, and run `wc -l ` to confirm the line limit. +- [x] AC2: The durable rules identify `sce setup --bootstrap-context` as the bootstrap boundary and the separately gated `sce-task-context-sync` and `sce-plan-context-sync` skills as the synchronization lifecycle, consistent with the canonical Pkl workflows. + - Validate: Compare the resulting document against `config/pkl/base/workflow-change-to-plan.pkl`, `config/pkl/base/workflow-next-task.pkl`, `config/pkl/base/workflow-validate.pkl`, and `config/pkl/base/workflow-context-sync.pkl`; confirm no obsolete `sce-bootstrap-context` or singular `sce-context-sync` ownership remains. +- [x] AC3: No conflicting root-level `context-rules.md` remains after its durable content is migrated. + - Validate: Confirm `context-rules.md` is absent and search repository documentation for stale references to that path or the obsolete workflow names. + +### Full validation + +- `nix flake check` +- `nix run .#pkl-check-generated` + +### Context sync + +- The new canonical rules document under `context/sce/` and `context/context-map.md` are the durable context changed by this plan. +- `context/overview.md`, `context/architecture.md`, `context/glossary.md`, and `context/patterns.md` must remain consistent with the canonical Pkl ownership model; update them only if the mandatory synchronization pass finds a material mismatch. + +## Constraints and non-goals + +- **In scope:** Migrate and reconcile `context-rules.md` into one focused document under `context/sce/`, update `context/context-map.md`, repair directly affected context links, and remove the superseded root file. +- **Out of scope:** Changes to Pkl workflow behavior, generated skill packages, commands, application code, tests, or unrelated durable context. +- **Constraints:** Treat `config/pkl/base/workflow-change-to-plan.pkl`, `workflow-next-task.pkl`, `workflow-validate.pkl`, and `workflow-context-sync.pkl` as code truth; keep context current-state oriented, focused, at most 250 lines per file, relatively linked, and indexed; do not delete `context-rules.md` if it has uncommitted changes not attributable to this change. +- **Non-goal:** Preserve obsolete skill names or turn the migrated document into a historical account of workflow evolution. + +## Assumptions + +- Place the canonical document in `context/sce/` because these are cross-workflow SCE rules and the existing workflow lifecycle documentation lives there. +- Migration means removing the superseded root file rather than retaining a duplicate that could drift independently. +- The exact focused filename and map section are reversible local choices and should follow neighboring `context/sce/` naming and indexing conventions. + +## Task stack + +- [x] T01: `Migrate context workflow rules into durable context` (status:done) + - Task ID: T01 + - Goal: Establish one canonical, Pkl-aligned context maintenance rules document under `context/sce/` and make it discoverable from the context index. + - Boundaries (in/out of scope): In — rewrite the durable substance of `context-rules.md` into a focused `context/sce/` document, reconcile bootstrap and synchronization ownership with current Pkl, update `context/context-map.md` and directly affected relative links, and remove the superseded root file when safe. Out — changing workflow implementation, generated assets, tests, or unrelated context. + - Dependencies: none + - Done when: The migrated document accurately describes current bootstrap, maintenance, task-sync, and plan-sync rules; it meets context hygiene constraints; the context map links it; stale references and obsolete workflow names are absent from the migrated guidance; and the root source has been safely removed. + - Verification notes (commands or checks): Inspect the document against the four canonical workflow Pkl modules; run `wc -l `; search documentation for `context-rules.md`, `sce-bootstrap-context`, and singular `sce-context-sync`; inspect all changed relative links; run `git diff --check`. + - Completed: 2026-07-27 + - Files changed: `context/sce/context-workflow-rules.md`, `context/context-map.md`, `context/sce/shared-context-plan-workflow.md`, `context/decisions/2026-03-03-plan-code-agent-separation.md`; removed the untracked superseded source `context-rules.md` after migrating its durable content. + - Evidence: Compared the migrated rules with `config/pkl/base/workflow-change-to-plan.pkl`, `workflow-next-task.pkl`, `workflow-validate.pkl`, and `workflow-context-sync.pkl`; `wc -l context/sce/context-workflow-rules.md` reported 139 lines; a documentation search outside historical plan artifacts found no `context-rules.md`, `sce-bootstrap-context`, or singular `sce-context-sync`; all added relative links resolve; `test ! -e context-rules.md` and `git diff --check` passed. + - Notes: Updated the directly affected plan-workflow bootstrap continuation and decision record to current canonical ownership. No workflow implementation or generated assets changed. + +## Open questions + +None. The loaded brief identifies both the missing durable owner and the canonical Pkl sources needed to reconcile the stale rules. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-27 + +### Commands run + +- `nix flake check` -> exit 0 (all flake checks passed) +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral Pkl generation passed for 73 files) +- `wc -l context/sce/context-workflow-rules.md && test ! -e context-rules.md && git diff --check` -> exit 0 (canonical rules are 139 lines, the root copy is absent, and the diff is clean) +- `nix run nixpkgs#bun -- -e ''` -> exit 0 (all changed-document relative links resolve) +- `nix run nixpkgs#ripgrep -- -n --glob '*.md' --glob '!context/plans/**' 'context-rules\\.md|sce-bootstrap-context|`sce-context-sync`' .` -> exit 0 (no stale current-documentation references found) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: The bootstrap, maintenance, and synchronization rules have a canonical current-state-oriented home under `context/`, remain at most 250 lines, and are discoverable from the context map -> inspected `context/sce/context-workflow-rules.md` and `context/context-map.md`; all required subjects are covered, the relative link resolves, and the document is 139 lines. +- [x] AC2: The durable rules name the current bootstrap boundary and separate task/plan synchronization lifecycle -> compared the document with all four canonical Pkl workflow modules; ownership and success gates match `sce setup --bootstrap-context`, `sce-task-context-sync`, and `sce-plan-context-sync`. +- [x] AC3: No conflicting root-level rules file or stale current-documentation reference remains -> the root file absence check and the documentation search both passed; obsolete references remain only in historical plan artifacts. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- Historical active-plan artifacts still mention superseded names as recorded execution history; the canonical current-state context excludes them. diff --git a/context/sce/context-workflow-rules.md b/context/sce/context-workflow-rules.md new file mode 100644 index 00000000..3038794b --- /dev/null +++ b/context/sce/context-workflow-rules.md @@ -0,0 +1,139 @@ +# Context Workflow Rules + +## Purpose + +`context/` is durable, AI-first repository memory. It records the current state +needed to plan, implement, and validate changes without rediscovering the +repository. Code and executable configuration remain the source of truth; when +context disagrees with them, context must be repaired. + +The workflow lifecycle is described in +[Shared Context Plan Workflow](shared-context-plan-workflow.md) and +[Shared Context Code Workflows](shared-context-code-workflow.md). + +## Bootstrap boundary + +When `sce-context-load` reports that `context/` is absent, the active workflow +stops. It does not create durable context. The user bootstraps it with: + +`sce setup --bootstrap-context` + +That command owns creation of the baseline context tree. The baseline contains: + +- `context/overview.md` +- `context/architecture.md` +- `context/patterns.md` +- `context/glossary.md` +- `context/context-map.md` +- `context/plans/` +- `context/handovers/` +- `context/decisions/` +- `context/tmp/` with a `.gitignore` that ignores scratch content + +Bootstrap must not invent application details. For a repository without +application code, baseline documents remain empty or placeholder-only. The +context map links the baseline entry points, and the resulting tree is committed +as shared memory. After bootstrap, the waiting workflow reloads context and +continues with the original request. + +## Ongoing invariants + +### Current-state orientation + +- Describe resulting behavior and structure, not completed-work summaries or a + narrative changelog. +- Repair context when code or executable configuration has outrun it. +- Keep one authoritative location for each durable fact. + +### File hygiene + +- Keep one topic per file and every context file at or below 250 lines. +- Split growing detail into focused domain files and link them with relative + Markdown links. +- Use a Mermaid diagram when structure, boundaries, or flow are too complex for + prose alone. +- Include code examples only when they clarify non-trivial behavior. +- Keep root context concise and put feature detail under `context/{domain}/`. + +### Authority and deletion safety + +- Context-maintenance phases may create, edit, move, rename, or delete files + under `context/`. +- New top-level context domains may be created when durable knowledge needs one. +- Do not delete a context file with uncommitted changes. +- Planning reads durable context but does not modify it outside an authored plan. + Planning does not authorize implementation. + +### Durable and disposable areas + +- `context/plans/` contains active execution artifacts, not durable history. +- `context/handovers/` contains task-transition notes. +- `context/tmp/` is ignored scratch space. +- Promote lasting outcomes into current-state domain files or + `context/decisions/` when rationale must remain discoverable. + +### Discoverability and feature existence + +- `context/context-map.md` is the index. New canonical context must be linked + there, and moved or renamed files require updated cross-references. +- Every implemented feature has at least one durable canonical description + reachable from the map: a focused domain file, or `context/overview.md` for a + genuinely cross-cutting feature. + +## Synchronization lifecycle + +Synchronization is split by lifecycle boundary. Both phases share the canonical +rules in `config/pkl/base/workflow-context-sync.pkl`, but receive different +authoritative handoffs. + +### Task synchronization + +`sce-task-context-sync` runs from `/next-task` only after +`sce-task-execution` returns `complete`. It reconciles one implemented and +verified task with durable context. Declined, blocked, and incomplete executions +do not enter synchronization. + +### Plan synchronization + +`sce-plan-context-sync` runs from `/validate` only after `sce-validation` +returns `Status: validated`. It performs the final plan-level pass using the +plan's Context sync requirements and validation evidence. Failed or blocked +validation does not enter synchronization. + +A synchronization blocker does not undo the successful prior phase. The task or +validation evidence remains recorded, but the workflow stops because durable +context is out of date and must be reconciled before continuing or closing the +plan. + +### Mandatory synchronization pass + +Every task and plan synchronization verifies these files against code truth, +whether or not an edit is warranted: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Synchronization then inspects the affected domain, classifies the impact, and +makes the smallest coherent documentation change: + +- `none`: no edit unless the mandatory pass finds drift. +- `local`: update the nearest authoritative context when behavior is not obvious + from code. +- `domain`: update affected domain context and map metadata or links. +- `root`: update root and domain context for cross-cutting policy, architecture, + ownership, or terminology changes. + +Every pass also accounts for feature existence, adds glossary entries for new +domain language, verifies relative links and line limits, and reports each root +file as verified, edited, or absent. Task synchronization does not run full-plan +validation, and plan synchronization does not rerun final validation. + +## Canonical sources + +- `config/pkl/base/workflow-change-to-plan.pkl` +- `config/pkl/base/workflow-next-task.pkl` +- `config/pkl/base/workflow-validate.pkl` +- `config/pkl/base/workflow-context-sync.pkl` diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index d1d6173c..77ae2e95 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -31,7 +31,9 @@ When context loading returns `bootstrap_required`, the workflow stops without cr `sce setup --bootstrap-context` -The user then reruns `/change-to-plan` with the original request. +After the user reports that bootstrap completed, the waiting workflow invokes +`sce-context-load` again and continues with the original request in the same +session. ## Planning boundary From ceac3414911c02d6949f644f6c2a3dc7fc3bd9ae Mon Sep 17 00:00:00 2001 From: David Abram Date: Mon, 27 Jul 2026 23:55:17 +0200 Subject: [PATCH 08/21] build: Add pre-Cargo Pkl payload generation Generate a fresh payload before repository Cargo commands and teach Nix and build.rs to consume an explicit generated-input directory. Add wrapper tests and update build contracts so Crane no longer evaluates Pkl independently in each Cargo derivation. Plan: generate-cli-assets-in-cargo-out-dir (T04, T05, T06) Co-authored-by: SCE --- AGENTS.md | 10 +- cli/README.md | 24 +- cli/build.rs | 323 ++++++++++++++++-- context/architecture.md | 10 +- context/cli/cli-command-surface.md | 2 +- context/context-map.md | 8 +- ...26-07-27-ephemeral-pkl-build-generation.md | 4 +- context/glossary.md | 7 +- context/overview.md | 10 +- context/patterns.md | 8 +- .../generate-cli-assets-in-cargo-out-dir.md | 112 +++++- .../sce/cli-cargo-distribution-contract.md | 11 +- context/sce/flake-build-performance.md | 11 + context/sce/pi-extension-runtime.md | 8 +- flake.nix | 104 +++++- scripts/run-cli-cargo.sh | 114 +++++++ scripts/test-run-cli-cargo.sh | 124 +++++++ 17 files changed, 802 insertions(+), 88 deletions(-) create mode 100755 scripts/run-cli-cargo.sh create mode 100755 scripts/test-run-cli-cargo.sh diff --git a/AGENTS.md b/AGENTS.md index af7f8543..a1476c41 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,13 +45,14 @@ This repository uses the Shared Context Engineering (SCE) approach for AI-assist Run these through Nix from repo root unless noted otherwise. -- Build CLI: `nix develop -c sh -c 'cd cli && cargo build'` -- Run CLI: `nix develop -c sh -c 'cd cli && cargo run -- --help'` +- Build CLI: `nix develop -c ./scripts/run-cli-cargo.sh build --manifest-path cli/Cargo.toml` +- Run CLI: `nix develop -c ./scripts/run-cli-cargo.sh run --manifest-path cli/Cargo.toml -- --help` - Build packaged CLI output: `nix build .#default` - Run packaged CLI app: `nix run .#sce -- --help` - Preferred repo-level verification: `nix flake check` -- Run a single Rust test by exact name when explicitly needed: `nix develop -c sh -c 'cd cli && cargo test parser_routes_mcp -- --exact'` -- Run Rust tests in one module/file pattern when explicitly needed: `nix develop -c sh -c 'cd cli && cargo test setup'` +- Run a single Rust test by exact name when explicitly needed: `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml parser_routes_mcp -- --exact` +- Run Rust tests in one module/file pattern when explicitly needed: `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup` +- Run pre-Cargo wrapper tests: `bash scripts/test-run-cli-cargo.sh` - Run ignored? none were found; do not assume ignored-test flows exist. - Rust format verification is covered by `nix flake check` - Auto-format: `nix develop -c sh -c 'cd cli && cargo fmt'` @@ -73,6 +74,7 @@ Run these from `config/lib/bash-policy-plugin/` when working on the Bun-owned Op ## Testing notes - Rust tests live inline in source files and in module test files such as `cli/src/services/setup/tests.rs`. +- Repository Cargo builds must use `scripts/run-cli-cargo.sh`; it generates a fresh temporary Pkl payload, passes `SCE_CLI_GENERATED_INPUT_DIR` to Cargo, and cleans up the payload afterward. - Rust/Cargo commands should be executed through `nix develop`, even for one-off builds, tests, fmt, and clippy runs. - Prefer `nix flake check` for routine verification and avoid `cargo test` unless the user explicitly asks for it. - Rust single-test selection uses standard Cargo substring matching; add `-- --exact` for deterministic one-test runs. diff --git a/cli/README.md b/cli/README.md index 8bbf1051..ba0babd4 100644 --- a/cli/README.md +++ b/cli/README.md @@ -23,18 +23,34 @@ Published Cargo releases target the `shared-context-engineering` crate and insta cargo install shared-context-engineering --locked ``` -### Git repository +### Local checkout + +Repository source builds require Pkl-generated assets to be prepared before +Cargo starts. From the repository root, use the repository-owned wrapper rather +than invoking Cargo directly: ```bash -cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked +./scripts/run-cli-cargo.sh install --path cli --locked ``` -### Local checkout +The wrapper creates a fresh temporary payload from the canonical Pkl inputs, +passes it to the build through `SCE_CLI_GENERATED_INPUT_DIR`, and removes it when +Cargo exits. Direct `cargo install --git` is not supported because a Git install +has no pre-Cargo generation boundary; use crates.io or a local checkout instead. + +## Develop from a local checkout + +Use the same wrapper for supported Cargo development workflows: ```bash -cargo install --path cli --locked +./scripts/run-cli-cargo.sh build --manifest-path cli/Cargo.toml +./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup +./scripts/run-cli-cargo.sh clippy --manifest-path cli/Cargo.toml --all-targets -- -D warnings ``` +The wrapper requires `pkl`, `cargo`, and `sha256sum` on `PATH`. The repository +Nix dev shell provides them when they are not installed by the host system. + ## Other supported install channels - Nix: `nix run github:crocoder-dev/shared-context-engineering -- --help` diff --git a/cli/build.rs b/cli/build.rs index ef132573..eb9cdbc3 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,18 +1,27 @@ use sha2::{Digest, Sha256}; use std::{ env, + ffi::OsString, fmt::Write, fs, io::{self, Write as IoWrite}, path::{Path, PathBuf}, - process::Command, }; const PKL_OUTPUT_DIR: &str = "pkl-generated"; const STATIC_OUTPUT_DIR: &str = "static"; const MIGRATIONS_ROOT: &str = "migrations"; +const GENERATED_INPUT_ENV: &str = "SCE_CLI_GENERATED_INPUT_DIR"; +const GENERATED_INPUT_INVENTORY: &str = "SHA256SUMS"; +const CANONICAL_INPUT_INVENTORY: &str = "INPUTS.SHA256SUMS"; const PACKAGE_FALLBACK_DIR: &str = "package-fallback"; const PACKAGE_FALLBACK_INVENTORY: &str = "SHA256SUMS"; +const CANONICAL_GENERATOR_INPUTS: &[&str] = &[ + "config/pkl", + "config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts", + "config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts", + "config/lib/pi-plugin/sce-pi-extension.ts", +]; const TARGETS: &[TargetSpec] = &[ TargetSpec { @@ -57,7 +66,9 @@ fn prepare_build_artifacts() -> io::Result<()> { let out_dir = PathBuf::from(env::var("OUT_DIR").map_err(|e| invalid_data(&e))?); if repository_sources_available(repository_root) { - generate_pkl_outputs(repository_root, &out_dir)?; + println!("cargo:rerun-if-env-changed={GENERATED_INPUT_ENV}"); + let generated_input_root = generated_input_root(env::var_os(GENERATED_INPUT_ENV))?; + stage_generated_input(repository_root, &generated_input_root, &out_dir)?; stage_static_inputs(repository_root, &manifest_dir, &out_dir)?; } else { stage_packaged_fallback(&manifest_dir, &out_dir)?; @@ -72,49 +83,119 @@ fn repository_sources_available(repository_root: &Path) -> bool { && repository_root.join("config/lib").is_dir() } -fn generate_pkl_outputs(repository_root: &Path, out_dir: &Path) -> io::Result<()> { - let pkl_root = repository_root.join("config/pkl"); - let config_lib_root = repository_root.join("config/lib"); - emit_rerun_tree(&pkl_root)?; - emit_rerun_tree(&config_lib_root)?; +fn generated_input_root(value: Option) -> io::Result { + let value = value.ok_or_else(|| { + invalid_data(&format!( + "repository builds require a pre-generated Pkl payload. Set {GENERATED_INPUT_ENV} to a generated-input directory containing {PKL_OUTPUT_DIR}/, {GENERATED_INPUT_INVENTORY}, and {CANONICAL_INPUT_INVENTORY}" + )) + })?; + if value.is_empty() { + return Err(invalid_data(&format!( + "{GENERATED_INPUT_ENV} is empty; set it to a generated-input directory" + ))); + } + Ok(PathBuf::from(value)) +} + +fn stage_generated_input( + repository_root: &Path, + generated_input_root: &Path, + out_dir: &Path, +) -> io::Result<()> { + for relative_path in CANONICAL_GENERATOR_INPUTS { + let path = repository_root.join(relative_path); + if path.is_dir() { + emit_rerun_tree(&path)?; + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } + } + + let payload_inventory = generated_input_root.join(GENERATED_INPUT_INVENTORY); + let canonical_inventory = generated_input_root.join(CANONICAL_INPUT_INVENTORY); + println!("cargo:rerun-if-changed={}", payload_inventory.display()); + println!("cargo:rerun-if-changed={}", canonical_inventory.display()); + + validate_inventory( + generated_input_root, + &[PKL_OUTPUT_DIR], + &payload_inventory, + "generated Pkl payload", + )?; + validate_inventory( + repository_root, + CANONICAL_GENERATOR_INPUTS, + &canonical_inventory, + "canonical Pkl inputs", + ) + .map_err(|error| { + invalid_data(&format!( + "generated Pkl payload at '{}' is stale: {error}. Regenerate it from the current config/pkl and config/lib inputs", + generated_input_root.display() + )) + })?; let output_root = out_dir.join(PKL_OUTPUT_DIR); remove_path_if_exists(&output_root)?; - fs::create_dir_all(&output_root)?; - - let generator = pkl_root.join("generate.pkl"); - let status = Command::new("pkl") - .arg("eval") - .arg("-m") - .arg(&output_root) - .arg(&generator) - .current_dir(repository_root) - .status() - .map_err(|error| { - invalid_data(&format!( - "could not run Pkl generator '{}': {error}. Run Cargo from the Nix dev shell", - generator.display() - )) - })?; - - if !status.success() { + copy_tree(&generated_input_root.join(PKL_OUTPUT_DIR), &output_root)?; + + Ok(()) +} + +fn validate_inventory( + root: &Path, + directories: &[&str], + inventory_path: &Path, + description: &str, +) -> io::Result<()> { + let expected = fs::read_to_string(inventory_path).map_err(|error| { + invalid_data(&format!( + "{description} inventory '{}' is unavailable: {error}", + inventory_path.display() + )) + })?; + let actual = inventory_for_paths(root, directories).map_err(|error| { + invalid_data(&format!( + "could not inspect {description} under '{}': {error}", + root.display() + )) + })?; + if actual != expected { return Err(invalid_data(&format!( - "Pkl generator '{}' exited with {status}", - generator.display() + "{description} inventory '{}' does not match the current files", + inventory_path.display() ))); } + Ok(()) +} - for target in TARGETS.iter().take(3) { - let expected_root = output_root.join(target.generated_root); - if !expected_root.is_dir() { +fn inventory_for_paths(root: &Path, paths: &[&str]) -> io::Result { + let mut files = Vec::new(); + for relative_path in paths { + let path = root.join(relative_path); + if path.is_dir() { + collect_files(root, &path, &mut files)?; + } else if path.is_file() { + files.push(SourceFile { + relative_path: normalize_relative_path(Path::new(relative_path))?, + absolute_path: path, + }); + } else { return Err(invalid_data(&format!( - "Pkl generator did not emit required target directory '{}'", - expected_root.display() + "required path '{}' is missing", + path.display() ))); } } + files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path)); - Ok(()) + let mut inventory = String::new(); + for file in files { + let digest = compute_sha256(&fs::read(&file.absolute_path)?); + writeln!(inventory, "{} {}", format_hex(&digest), file.relative_path) + .expect("writing to String buffer should never fail"); + } + Ok(inventory) } fn stage_packaged_fallback(manifest_dir: &Path, out_dir: &Path) -> io::Result<()> { @@ -564,3 +645,179 @@ fn write_if_changed(path: &Path, bytes: &[u8]) -> io::Result<()> { fn invalid_data(error: &E) -> io::Error { io::Error::new(io::ErrorKind::InvalidData, error.to_string()) } + +#[cfg(test)] +mod tests { + use std::{ + ffi::OsString, + fs, + path::{Path, PathBuf}, + sync::atomic::{AtomicU64, Ordering}, + }; + + use super::{ + generated_input_root, inventory_for_paths, stage_generated_input, + CANONICAL_GENERATOR_INPUTS, CANONICAL_INPUT_INVENTORY, GENERATED_INPUT_INVENTORY, + PKL_OUTPUT_DIR, + }; + + static NEXT_TEMP_ID: AtomicU64 = AtomicU64::new(0); + + struct TempDir(PathBuf); + + impl TempDir { + fn new(name: &str) -> Self { + let id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed); + let path = std::env::temp_dir().join(format!( + "sce-build-script-{name}-{}-{id}", + std::process::id() + )); + fs::create_dir_all(&path).expect("create test temporary directory"); + Self(path) + } + + fn path(&self) -> &Path { + &self.0 + } + } + + impl Drop for TempDir { + fn drop(&mut self) { + fs::remove_dir_all(&self.0).expect("remove test temporary directory"); + } + } + + fn write_file(root: &Path, relative_path: &str, contents: &str) { + let path = root.join(relative_path); + fs::create_dir_all(path.parent().expect("fixture file parent")) + .expect("create fixture directory"); + fs::write(path, contents).expect("write fixture file"); + } + + fn create_fixture() -> (TempDir, PathBuf, PathBuf) { + let temp = TempDir::new("handoff"); + let repository_root = temp.path().join("repository"); + let handoff_root = temp.path().join("handoff"); + + write_file(&repository_root, "config/pkl/generate.pkl", "generator"); + write_file( + &repository_root, + "config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts", + "agent trace", + ); + write_file( + &repository_root, + "config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts", + "bash policy", + ); + write_file( + &repository_root, + "config/lib/pi-plugin/sce-pi-extension.ts", + "pi extension", + ); + write_file( + &handoff_root, + "pkl-generated/config/.opencode/opencode.json", + "opencode", + ); + write_file( + &handoff_root, + "pkl-generated/config/.claude/settings.json", + "claude", + ); + write_file( + &handoff_root, + "pkl-generated/config/.pi/extensions/sce/index.ts", + "pi", + ); + + let payload_inventory = + inventory_for_paths(&handoff_root, &[PKL_OUTPUT_DIR]).expect("payload inventory"); + fs::write( + handoff_root.join(GENERATED_INPUT_INVENTORY), + payload_inventory, + ) + .expect("write payload inventory"); + let canonical_inventory = inventory_for_paths(&repository_root, CANONICAL_GENERATOR_INPUTS) + .expect("canonical inventory"); + fs::write( + handoff_root.join(CANONICAL_INPUT_INVENTORY), + canonical_inventory, + ) + .expect("write canonical inventory"); + + (temp, repository_root, handoff_root) + } + + #[test] + fn generated_input_requires_handoff_environment_value() { + let error = generated_input_root(None).expect_err("missing handoff must fail"); + assert!(error + .to_string() + .contains("repository builds require a pre-generated Pkl payload")); + assert!(generated_input_root(Some(OsString::from(""))).is_err()); + } + + #[test] + fn missing_generated_input_directory_is_rejected() { + let temp = TempDir::new("missing-handoff"); + let repository_root = temp.path().join("repository"); + write_file(&repository_root, "config/pkl/generate.pkl", "generator"); + for relative_path in CANONICAL_GENERATOR_INPUTS.iter().skip(1) { + write_file(&repository_root, relative_path, "plugin"); + } + + let error = stage_generated_input( + &repository_root, + &temp.path().join("missing"), + &temp.path().join("out"), + ) + .expect_err("missing handoff directory must fail"); + assert!(error.to_string().contains("inventory")); + assert!(error.to_string().contains("is unavailable")); + } + + #[test] + fn valid_generated_input_is_copied_with_matching_inventory() { + let (temp, repository_root, handoff_root) = create_fixture(); + let out_dir = temp.path().join("out"); + + stage_generated_input(&repository_root, &handoff_root, &out_dir) + .expect("valid handoff should be staged"); + + let expected = + inventory_for_paths(&handoff_root, &[PKL_OUTPUT_DIR]).expect("source inventory"); + let actual = inventory_for_paths(&out_dir, &[PKL_OUTPUT_DIR]).expect("copied inventory"); + assert_eq!(actual, expected); + } + + #[test] + fn incomplete_generated_input_is_rejected() { + let (temp, repository_root, handoff_root) = create_fixture(); + fs::remove_file(handoff_root.join("pkl-generated/config/.claude/settings.json")) + .expect("remove generated fixture file"); + + let error = + stage_generated_input(&repository_root, &handoff_root, &temp.path().join("out")) + .expect_err("incomplete handoff must fail"); + assert!(error + .to_string() + .contains("generated Pkl payload inventory")); + } + + #[test] + fn stale_generated_input_is_rejected() { + let (temp, repository_root, handoff_root) = create_fixture(); + write_file( + &repository_root, + "config/lib/pi-plugin/sce-pi-extension.ts", + "changed extension", + ); + + let error = + stage_generated_input(&repository_root, &handoff_root, &temp.path().join("out")) + .expect_err("stale handoff must fail"); + assert!(error.to_string().contains("is stale")); + assert!(error.to_string().contains("Regenerate it")); + } +} diff --git a/context/architecture.md b/context/architecture.md index 4249a235..9be414dd 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -81,7 +81,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - Repo-root `.version` is the canonical checked-in release version authority across GitHub Releases, Cargo publication, and npm publication. - GitHub Releases are the canonical publication surface for release archives, checksums, release-manifest assets, npm package assets, and approved Flatpak source-manifest and bundle assets. - Cargo/crates.io and npm registry publication belong to separate downstream publish stages that consume already-versioned checked-in package metadata rather than inventing release versions during workflow execution. -- Crates.io packaging is self-contained through ignored `cli/package-fallback/`: the preparation script generates and inventories the payload from canonical Pkl plus static inputs in a temporary clean workspace, `cli/Cargo.toml` includes only that fallback and crate sources, and unpacked-crate `build.rs` validates then copies it into `OUT_DIR` without Pkl. Repository builds detect canonical Pkl sources first and retain direct generation as the authoritative path. +- Crates.io packaging is self-contained through ignored `cli/package-fallback/`: the preparation script generates and inventories the payload from canonical Pkl plus static inputs in a temporary clean workspace, `cli/Cargo.toml` includes only that fallback and crate sources, and unpacked-crate `build.rs` validates then copies it into `OUT_DIR` without Pkl. Repository builds use `scripts/run-cli-cargo.sh` to generate a fresh deterministic payload and both inventories before Cargo; `build.rs` requires the resulting `SCE_CLI_GENERATED_INPUT_DIR` handoff and copies it into `OUT_DIR` without invoking Pkl. - npm is a downstream consumer of the shared release artifact contract rather than a separate build owner. - `flake.nix` now exposes dedicated release-packaging apps for this rollout: `apps.release-artifacts` packages the current-platform `sce` archive/checksum/manifest-fragment set from the release output `packages.sce-release` (`nix build .#sce-release`), prepares/audits the staged `bin/sce` before archive creation (including macOS `libiconv` install-name rewriting plus ad-hoc re-signing when needed), and fails if `.version`, `cli/Cargo.toml`, `npm/package.json`, the built/prepared CLI version, or the native portability audit disagree; `apps.native-portability-audit` audits native binaries for forbidden `/nix/store/` runtime references using Linux ELF/string inspection or macOS `otool -L`; `apps.release-manifest` merges per-platform metadata fragments into release-level manifest/checksum outputs and signs the merged manifest with a non-repo private key provided via env/file input; `apps.release-npm-package` packs the checked-in npm launcher package into a release-ready `sce-v-npm.tgz` tarball plus npm metadata JSON while refusing mismatched checked-in version metadata; and Linux-only `apps.release-flatpak-package` emits the Flatpak source-manifest tarball/checksum/JSON metadata while refusing `.version`/Cargo/npm/AppStream version drift and non-git checkouts that cannot resolve a release commit; Linux-only `apps.release-flatpak-bundle` builds a source-built `.flatpak` bundle from the checkout and emits per-architecture bundle/checksum/JSON metadata. - CLI release automation: `.github/workflows/release-sce.yml` orchestrates `sce` GitHub release asset assembly, validates `.version`/Cargo/npm parity before tagging or releasing, calls three reusable per-platform workflow files (`release-sce-linux.yml`, `release-sce-linux-arm.yml`, `release-sce-macos-arm.yml`), assembles the signed native release manifest, builds npm and Flatpak source-manifest release packages, and uploads the CLI/npm/Flatpak asset set to the GitHub Release. Each native reusable workflow validates its generated archive before native artifact upload by extracting the target archive, smoke-running `bin/sce version --format json`, and running `nix run .#native-portability-audit` with the lane platform. Manual `workflow_dispatch` runs can set the GitHub Release-level `prerelease` flag through an explicit checkbox; tag-triggered releases keep the flag false and no tag-name prerelease inference is performed. @@ -112,7 +112,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/auth_db/mod.rs` provides the encrypted auth DB spec and `AuthDb` type alias over `EncryptedTursoDb`. `AuthDbSpec` resolves `/sce/auth.db` through the shared default-path seam and embeds ordered auth migrations. Auth DB lifecycle setup/doctor integration is wired through `AuthDbLifecycle`; auth command/token-storage reads/writes are directed through `token_storage.rs`. - `cli/src/services/agent_trace_db/mod.rs` owns the shared Agent Trace insert payloads, SQL constants, and typed row helpers (diff-trace/intersection/Agent Trace/message/part) plus `ensure_schema_ready_for_hooks()` consumed by the repository adapter. `cli/src/services/agent_trace_db/repository.rs` defines the sole `RepositoryAgentTraceDb` adapter over `TursoDb` with one fresh `agent-trace-repository/001_repository_schema.sql` baseline for `diff_traces` (including `payload_type`), `post_commit_patch_intersections`, `agent_traces`, `messages`, `parts`, indexes, and triggers, `repository_metadata` validation, no trace-table `checkout_id` columns, `agent_traces.agent_trace_id NOT NULL UNIQUE`, and `recent_diff_trace_patches(cutoff_time_ms, end_time_ms)` using the inclusive chronological parser without checkout filtering. Active hook runtime, setup/lifecycle storage, and trace status/list/shell flows resolve through `agent_trace_storage` and use `RepositoryAgentTraceDb`. The checkout-scoped `AgentTraceDb`/`AgentTraceDbSpec` adapter, its `agent_trace_db_path()`/`agent_trace_db_path_for_checkout()` helpers, the 15-file `cli/migrations/agent-trace/` chain, and the `sce trace --legacy` surface were removed by the `retire-legacy-agent-trace-db` plan. - `cli/src/test_support.rs` provides a shared test-only temp-directory helper (`TestTempDir`) used by service tests that need filesystem fixtures. -- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), and compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups). For repository builds, `cli/build.rs` evaluates canonical Pkl outputs into Cargo `OUT_DIR/pkl-generated`, stages `cli/assets/hooks/**` under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; focused internal seams separate install-flow from prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). The setup command derives a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. +- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), and compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups). For repository builds, `cli/build.rs` validates the `SCE_CLI_GENERATED_INPUT_DIR` payload and canonical-input inventories, copies the payload into Cargo `OUT_DIR/pkl-generated`, stages `cli/assets/hooks/**` under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; focused internal seams separate install-flow from prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). The setup command derives a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. - `cli/src/services/setup/mod.rs` keeps those responsibilities inside one file for now, but the current ownership split is explicit: the inline `install` module owns repository-path normalization, staging/swap install behavior, required-hook installation, and filesystem safety guards, while the inline `prompt` module owns interactive target selection and prompt styling. - `cli/src/services/security.rs` provides shared security utilities for deterministic secret redaction (`redact_sensitive_text`) and directory write-permission probes (`ensure_directory_is_writable`) used by app/setup/observability surfaces. - `cli/src/services/doctor/mod.rs` owns the current doctor request/report surface while focused submodules (`doctor/inspect.rs`, `doctor/render.rs`, `doctor/fixes.rs`, `doctor/types.rs`) split report fact collection, rendering, manual fix reporting, and doctor-owned domain types into smaller seams; `cli/src/services/doctor/command.rs` owns the `DoctorCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Runtime doctor execution resolves a repository root, derives a scoped context, requests the shared static lifecycle provider catalog with hooks included for service-owned `diagnose` and `fix` behavior, adapts lifecycle-owned health/fix records into doctor-owned problem/fix records, and then renders stable text/JSON problem records with category/severity/fixability/remediation fields plus deterministic fix-result reporting in fix mode. Checkout DB discovery no longer lives in `doctor`; it moved to the `trace` group (`sce trace db list`) in `cli/src/services/trace/`. Report fact collection preserves environment/repository/hook/integration display data and checkout identity facts, while service-owned lifecycle providers own config validation, local DB and repository-scoped Agent Trace DB readiness/bootstrap, and hook rollout diagnosis/repair. @@ -126,8 +126,8 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/structured_patch.rs` defines the synchronous structured editor-hook derivation seam. It derives Claude `PostToolUse` `Write` structured-update hunks, `Write` `tool_input.content` create fallback, and `Edit` structured-patch payloads into canonical `ParsedPatch` values plus Claude session/tool metadata, returning deterministic skip reasons for unsupported events/tools/payload shapes. The module is pure and side-effect-free. It is wired into `sce hooks diff-trace` for Claude payload classification at intake (T04) and into `RepositoryAgentTraceDb::recent_diff_trace_patches` for post-commit structured payload parsing dispatch at read time (T05). - `cli/src/services/` contains module boundaries for command_registry, lifecycle, auth_command, config, setup, doctor, hooks, checkout identity, bash_policy, version, completion, help, patch, SCE web URL helpers, shared database infrastructure, local DB adapters, encrypted auth DB adapters, and Agent Trace DB adapters with explicit trait seams for future implementations. `cli/src/services/checkout/` owns checkout ID file infrastructure (the per-checkout Agent Trace DB opener/path helper was removed by the `retire-legacy-agent-trace-db` plan); active setup/hooks use `agent_trace_storage` to establish checkout identity as diagnostics and initialize/open the repository-scoped DB, while `sce doctor` surfaces checkout identity facts plus credential-safe repository Agent Trace DB metadata. There is no checkout-scoped discovery or `sce trace --legacy` surface; any pre-migration `agent-trace-*.db` files on disk are never touched and no longer inspectable via the CLI. `cli/src/services/bash_policy.rs` owns both the CLI-agnostic evaluator logic and the hidden `sce policy bash` command adapter used by OpenCode, Claude, and Pi callers. `cli/src/services/command_registry.rs` defines the static `RuntimeCommand` enum, deterministic `CommandRegistry` name catalog, and `build_default_registry()` function for command dispatch metadata. Service-owned command modules own the runtime command payload structs for help/help-text, version, completion, auth, config, setup, doctor, hooks, and policy. - `cli/README.md` is the crate-local onboarding and usage source of truth for placeholder behavior, safety limitations, and roadmap mapping back to service contracts. -- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, and reads package/check version from repo-root `.version`. Crane package/test/clippy sources include canonical Pkl, referenced plugin/extension sources, and static inputs, with Pkl on the native build path so `cli/build.rs` evaluates directly into `OUT_DIR`; published crates use the validated packaging-only fallback. The build script stages SQL under `OUT_DIR/static/migrations` and writes `OUT_DIR/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. -- The root flake runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed paths for the CLI crate; `cli-fmt` intentionally uses the CLI-only Cargo source set. The flake also exposes directory-scoped JS validation derivations for `npm/` and `config/lib/`, while `pkl-generated` uses a narrow canonical-input source set plus maybe-missing forbidden paths so reintroduced generated repository artifacts fail the check. +- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, and reads package/check version from repo-root `.version`. Its `cliGeneratedInput` derivation evaluates the canonical Pkl model twice, rejects nondeterminism, and writes exact payload and canonical-input SHA-256 inventories. Native, release, test, and Clippy Cargo derivations receive that same store path through `SCE_CLI_GENERATED_INPUT_DIR`; their Cargo environments exclude Pkl and assert that it is unavailable. Repository-mode `cli/build.rs` validates the handoff before copying it into `OUT_DIR`; published crates use the validated packaging-only fallback. The build script stages SQL under `OUT_DIR/static/migrations` and writes `OUT_DIR/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. +- Crane dependency-only derivations and `cli-fmt` intentionally do not receive `SCE_CLI_GENERATED_INPUT_DIR`, so canonical generation changes invalidate the producer and compiling derivations while preserving host/musl dependency artifacts and formatting. The root flake runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed paths and exposes `cli-generated-input` as the focused payload/inventory integrity check. It also exposes directory-scoped JS validation derivations for `npm/` and `config/lib/`, while `pkl-generated` uses a narrow canonical-input source set plus maybe-missing forbidden paths so reintroduced generated repository artifacts fail the check. - Git-commit embedding is release-only. `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment (`{ SCE_GIT_COMMIT = shortGitCommit; }`) merged only into the release derivations — `scePackageMusl` on Linux and a dedicated native-toolchain `sceReleasePackageNative` on Darwin — and is deliberately absent from `commonCargoArgs`. As a result native `packages.sce`/`packages.default` and the `cli-tests`/`cli-clippy`/`cli-fmt` check derivations carry no commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` reports the real commit. `cli/build.rs` `emit_git_commit` emits the `rustc-env` value only when `SCE_GIT_COMMIT` is explicitly set (with `rerun-if-env-changed=SCE_GIT_COMMIT` as its sole rerun trigger) — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` watches — and `cli/src/services/version/mod.rs` resolves the commit through `option_env!("SCE_GIT_COMMIT")` with an `"unknown"` fallback. On Darwin the release derivation therefore diverges from `.#sce` (shared deps `cargoArtifacts`, but distinct final crate carrying the commit). - `flake.nix` exposes `packages..ci-checks` (`ciChecks`) as the explicit long-running validation tier so the expensive work lives behind `nix build .#ci-checks` and never folds into `nix flake check`. It is a `runCommand` aggregate that symlinks its primary member `sceReleasePackage` into `$out/sce-release` (forcing the static-musl release build on Linux, native on Darwin) and, on Linux only, symlinks `releasePortabilityAuditCheck` into `$out/release-portability-audit`. That Linux-only `releasePortabilityAuditCheck` derivation runs `nix/release/native-portability-audit.sh --platform linux --binary ${sceReleasePackage}/bin/sce` (with `binutils`+`coreutils` on PATH) so `nix build .#ci-checks` fails when the real release binary carries forbidden `/nix/store/` references. This is distinct from `checks..native-portability-audit` (`nativePortabilityAuditCheck`), which remains a fixture-based unit test of the audit script on both platforms. CI wiring to `.#ci-checks` is owned by the separate `release-validation` matrix job in `.github/workflows/pr-ci.yml`, which builds `nix build .#ci-checks` on every PR/`main`/tag commit. - Flatpak flake tooling is Linux-only and reduced to a minimal app surface: `apps.sce-flatpak` is the umbrella entrypoint (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest --repo-root `, etc.) that delegates to `packaging/flatpak/sce-flatpak.sh`; `apps.release-flatpak-package` emits deterministic Flatpak GitHub Release source-manifest assets; `apps.release-flatpak-bundle` builds a source-built `.flatpak` bundle; helper apps `apps.regenerate-flatpak-manifest` and `apps.regenerate-cargo-sources` rewrite the checked-in generated artifacts from their Nix sources. The standalone `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed in favor of `sce-flatpak `. `checks..flatpak-static-validation` runs the Nix-built static validator script during default `nix flake check`, and `checks..flatpak-manifest-parity` plus `checks..cargo-sources-parity` enforce the generated-artifact parity contracts; default `nix flake check` does not run `flatpak-builder`. The Linux dev shell includes `appstreamcli`, `flatpak`, and `flatpak-builder`. @@ -135,7 +135,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - The config-lib check source preserves repo-relative access to shared CLI patch fixtures: Nix copies a filtered repo-shaped source containing `config/lib/**` plus `cli/src/services/structured_patch/fixtures`, then runs Bun/Biome from `config/lib/`. - `flake.nix` exposes the **native** development package as `packages.sce` (`packages.default = packages.sce`) plus `apps.sce` and `apps.default`, all targeting `${packages.sce}/bin/sce`; this keeps repo-local and remote flake run/install flows (`nix run .`, `nix run github:crocoder-dev/shared-context-engineering`, `nix profile install github:crocoder-dev/shared-context-engineering`) aligned to the native CLI output. The static-musl release binary is a distinct output, `packages.sce-release` (`apps.sce-release`); see the native/release split note above and `context/sce/cli-release-artifact-contract.md`. - `biome.json` at the repository root is the canonical Biome configuration for the current JS tooling slice and deliberately scopes coverage to `npm/**` plus the shared `config/lib/**` plugin package root while excluding package-local `node_modules/**`; `flake.nix` exposes Biome through the default dev shell rather than through package-local installs. -- `cli/Cargo.toml` now keeps crates.io publication-ready package metadata for the `shared-context-engineering` crate, and `cli/README.md` is the Cargo install surface for crates.io (`cargo install shared-context-engineering --locked`), git (`cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked`), and local checkout (`cargo install --path cli --locked`) guidance. The published crate installs the `sce` binary. Tokio remains intentionally constrained (`default-features = false`) with current-thread runtime usage plus timer-backed bounded resilience wrappers for retry/timeout behavior. +- `cli/Cargo.toml` keeps crates.io publication-ready package metadata for the `shared-context-engineering` crate, and `cli/README.md` is the Cargo install surface for crates.io (`cargo install shared-context-engineering --locked`) and local checkout (`./scripts/run-cli-cargo.sh install --path cli --locked`) guidance. Direct `cargo install --git` is unsupported because it cannot invoke the repository's pre-Cargo producer. The published crate installs the `sce` binary. Tokio remains intentionally constrained (`default-features = false`) with current-thread runtime usage plus timer-backed bounded resilience wrappers for retry/timeout behavior. - `cli/Cargo.toml` now declares Tokio's `time` feature directly alongside the existing constrained current-thread runtime setup (`rt`, `io-util`, `time`) instead of relying on transitive enablement. ## Build / devShell / CI performance (flake-speedup) diff --git a/context/cli/cli-command-surface.md b/context/cli/cli-command-surface.md index 47a8a142..dc7da026 100644 --- a/context/cli/cli-command-surface.md +++ b/context/cli/cli-command-surface.md @@ -36,7 +36,7 @@ Operator onboarding currently comes from `sce --help`, command-local `--help` ou ## Cargo release and future crates.io posture - `cli/Cargo.toml` includes crates.io-facing package metadata (`description`, `license`, `repository`, `homepage`, `documentation`, `readme`, `keywords`, `categories`) and is aligned to the current crates.io publication posture described by the root release/publish workflows. -- Current local install contract is `cargo install --path cli --locked`. +- Current local install contract is `./scripts/run-cli-cargo.sh install --path cli --locked`; direct `cargo install --git` is unsupported because it cannot run the required repository pre-Cargo producer. - Current build/installability checks run through the root flake against the native package (`nix build .#sce`, `nix run .#sce -- --help`) so the packaged binary and embedded generated assets stay aligned with the canonical Nix-owned build path; the static-musl release archive is built from `.#sce-release` (see `context/sce/cli-release-artifact-contract.md`). - Crates.io publication is now a dedicated downstream publish stage (`.github/workflows/publish-crates.yml`) that validates `.version`/tag/Cargo parity before publishing the checked-in crate version. diff --git a/context/context-map.md b/context/context-map.md index a78331bd..3c1572a5 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -58,13 +58,13 @@ Feature/domain context: - `context/sce/bash-tool-policy-enforcement-contract.md` (approved bash-tool blocking contract plus current Rust evaluator seam and OpenCode/Claude delegation references, including config schema, argv-prefix matching, shell/nix unwrapping, custom-policy `satisfied_by` wrapper exemption, fixed preset catalog/messages, and precedence rules) - `context/sce/bash-policy-satisfied-by-wrapper-exemption.md` (custom-policy `satisfied_by` field: optional list of wrapper argv prefixes that exempt a policy from firing when the matched command was unwrapped from one of them; `NormalizedSegment` wrapper-chain tracking, matching model, examples, and scope) - `context/sce/generated-opencode-plugin-registration.md` (canonical Pkl ownership and ephemeral OpenCode payload layout for `opencode.json`, `sce-bash-policy`, and `sce-agent-trace`, plus the Claude generated settings boundary) -- `context/sce/pi-extension-runtime.md` (project-local Pi extension runtime: `config/lib/pi-plugin/sce-pi-extension.ts` emitted verbatim to `config/.pi/extensions/sce/index.ts`, Pi auto-discovery registration model with no manifest, implemented bash policy adapter delegating to `sce policy bash` with block-by-return `{ block, reason }` and fail-open behavior, implemented `message_end` conversation text capture piping mixed `message`/`message.part` batches (text + reasoning parts, `responseId`-or-random message IDs) to `sce hooks conversation-trace` fail-open, and implemented edit/write diff capture producing `git diff --no-index` unified diffs emitted as synthetic-message `patch` conversation parts plus normalized `sce hooks diff-trace` payloads with `tool_name: "pi"`, nullable `model_id`/`tool_version`, Rust-side `pi_` stored session-ID prefixing, and asset-pipeline shipping — direct Pkl generation into Cargo `OUT_DIR` for repository builds, embedded install via `sce setup --pi`, and `sce doctor` `Pi extensions` health group) +- `context/sce/pi-extension-runtime.md` (project-local Pi extension runtime: `config/lib/pi-plugin/sce-pi-extension.ts` emitted verbatim to `config/.pi/extensions/sce/index.ts`, Pi auto-discovery registration model with no manifest, implemented bash policy adapter delegating to `sce policy bash` with block-by-return `{ block, reason }` and fail-open behavior, implemented `message_end` conversation text capture piping mixed `message`/`message.part` batches (text + reasoning parts, `responseId`-or-random message IDs) to `sce hooks conversation-trace` fail-open, and implemented edit/write diff capture producing `git diff --no-index` unified diffs emitted as synthetic-message `patch` conversation parts plus normalized `sce hooks diff-trace` payloads with `tool_name: "pi"`, nullable `model_id`/`tool_version`, Rust-side `pi_` stored session-ID prefixing, and asset-pipeline shipping through the validated repository generated-input handoff, embedded install via `sce setup --pi`, and `sce doctor` `Pi extensions` health group) - `context/sce/opencode-agent-trace-plugin-runtime.md` (current OpenCode agent-trace plugin runtime behavior, including captured `message.updated` handoff with `summary.diffs` branching: when diffs exist sends one `-patch` mixed batch containing a synthetic parent message plus per-diff `message.part` patch items, when no diffs sends the original `message.updated` payload; in-memory dedup `Set` keyed by `"${sessionID}:${messageID}"`; captured `message.part.updated` handoff to `sce hooks conversation-trace` for `text`/`reasoning` parts with non-empty text plus completed `question` tool parts emitted as `part_type: "question"` with JSON-stringified `{ question, answer }[]`; existing user-message diff extraction for `{ sessionID, diff, time, model_id }`; session-scoped OpenCode client version capture from `session.created`/`session.updated`; and CLI handoff to `sce hooks diff-trace` over STDIN JSON with required `tool_name="opencode"` plus required nullable `tool_version`; Rust hook parsing and AgentTraceDb insertion persist `oc_`-prefixed session IDs plus required payload fields including `model_id`) - `context/sce/cli-first-install-channels-contract.md` (current Nix/Cargo/npm/source-built Flatpak channel contract, release authority and workflow topology, Nix-owned Flatpak manifest/cargo-source generation and validation, reduced Flatpak app surface, and host-git bridge decision) - `context/sce/cli-release-artifact-contract.md` (shared `sce` binary release artifact naming, checksum/manifest outputs, pre-archive staged-binary preparation including macOS `libiconv` install-name sanitization/ad-hoc re-signing, native portability audit app/check for forbidden `/nix/store/` runtime references, GitHub Releases as the canonical artifact publication surface, manual dispatch `prerelease` flag behavior, the current three-target Linux/macOS release workflow topology including pre-upload extracted-archive smoke/audit validation in each native lane, implemented Flatpak source-manifest and source-built `.flatpak` bundle package assets uploaded by `.github/workflows/release-sce.yml`, and Flatpak's explicit source-built non-binary exception) - `context/sce/cli-npm-distribution-contract.md` (implemented `sce` npm launcher package, release-manifest/checksum-verified native binary install flow, the supported darwin/arm64 plus linux x64+arm64 npm platform matrix, the prerequisite that npm-consumed native archives are portable and free of forbidden `/nix/store/` runtime references before upload, and dedicated `.github/workflows/publish-npm.yml` downstream npm publish-stage contract including prerelease publication via npm `next` dist-tag instead of `latest`) -- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io, git, and local checkout install guidance, dedicated crates.io publish workflow with semver prerelease guard, direct repository Pkl-to-`OUT_DIR` generation, and the deterministic checksummed packaging-only fallback used for Pkl-free downstream crate builds) -- `context/sce/flake-build-performance.md` (current native-vs-release package split, release-only commit embedding, slim default/database devShell contract, normal-vs-expensive CI tiers, durable before/after benchmark summary, validation evidence, and remaining cold-build trade-offs) +- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io and wrapper-driven local-checkout install guidance, explicit unsupported `cargo install --git` boundary, dedicated crates.io publish workflow with semver prerelease guard, `scripts/run-cli-cargo.sh` ownership of the validated `SCE_CLI_GENERATED_INPUT_DIR` repository-build handoff, and the deterministic checksummed packaging-only fallback used for Pkl-free downstream crate builds) +- `context/sce/flake-build-performance.md` (current native-vs-release package split, release-only commit embedding, deterministic pre-Cargo generated-input derivation shared by native/release/test/Clippy but excluded from dependency/format derivations, slim default/database devShell contract, normal-vs-expensive CI tiers, durable before/after benchmark summary, validation evidence, and remaining cold-build trade-offs) - `context/sce/flatpak-distribution-patterns.md` (source-built Flatpak conventions, including Nix-side ephemeral fallback preparation for the Pkl-free build sandbox, manifest generation, local/release builds, release assets, and host-git bridge) Working areas: @@ -83,7 +83,7 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` - `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (current workflow-oriented target matrix and canonical Pkl ownership) -- `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes Cargo `OUT_DIR` generation plus crates.io/Flatpak packaging fallbacks) +- `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes pre-Cargo generation, validated copying into Cargo `OUT_DIR`, and crates.io/Flatpak packaging fallbacks) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) - `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md` (retire the checkout-scoped Agent Trace DB surface; `RepositoryAgentTraceDb` is the sole adapter, no `sce trace --legacy`, no global/checkout fallback path; pre-migration on-disk files are never touched and no longer inspectable via the CLI) diff --git a/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md b/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md index 92c0a672..b22ac992 100644 --- a/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md +++ b/context/decisions/2026-07-27-ephemeral-pkl-build-generation.md @@ -8,7 +8,7 @@ Plan: `context/plans/generate-cli-assets-in-cargo-out-dir.md` - Keep `config/pkl/` and referenced `config/lib/` files as the canonical authoring sources. - Do not commit generated `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, or `cli/assets/generated` outputs. -- Repository and Nix/Crane Cargo builds evaluate `config/pkl/generate.pkl` directly into Cargo `OUT_DIR`; `cli/build.rs` stages non-Pkl hooks, schemas, and migrations there and production Rust embeds only from `OUT_DIR`. +- Repository and Nix/Crane builds evaluate `config/pkl/generate.pkl` at a pre-Cargo boundary, inventory the generated payload and canonical inputs, and pass the resulting directory through `SCE_CLI_GENERATED_INPUT_DIR`. `cli/build.rs` validates and copies that payload into Cargo `OUT_DIR`, stages non-Pkl hooks, schemas, and migrations there, and never invokes Pkl; production Rust embeds only from `OUT_DIR`. - `nix run .#pkl-check-generated` validates metadata coverage, required outputs, forbidden repository paths, and deterministic two-pass temporary inventories rather than comparing committed snapshots. - Published crates and source-built Flatpak packages may carry a checksummed packaging-only fallback generated from canonical Pkl in a temporary clean workspace. Downstream Pkl-free builds validate and copy that payload into their own `OUT_DIR`. @@ -19,7 +19,7 @@ Committed target trees duplicated canonical Pkl ownership, made source filters a ## Consequences - Generated path names remain stable payload-relative install layouts, but they appear only under temporary generation roots, Cargo `OUT_DIR`, crate/Flatpak staging directories, and final `sce setup` destinations. -- Crane source filters include canonical Pkl, referenced plugin/extension sources, and static inputs; Pkl is a native build input for repository package/test/clippy derivations. +- Pre-Cargo generation inputs include canonical Pkl and referenced plugin/extension sources; Cargo compilation consumes only the validated generated-input handoff plus its static source inputs, keeping Pkl outside build-script execution. - Flatpak helpers prepare `cli-package-fallback/` before entering the sandbox, and manifests copy it to `cli/package-fallback` as a `type: dir` source. - Contributor workflows inspect temporary output and must not run Pkl generation with repository root as the output directory. diff --git a/context/glossary.md b/context/glossary.md index 7bfa1ace..dbcdc173 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -7,6 +7,7 @@ - important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. +- `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, and `/validate` this way and has no generated agent-role prompts. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. @@ -21,8 +22,8 @@ - `config-lib repo-shaped test source`: Root-flake source-layout contract where `config-lib-bun-tests`, `config-lib-biome-check`, and `config-lib-biome-format` run from `config/lib/` while their copied Nix source preserves repo-relative shared fixtures, currently `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden tests (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). - `config-lib shared package root`: Shared Bun/TypeScript package root at `config/lib/` for repository-owned OpenCode plugin support code. It owns `package.json`, `bun.lock`, and `tsconfig.json`, pins `@opencode-ai/plugin` to `1.15.4`, includes both `agent-trace-plugin/**/*.ts` and `bash-policy-plugin/**/*.ts` in strict TypeScript coverage, and excludes package-local `node_modules/` from both TypeScript and root Biome coverage. - `cli rust overlay toolchain`: Toolchain contract in root `flake.nix` that applies `rust-overlay.overlays.default`, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, uses that toolchain across both Crane package and check derivations, and keeps toolchain selection explicit rather than inheriting nixpkgs defaults. -- `cli Crane package pipeline`: Root-flake packaging path where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage` against a filtered repo source containing the Cargo tree, canonical Pkl/referenced plugin inputs, and static build inputs; Pkl runs in `cli/build.rs` and embeds only from Cargo `OUT_DIR`. -- `cli Crane check pipeline`: Current root-flake check path in `flake.nix` where `cli-tests`, `cli-clippy`, and `cli-fmt` run through `craneLib.cargoTest`, `craneLib.cargoClippy`, and `craneLib.cargoFmt`; test and clippy derivations reuse the shared `cargoArtifacts` dependency cache from the package pipeline. +- `cli Crane package pipeline`: Root-flake packaging path where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage`. One deterministic `cliGeneratedInput` derivation evaluates canonical Pkl twice and inventories its payload and inputs; native and release compiling derivations consume the same validated `SCE_CLI_GENERATED_INPUT_DIR` store path and embed only from Cargo `OUT_DIR`. Pkl is unavailable inside Cargo derivations, and host/musl dependency-only artifacts omit the handoff so generated-input changes do not rebuild dependencies. +- `cli Crane check pipeline`: Current root-flake check path in `flake.nix` where `cli-tests`, `cli-clippy`, and `cli-fmt` run through `craneLib.cargoTest`, `craneLib.cargoClippy`, and `craneLib.cargoFmt`; test and Clippy receive the shared generated-input handoff and reuse `cargoArtifacts`, while format receives neither because it does not compile the CLI. `cli-generated-input` separately verifies required target roots plus payload and canonical-input inventories. - `repo-root .version contract`: Repository packaging/version-source contract where `.version` stores the canonical semver string for flake-evaluated CLI package/check metadata and the approved release version authority for GitHub Releases, Cargo publication, and npm publication; `flake.nix` trims and reuses that value instead of hardcoding a version literal, and staged generated-config workflows must mirror it when Pkl renderers read the same path. - `Flatpak source-manifest GitHub Release asset`: Non-binary release asset set for source-built `dev.crocoder.sce`: the manifest tarball, checksum, and JSON metadata emitted by `nix run .#release-flatpak-package`. The tarball contains manifest/support files plus an ephemeral checksummed `cli-package-fallback/`; Flatpak copies that directory to `cli/package-fallback` before its offline Cargo source build, so no Pkl executable or prebuilt `sce` binary is bundled. - `Flatpak bundle GitHub Release asset`: Implemented source-built `.flatpak` bundle release asset set for the `dev.crocoder.sce` Flatpak channel: `sce-v-x86_64.flatpak`, `sce-v-aarch64.flatpak`, plus per-architecture `.sha256` and `.json` metadata, built from source inside Flatpak using `flatpak-builder` + `flatpak build-bundle`. The bundle is a source-built Flatpak app for direct install (`flatpak install --user `), not a prebuilt binary or Flathub submission. These assets coexist with the existing Flatpak source-manifest packaging metadata on GitHub Releases. The `release-bundle` command is implemented in `packaging/flatpak/sce-flatpak.sh` and the GitHub workflow upload is implemented in `.github/workflows/release-sce-linux.yml` / `release-sce-linux-arm.yml` (x86_64/aarch64), assembled by `release-sce.yml`. @@ -33,7 +34,7 @@ - `cli flake runnable app`: Root-flake app outputs where `apps.sce` and `apps.default` execute the native `${scePackage}/bin/sce` (dev ergonomics), supporting explicit `nix run .#sce -- ...` and default-app flows such as `nix run . -- ...` / `nix run github:crocoder-dev/shared-context-engineering -- ...`; `apps.sce-release` executes the release `${sceReleasePackage}/bin/sce` for explicit `nix run .#sce-release -- ...`. - `slimmed default dev shell`: `devShells..default` (`nix develop`) no longer includes `scePackage` or `tursoPackage`, so entering it compiles neither the CLI package nor the Turso CLI — it provides only the Rust toolchain plus JS/pkl tooling for `cargo`/`biome`/`pkl` work. Turso stays available as `packages..turso` and via the opt-in `database dev shell`. The shared package list + shellHook are factored into `defaultDevShellPackages`/`defaultDevShellHook` `let` bindings so the two shells cannot drift. - `database dev shell`: Opt-in `devShells..database` entered via `nix develop .#database`; layers `tursoPackage` (plus a `turso` version echo) on top of `defaultDevShellPackages`/`defaultDevShellHook`, providing the Turso CLI without adding it to the default shell. -- `cli cargo install contract`: Supported Cargo install surface for the published `shared-context-engineering` crate, which installs the `sce` binary: crates.io (`cargo install shared-context-engineering --locked`), git (`cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked`), and local checkout (`cargo install --path cli --locked`). +- `cli cargo install contract`: Supported Cargo install surface for the `shared-context-engineering` crate, which installs the `sce` binary: crates.io (`cargo install shared-context-engineering --locked`) and local checkout (`./scripts/run-cli-cargo.sh install --path cli --locked`). Direct `cargo install --git` is unsupported because it has no repository pre-Cargo generation boundary. - `cli crates.io publication posture`: Current Cargo package posture in `cli/Cargo.toml` where crates.io-facing metadata is publication-ready for the `shared-context-engineering` crate, with crate-facing install guidance owned by `cli/README.md`. - `Nix performance recommendations`: Repo-local operator guidance in `AGENTS.md` covering optional user-level `~/.config/nix/nix.conf` tuning (`max-jobs = auto`, `cores = 0`) and the explicit root/admin-only boundary for `/etc/nix/nix.conf` `auto-optimise-store = true`. - `sce` (CLI foundation): Rust binary crate at `cli/` with implemented auth command flows (`auth login|renew|logout|status`) plus auth-local bare-command guidance (`sce auth`, `sce auth --help`), implemented setup installation flow including lifecycle-aggregated local DB and Agent Trace DB bootstrap, implemented attribution-only `hooks` subcommand routing/validation entrypoints, and no user-invocable `sync` command yet (`sce sync` wiring is deferred to `0.4.0`). diff --git a/context/overview.md b/context/overview.md index 38ba5ad6..a9f0c560 100644 --- a/context/overview.md +++ b/context/overview.md @@ -1,6 +1,6 @@ # Overview -This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. Generated target layouts are ephemeral: repository and Nix Cargo builds evaluate Pkl into Cargo `OUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` validates exact metadata coverage plus repeatable temporary inventories, and `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. +This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. Generated target layouts are ephemeral: repository builds consume a pre-Cargo generated payload through `SCE_CLI_GENERATED_INPUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` validates exact metadata coverage plus repeatable temporary inventories, and `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. It also includes a Rust CLI (`sce`) for Shared Context Engineering workflows: auth, config inspection, setup, doctor, agent-trace hooks, bash-policy evaluation, and trace database inspection. See `context/architecture.md` for module-level boundaries and `context/context-map.md` for the full domain file index. @@ -24,7 +24,7 @@ The CLI now also enforces a shared output-format parser contract in `cli/src/ser Agent Trace lifecycle setup now resolves repository storage, creates/reuses checkout identity for diagnostics, and initializes `/sce/repos//agent-trace.db` via `RepositoryAgentTraceDb`; hook runtime lazy initialization uses the same repository storage resolver when setup has not prepared the DB or schema metadata is incomplete. The CLI now also includes a shared text styling service in `cli/src/services/style.rs` that provides deterministic color enablement via `owo-colors`, automatic TTY detection, and `NO_COLOR` compliance for human-facing text output; stdout help/text surfaces, stderr diagnostics, and interactive prompt-adjacent text now reuse that shared styling policy while JSON, completion, and other non-interactive/machine-readable flows remain unstyled. The service exports color-detection, conditional styling, help/diagnostic/label/prompt styling, and `banner_with_gradient()` helpers for use across command surfaces while preserving pipe-safe output for non-interactive environments. The `setup` command includes an `inquire`-backed target-selection flow: default interactive selection for OpenCode/Claude/Pi/All with required-hook installation in the same run, explicit non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`), deterministic mutually-exclusive validation, and non-destructive cancellation exits; the former `--both` flag was removed in favor of `--all` (opencode+claude+pi). -For repository Cargo builds, `cli/build.rs` evaluates the canonical `config/pkl/generate.pkl` model directly into Cargo `OUT_DIR/pkl-generated`, stages hook templates, the Agent Trace schema, and SQL migrations under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`. `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths, embedded bytes, and target-scoped iteration without runtime reads from `config/`; production setup, policy, config-schema, Agent Trace, and migration includes all resolve through `OUT_DIR`. Published crates instead carry an ignored, packaging-only fallback generated deterministically from the same canonical inputs before `cargo package`; unpacked downstream builds validate and copy that payload into their own `OUT_DIR` without requiring Pkl or parent repository paths. +For repository Cargo builds, `scripts/run-cli-cargo.sh` evaluates the canonical `config/pkl/generate.pkl` model twice into a fresh temporary generated-input directory, rejects nondeterminism, and records SHA-256 inventories for both the payload and canonical generator inputs before invoking the requested Cargo workflow with `SCE_CLI_GENERATED_INPUT_DIR`. The wrapper cleans up after Cargo success, failure, or handled signals. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, copies the validated payload into Cargo `OUT_DIR/pkl-generated`, stages hook templates, the Agent Trace schema, and SQL migrations under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`; it never invokes Pkl. `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths, embedded bytes, and target-scoped iteration without runtime reads from `config/`; production setup, policy, config-schema, Agent Trace, and migration includes all resolve through `OUT_DIR`. Published crates instead carry an ignored, packaging-only fallback generated deterministically from the same canonical inputs before `cargo package`; unpacked downstream builds validate and copy that payload into their own `OUT_DIR` without requiring Pkl or parent repository paths. The setup service also provides repository-root install orchestration: it resolves the repository root, derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup uses a unified remove-and-replace policy for all write flows — it removes existing targets before swapping staged content and returns deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs` now separates install-flow logic from interactive prompt logic through focused support seams. The CLI now also applies baseline security hardening for reliability-driven automation: diagnostics/logging paths use deterministic secret redaction, `sce setup --hooks --repo ` canonicalizes and validates repository paths before execution, and setup write flows run explicit directory write-permission probes before staging/swap operations. The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_file`, `log_file_mode`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config_root}/sce/config.json` then `.sce/config.json` with local override, where `config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_file_mode=truncate`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by` wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as `nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json` JSON Schema generated beneath Cargo `OUT_DIR` and embedded by `cli/src/services/config/mod.rs` for both `sce config validate` and doctor-time config checks. Runtime startup config loading now keeps parity with that schema by accepting the canonical `"$schema": "https://sce.crocoder.dev/config.json"` declaration in repo-local and global config files, so startup commands such as `sce version` no longer fail before dispatch on that field. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for file logging; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/data/bash-policy-presets.json` and `context/sce/bash-tool-policy-enforcement-contract.md`. @@ -37,12 +37,12 @@ The config service split now includes `cli/src/services/config/resolver.rs` as t Generated config now includes repo-local OpenCode plugin assets: `sce-bash-policy.ts` plus `sce-agent-trace.ts` are emitted under `config/.opencode/plugins/`; the OpenCode agent-trace plugin extracts `{ sessionID, diff, time, model_id }` from user `message.updated` events with diffs, tracks per-session OpenCode client version from `session.created`/`session.updated`, and sends payloads to `sce hooks diff-trace` with `tool_name="opencode"` plus optional `tool_version`. Claude generated config now routes supported `PostToolUse Write|Edit|MultiEdit|NotebookEdit` events directly to `sce hooks diff-trace`; it no longer registers a `SessionStart` hook or calls `sce hooks session-model`. Rust handles extraction, validation, and persistence without a TypeScript intermediary; the former `config/.claude/plugins/sce-agent-trace.ts` Bun runtime was removed in T07 of the `claude-rust-diff-trace` plan. The Rust hook validates required fields, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and persists tool-prefixed `session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), `model_id`, `tool_name`, and nullable `tool_version` into `diff_traces` through AgentTraceDb. Bash-policy now delegates OpenCode enforcement to the Rust `sce policy bash` command: the generated OpenCode plugin at `config/.opencode/plugins/sce-bash-policy.ts` is a thin wrapper that calls `sce policy bash --input normalized --output json` via `spawnSync` and throws on deny decisions; it no longer contains independent TypeScript policy logic. The former `bash-policy/runtime.ts` TypeScript runtime has been removed. Preset... Claude bash-policy enforcement is also generated through `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`, so Claude and OpenCode both delegate to the Rust policy evaluator without a Claude TypeScript runtime. Pi bash-policy enforcement is delegated the same way through a project-local Pi extension (`config/lib/pi-plugin/sce-pi-extension.ts`, emitted to `config/.pi/extensions/sce/index.ts`) whose `tool_call` handler blocks denied bash commands via `sce policy bash` and fails open when the policy check cannot run (see `context/sce/pi-extension-runtime.md`). Local database bootstrap is now owned by `LocalDbLifecycle::setup` and `AgentTraceDbLifecycle::setup` aggregated by the setup command. Agent Trace setup creates/reuses the current checkout ID for diagnostics and initializes the repository-scoped `/sce/repos//agent-trace.db` with the repository schema; hook runtime lazily creates or upgrades that repository DB when setup has not run or schema metadata is incomplete. Doctor validates the repository-scoped DB path/health and can bootstrap missing parent directories; outside a Git repository it reports an actionable "requires a Git repository" diagnostic instead of probing a sentinel path. The `sce trace` group operates only on repository-scoped DBs for list/status/status-all/shell UX; the checkout-scoped `--legacy` surface was removed by the `retire-legacy-agent-trace-db` plan (see `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md`). Wiring a user-invocable `sce sync` command is deferred to `0.4.0`. -The repository-root flake (`flake.nix`) applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, and builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline whose filtered source contains the Cargo tree, canonical Pkl/plugin inputs, and required static assets. Crane package/test/clippy builds include Pkl and exercise direct generation into Cargo `OUT_DIR`; `cli-tests`, `cli-clippy`, and `cli-fmt` remain Crane-backed check derivations. +The repository-root flake (`flake.nix`) applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, and builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline. One deterministic pre-Cargo Nix derivation evaluates the canonical Pkl/plugin inputs twice, inventories the payload and inputs, and supplies the same validated `SCE_CLI_GENERATED_INPUT_DIR` store path to native, release, test, and Clippy Cargo derivations. Pkl is absent from those Cargo environments; dependency-only and format derivations do not receive the handoff, so canonical generation changes invalidate compiling outputs without invalidating dependency artifacts or formatting. `cli-tests`, `cli-clippy`, and `cli-fmt` remain Crane-backed check derivations. The root flake splits native and release outputs: `packages.sce` and `packages.default` build the **native** development binary (`scePackage`), while `packages.sce-release` builds the release binary (`sceReleasePackage`: static musl on Linux, native on Darwin). So `nix build .#sce` / `.#default`, `nix run . -- --help`, `nix run .#sce -- --help`, and `nix profile install github:crocoder-dev/shared-context-engineering` target the native binary, and `nix build .#sce-release` / `nix run .#sce-release -- ...` (plus `nix run .#release-artifacts`, which builds `.#sce-release`) target the release binary. On Linux the native and release outputs are distinct store paths, and the release output passes the native portability audit. `packages..ci-checks` is the explicit long-running validation tier: `nix build .#ci-checks` builds the `.#sce-release` package and, on Linux, audits the real release binary for forbidden `/nix/store/` references, so the expensive work stays out of `nix flake check` (which never builds `.#sce-release`). Git-commit embedding is **release-only**: `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment applied only to the release derivations (`scePackageMusl` on Linux, `sceReleasePackageNative` on Darwin), not to `commonCargoArgs`. So native `.#sce`/`.#default` and every `nix flake check` derivation (`cli-tests`, `cli-clippy`, `cli-fmt`) build without the commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` still reports the real commit via `sce version`. `cli/build.rs` `emit_git_commit` emits `SCE_GIT_COMMIT` only when the env var is explicitly set — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` rerun watches. On Darwin the release now uses a distinct native-toolchain derivation (native toolchain + commit), so it diverges from `.#sce` to carry the commit while native stays commit-independent. The default development shell is slimmed for fast iteration: `devShells.default` no longer includes `scePackage` or `tursoPackage`, so `nix develop` compiles neither the CLI package nor the Turso CLI — it provides only the Rust toolchain and JS/pkl tooling for `cargo`/`biome`/`pkl` work. Turso stays available as `packages..turso` and through a new opt-in `devShells..database` shell (default tools + `tursoPackage`), entered via `nix develop .#database`. Both shells share `defaultDevShellPackages`/`defaultDevShellHook` `let` bindings so they cannot drift. -The CLI Cargo package metadata now includes crates.io publication-ready fields with crate-local install guidance in `cli/README.md`; supported Cargo install paths are `cargo install shared-context-engineering --locked`, `cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked`, and local `cargo install --path cli --locked`. The published crate installs the `sce` binary. The crate also keeps `cargo clippy --manifest-path cli/Cargo.toml` warnings-denied through `cli/Cargo.toml` lint configuration, so an extra `-- -D warnings` flag is redundant. -The repository-root flake is the single Nix entrypoint for repo tooling and CLI packaging/checks, so root-level `nix flake check` evaluates the Crane-backed CLI checks (`cli-tests`, `cli-clippy`, `cli-fmt`), the ephemeral `pkl-generated` inventory check, Linux-only Flatpak checks, `workflow-actionlint`, and the split npm/config-lib JavaScript checks without nested-flake indirection. Ordinary repository and Crane Cargo builds generate canonical Pkl outputs directly into Cargo `OUT_DIR`; crates.io packaging prepares a self-contained Pkl-free fallback in a temporary clean workspace, and Flatpak helpers prepare the same payload beside generated manifests before the sandboxed source build. No general-purpose `cli/assets/generated/` mirror or committed generated target tree remains. +The CLI Cargo package metadata now includes crates.io publication-ready fields with crate-local install guidance in `cli/README.md`; supported Cargo install paths are `cargo install shared-context-engineering --locked` and local checkout installation through `./scripts/run-cli-cargo.sh install --path cli --locked`. Direct `cargo install --git` is unsupported because it cannot run the repository pre-Cargo producer. The published crate installs the `sce` binary. The crate also keeps `cargo clippy --manifest-path cli/Cargo.toml` warnings-denied through `cli/Cargo.toml` lint configuration, so an extra `-- -D warnings` flag is redundant. +The repository-root flake is the single Nix entrypoint for repo tooling and CLI packaging/checks, so root-level `nix flake check` evaluates the Crane-backed CLI checks (`cli-tests`, `cli-clippy`, `cli-fmt`), the ephemeral `pkl-generated` inventory check, Linux-only Flatpak checks, `workflow-actionlint`, and the split npm/config-lib JavaScript checks without nested-flake indirection. Repository Cargo builds copy a validated pre-Cargo generated payload into Cargo `OUT_DIR`; crates.io packaging prepares a self-contained Pkl-free fallback in a temporary clean workspace, and Flatpak helpers prepare the same payload beside generated manifests before the sandboxed source build. No general-purpose `cli/assets/generated/` mirror or committed generated target tree remains. Config-lib JS flake checks execute from `config/lib/`, but the copied Nix check source is repo-shaped when tests require shared repo fixtures; the current Claude agent-trace golden tests are fully Rust-owned in `cli/src/services/structured_patch/fixtures` (Claude TypeScript plugin test removed in T07). Local developer Nix tuning guidance now lives in `AGENTS.md`, including optional user-level `~/.config/nix/nix.conf` recommendations for `max-jobs` and `cores` plus an explicit system-level-only note for `auto-optimise-store`. The Pkl authoring layer owns generated OpenCode plugin registration for SCE-managed plugins: `config/pkl/base/opencode.pkl` defines the canonical plugin entries, `config/pkl/renderers/common.pkl` re-exports the shared plugin list for renderer use, and generated `config/.opencode/opencode.json` registers `./plugins/sce-bash-policy.ts` and `./plugins/sce-agent-trace.ts` through OpenCode's `plugin` field. Claude does not use an OpenCode-style plugin manifest; Claude bash-policy enforcement is registered through generated `.claude/settings.json` as a `PreToolUse` `Bash` command hook routed through `.claude/hooks/run-sce-or-show-install-guidance.sh` before running `sce policy bash`. diff --git a/context/patterns.md b/context/patterns.md index 35c826ad..eb7f74c9 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -113,7 +113,7 @@ - For interactive setup flows, isolate prompt handling behind a service-layer prompter seam so selection mapping and cancellation behavior can be tested without a live TTY. - When setup or path-catalog modules grow dense, extract focused internal support seams (for example install-flow, prompt-flow, or root-resolution helpers) before adding new behavior so orchestration files stay navigable without changing command contracts. - Treat setup prompt cancellation/interrupt as a non-destructive exit path with explicit user messaging (no file mutations and no partial side effects). -- For repository setup-asset build prep, have `cli/build.rs` evaluate `config/pkl/generate.pkl` directly into Cargo `OUT_DIR`, normalize embedded relative paths to forward slashes, stage non-Pkl hook/schema inputs under `OUT_DIR/static`, and generate the setup manifest in `OUT_DIR`; production Rust includes must not point back into `config/`, `cli/assets/`, or another source-tree generated mirror. +- For repository setup-asset build prep, route build, run, targeted-test, Clippy, and local-install Cargo workflows through `scripts/run-cli-cargo.sh`. The wrapper evaluates `config/pkl/generate.pkl` twice before Cargo into a fresh temporary generated-input directory, rejects nondeterminism, records exact `SHA256SUMS` and canonical-input `INPUTS.SHA256SUMS` inventories, passes it through `SCE_CLI_GENERATED_INPUT_DIR`, and cleans up after Cargo exits. Keep `cli/build.rs` free of Pkl subprocesses: it validates the handoff, copies it into Cargo `OUT_DIR/pkl-generated`, stages non-Pkl hook/schema inputs under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; production Rust includes must not point back into `config/`, `cli/assets/`, or another source-tree generated mirror. - For CLI database migration prep, keep SQL files under immediate `cli/migrations//` directories named `NNN_description.sql`; `cli/build.rs` stages those files under `OUT_DIR/static/migrations`, sorts by the numeric prefix before `_`, and writes deterministic `OUT_DIR/generated_migrations.rs` constants with `include_str!` references for service `DbSpec` consumers. - For setup install execution, write selected embedded assets into a per-target staging directory first, then remove the existing target and swap staged content into place; on swap failure, clean temporary staging paths and return deterministic recovery guidance (recover from version control). No backup artifacts are created. - For required-hook setup execution, resolve repository root and effective hooks directory from git (`rev-parse --show-toplevel`, `rev-parse --git-path hooks`), then apply deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`) with staged writes, executable-bit enforcement, and remove-and-replace behavior that removes existing hooks before swapping staged content. @@ -147,13 +147,13 @@ - Keep crate-local onboarding docs in `cli/README.md` and sanity-check command examples against actual `sce` output whenever command messaging changes. - Keep Rust verification in flake checks under stable named derivations re-exported by the root flake: `checks..cli-tests`, `checks..cli-clippy`, `checks..cli-fmt`, and `checks..workflow-actionlint`. - Keep cheap flake-check sources as narrow as their behavior allows: formatting checks should not depend on generated payloads, and ephemeral/static checks should copy only the canonical inputs and forbidden paths they inspect. -- Keep Rust package/check sources as narrow as behavior allows: repository builds include the Cargo tree, canonical Pkl and referenced plugin/extension sources, plus static inputs read by `cli/build.rs`; they must not include committed generated target trees. +- Keep Rust package/check sources as narrow as behavior allows: one deterministic pre-Cargo Nix derivation receives canonical Pkl and referenced plugin/extension sources, evaluates twice, inventories the result, and passes one validated generated-input store path to every Crane derivation that compiles the CLI (native, release, test, and Clippy). Keep Pkl out of those Cargo environments, and do not attach the handoff to dependency-only or formatting derivations so generated-input changes preserve dependency caches and formatting independence. Neither boundary may include committed generated target trees. - In `flake.nix`, select the Rust toolchain via an explicit Rust overlay (`rust-overlay`) and thread that toolchain through Crane package/check derivations so CLI builds and checks do not rely on implicit nixpkgs Rust defaults. - For installable CLI surfaces in the root flake, expose an explicit named package plus default alias (`packages.sce` and `packages.default = packages.sce`, the **native** development package) and pair it with a runnable app output (`apps.sce`) that points to the packaged binary path; keep the static-musl release binary a distinct output (`packages.sce-release`) rather than folding it into the default package. - For root-flake CLI release metadata, source the package/check version from repo-root `.version` and trim it at eval time so packaged outputs stay aligned without hardcoded semver strings in `flake.nix`. -- For Cargo CLI distribution, keep crate metadata publication-ready, document the supported Cargo install paths in `cli/README.md` (`cargo install shared-context-engineering --locked`, git install with `--locked`, and local `cargo install --path cli --locked`), and verify at least the repo-local build/check path through the Nix-managed validation baseline. +- For Cargo CLI distribution, keep crate metadata publication-ready and document the supported Cargo install paths in `cli/README.md`: crates.io via `cargo install shared-context-engineering --locked`, and local checkout via `./scripts/run-cli-cargo.sh install --path cli --locked`. Do not advertise direct `cargo install --git`; it cannot run the required pre-Cargo generation boundary. Verify at least the repo-local build/check path through the Nix-managed validation baseline. - Keep Pkl-free fallback payloads packaging-only and Git-ignored: generate them from canonical Pkl in a temporary clean workspace or manifest-support directory, stage all required static inputs, reject nondeterministic generation, and include an exact checksum inventory. Crates.io embeds this payload in the crate; Flatpak stages it as a manifest `type: dir` source before entering the Pkl-free sandbox. -- In `cli/build.rs`, choose direct canonical Pkl generation whenever repository sources exist; use the validated package fallback only when those sources are absent, copy either input mode into the same `OUT_DIR` shape, and fail actionably rather than silently switching modes after a direct-generation error. +- In `cli/build.rs`, require and validate `SCE_CLI_GENERATED_INPUT_DIR` whenever repository canonical sources exist; use the validated package fallback only when those sources are absent, copy either input mode into the same `OUT_DIR` shape, and fail actionably rather than silently switching repository builds to the package fallback. - Anchor Cargo `package.include` patterns at the crate root so similarly named files in obsolete source trees cannot enter the `.crate`; inspect `cargo package --list` and build the unpacked archive with Pkl absent when changing the fallback inventory. ## Unit testing in Nix sandbox diff --git a/context/plans/generate-cli-assets-in-cargo-out-dir.md b/context/plans/generate-cli-assets-in-cargo-out-dir.md index c9ccf913..e654befe 100644 --- a/context/plans/generate-cli-assets-in-cargo-out-dir.md +++ b/context/plans/generate-cli-assets-in-cargo-out-dir.md @@ -2,24 +2,26 @@ ## Change summary -Remove the committed generated target trees at `config/.opencode`, `config/.claude`, and `config/.pi`. Repository builds will evaluate the canonical Pkl model directly into Cargo's ephemeral `OUT_DIR`; `build.rs` will stage the remaining required static inputs there, and Rust will include generated source and static payloads only from `OUT_DIR`. +Remove the committed generated target trees at `config/.opencode`, `config/.claude`, and `config/.pi`. Preserve the completed move to ephemeral assets, then move Pkl evaluation out of `cli/build.rs`: a pre-Cargo producer will generate the canonical payload in a separate temporary directory, identify that directory through an explicit handoff, and `build.rs` will validate and copy it into Cargo's invocation-specific `OUT_DIR`. Rust will continue to include generated source and static payloads only from `OUT_DIR`. -Generated target files will no longer be repository artifacts or parity snapshots. Published crates remain self-contained through a packaging-only payload generated from Pkl in a temporary clean workspace before `cargo package`/`cargo publish`; downstream builds copy that packaged payload into their own `OUT_DIR` and do not require Pkl. +This follow-up keeps Pkl out of Cargo build-script sandboxes while retaining deterministic invalidation and the existing packaging fallback. Generated target files remain absent from the repository; published crates remain self-contained through a packaging-only payload generated from Pkl in a temporary clean workspace before `cargo package`/`cargo publish`; downstream builds copy that packaged payload into their own `OUT_DIR` and do not require Pkl. ## Acceptance criteria How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. -- [ ] AC1: `config/.opencode`, `config/.claude`, and `config/.pi` are absent from the repository, and generated workflow, skill, entry-point, plugin, settings, extension, and config-schema outputs exist only in temporary generation/build/package locations. +- [x] AC1: `config/.opencode`, `config/.claude`, and `config/.pi` are absent from the repository, and generated workflow, skill, entry-point, plugin, settings, extension, and config-schema outputs exist only in temporary generation/build/package locations. - Validate: `test ! -e config/.opencode && test ! -e config/.claude && test ! -e config/.pi`; run the generation check and inspect `git status --short` to confirm it does not recreate them. -- [ ] AC2: A repository CLI build runs the canonical Pkl generator into Cargo `OUT_DIR`, stages required non-Pkl inputs there, and writes no generated Rust or static files into `cli/src/`, `cli/assets/`, or `config/`. - - Validate: `nix develop -c sh -c 'cd cli && cargo clean && cargo build'`; inspect `cli/target/debug/build/shared-context-engineering-*/out/` and run `git status --short cli/src cli/assets config`. -- [ ] AC3: The built CLI embeds the deterministic OpenCode, Claude, Pi, hook, policy, schema, and migration payloads expected by setup and runtime consumers. +- [x] AC2: A supported repository CLI build generates the canonical Pkl payload before Cargo in a separate temporary location; `cli/build.rs` invokes no Pkl subprocess, validates and copies the handed-off payload plus required non-Pkl inputs into Cargo `OUT_DIR`, and writes no generated Rust or static files into `cli/src/`, `cli/assets/`, or `config/`. + - Validate: run the documented repository Cargo build entrypoint after `cargo clean`; inspect `cli/target/debug/build/shared-context-engineering-*/out/`, assert that `cli/build.rs` has no Pkl process invocation, and run `git status --short cli/src cli/assets config`. +- [x] AC3: The built CLI embeds the deterministic OpenCode, Claude, Pi, hook, policy, schema, and migration payloads expected by setup and runtime consumers. - Validate: `nix develop -c sh -c 'cd cli && cargo test setup && cargo test config && cargo test agent_trace && cargo test auth_db'` and the ephemeral Pkl inventory check. -- [ ] AC4: A staged crates.io package embeds a packaging-only Pkl-generated payload, and the unpacked crate builds without Pkl, the repository-level Pkl sources, or parent-directory `config/` paths. +- [x] AC4: A staged crates.io package embeds a packaging-only Pkl-generated payload, and the unpacked crate builds without Pkl, the repository-level Pkl sources, or parent-directory `config/` paths. - Validate: prepare a temporary clean repository copy, run the package-preparation and `cargo package` flow, inspect `cargo package --list`, unpack the `.crate`, remove Pkl from `PATH`, and build it with Cargo. -- [ ] AC5: Nix package/check builds and Flatpak source builds consume direct `OUT_DIR` generation or an explicitly prepared ephemeral fallback without relying on committed generated target trees. - - Validate: `nix flake check`; on Linux, `nix run .#sce-flatpak -- validate`; inspect Nix, Flatpak, and release definitions for references to removed `config/.opencode`, `config/.claude`, or `config/.pi` trees. +- [x] AC5: Nix package/check builds generate Pkl payloads before entering Cargo build-script execution and hand them to `build.rs` for copying into `OUT_DIR`; Flatpak source builds retain their explicitly prepared ephemeral fallback; neither path relies on committed generated target trees. + - Validate: `nix flake check`; on Linux, `nix run .#sce-flatpak -- validate`; inspect Nix derivations to confirm Pkl runs in the pre-Cargo producer rather than `cli/build.rs`, and inspect Nix, Flatpak, and release definitions for references to removed `config/.opencode`, `config/.claude`, or `config/.pi` trees. +- [x] AC6: Documented non-Nix repository workflows can pre-generate and hand off the payload for `cargo build`, targeted tests, Clippy, and `cargo install --path cli`, with freshness represented in Cargo invalidation inputs and actionable failure when the handoff is absent or invalid. + - Validate: run the documented pre-generation entrypoint with representative `cargo build`, targeted-test, Clippy, and `cargo install --path cli` commands; mutate one canonical Pkl input and confirm the payload is regenerated before Cargo; invoke repository Cargo without a valid handoff and assert the documented diagnostic. ### Full validation @@ -31,14 +33,15 @@ Repository-wide checks `/validate` runs after the last task, regardless of which ### Context sync - Add a decision record superseding the checked-in generated-target ownership portions of `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` while preserving its workflow matrix and canonical Pkl ownership decisions. -- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` to describe ephemeral Pkl generation, removed generated target trees, `OUT_DIR`-only Rust embedding, and the crates.io fallback payload. +- Update `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` to supersede direct build-script Pkl evaluation with pre-Cargo generation and a validated build-script copy boundary motivated by sandboxing. +- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` to describe pre-Cargo ephemeral Pkl generation, removed generated target trees, `OUT_DIR`-only Rust embedding, and the crates.io fallback payload. - Update `context/sce/generated-opencode-plugin-registration.md`, `context/sce/pi-extension-runtime.md`, `context/sce/shared-turso-db.md`, `context/cli/config-precedence-contract.md`, and `context/sce/cli-cargo-distribution-contract.md` where they currently identify checked-in generated paths or source-tree build artifacts. ## Constraints and non-goals -- **In scope:** canonical Pkl generation output routing; removal of `config/.opencode`, `config/.claude`, and `config/.pi`; ephemeral generation/inventory checks; `cli/build.rs`; Rust compile-time includes for setup assets, policy data, schemas, and migration manifests; Cargo package staging; Nix/Crane inputs; crates.io publishing; Flatpak preparation; focused regression coverage and contributor documentation. -- **Out of scope:** Changing workflow/skill/entry-point content, changing the OpenCode/Claude/Pi target matrix, changing runtime setup destinations, changing database migration SQL, or removing canonical Pkl and `config/lib` authoring sources. -- **Constraints:** Repository/Nix builds generate canonical Pkl outputs directly into Cargo `OUT_DIR`; all Rust compile-time generated source and static-data includes resolve from `OUT_DIR`; no generated target tree is committed; generation stays deterministic and exact-inventory checked; published crates build without Pkl or repository-external paths; normal verification remains Nix-managed. +- **In scope:** canonical Pkl generation output routing; removal of `config/.opencode`, `config/.claude`, and `config/.pi`; pre-Cargo ephemeral generation and handoff; generation/inventory checks; `cli/build.rs`; Rust compile-time includes for setup assets, policy data, schemas, and migration manifests; Cargo package staging; Nix/Crane inputs; non-Nix repository Cargo workflows; crates.io publishing; Flatpak preparation; focused regression coverage and contributor documentation. +- **Out of scope:** `cargo install --git` support; changing workflow/skill/entry-point content; changing the OpenCode/Claude/Pi target matrix; changing runtime setup destinations; changing database migration SQL; or removing canonical Pkl and `config/lib` authoring sources. +- **Constraints:** Repository/Nix builds generate canonical Pkl outputs before Cargo in a separate ephemeral directory and `build.rs` copies validated inputs into Cargo `OUT_DIR`; `build.rs` must not invoke Pkl; all Rust compile-time generated source and static-data includes resolve from `OUT_DIR`; no generated target tree is committed; generation stays deterministic and exact-inventory checked; published crates build without Pkl or repository-external paths; normal verification remains Nix-managed. - **Non-goal:** Bundling a Pkl executable/evaluator into the published Rust crate or preserving the removed generated directories as compatibility paths. ## Assumptions @@ -46,6 +49,8 @@ Repository-wide checks `/validate` runs after the last task, regardless of which - The previously approved crates.io exception remains in force: publication may create a temporary Pkl-generated payload inside the staged crate, but that payload is never committed and downstream `build.rs` copies it into the consumer's `OUT_DIR`. - `nix run .#pkl-check-generated` may retain its command name for compatibility while changing from committed-output parity comparison to ephemeral generation, exact-inventory validation, determinism checking, and rejection of the removed target directories. - Non-Pkl inputs required at compile time, such as hook templates, the Agent Trace schema, and SQL migrations, remain canonical source files and are copied by `build.rs` into `OUT_DIR`. +- The pre-Cargo producer may choose its own temporary output directory; an explicit environment-variable handoff is the smallest established Cargo-compatible mechanism for telling `build.rs` what to validate and copy. +- Direct `cargo install --git` is intentionally unsupported because a git checkout has no guaranteed pre-generation step; supported source installs use `cargo install --path cli` after the repository pre-generation entrypoint. ## Task stack @@ -79,6 +84,85 @@ Repository-wide checks `/validate` runs after the last task, regardless of which - Implementation evidence: Removed the committed OpenCode, Claude, Pi, generated SCE schema, and legacy `cli/assets/generated` outputs; replaced parity snapshots with two-pass ephemeral SHA-256 inventory validation; routed Crane source builds through canonical Pkl inputs and `OUT_DIR`; removed obsolete source-tree asset path helpers; and changed Flatpak manifests/helpers to stage a temporary packaging fallback before entering the Pkl-free Flatpak build sandbox. - Verification evidence: Two consecutive `nix run .#pkl-check-generated` runs reported the same 73-file inventory digest (`605e7d406bd56047f76b8eecff3f53e4226e208133166225c34d868de032faae`); legacy-path and diff checks passed; `nix run .#regenerate-flatpak-manifest` and `nix run .#sce-flatpak -- validate` passed; a release Flatpak source package contained the fallback inventory and representative generated payload; and `nix flake check` passed all checks. +- [x] T04: `Copy pre-generated Pkl payloads into OUT_DIR` (status:complete) + - Task ID: T04 + - Goal: Replace repository-mode Pkl subprocess execution in `cli/build.rs` with a validated handoff from an externally generated payload directory while retaining `OUT_DIR` ownership and the packaged-fallback path. + - Boundaries (in/out of scope): In — the generated-input environment contract, build-script validation/copying, Cargo rerun signals for the handed-off inventory and canonical inputs, actionable missing/stale/invalid-input diagnostics, and focused build-script tests. Out — implementing the producer in Nix or repository commands, changing Rust include paths, and changing the packaging fallback format. + - Dependencies: T03 + - Done when: Repository-mode `build.rs` invokes no Pkl process, accepts only a complete deterministic generated-input handoff, copies it into `OUT_DIR/pkl-generated`, preserves static staging and packaged fallback behavior, reruns when the handoff or canonical inputs change, and focused tests cover valid, missing, incomplete, and stale handoffs. + - Verification notes (commands or checks): run the focused build-script/setup tests through `nix develop`; inspect `cli/build.rs` for absence of `Command::new("pkl")`; exercise valid, missing, incomplete, and stale generated-input directories and compare the copied `OUT_DIR` inventory. + - Implementation evidence: `cli/build.rs` now requires `SCE_CLI_GENERATED_INPUT_DIR` for repository builds, validates exact sorted SHA-256 payload and canonical-input inventories, copies the validated `pkl-generated` tree into Cargo `OUT_DIR`, and emits rerun signals for the handoff environment, both inventories, and every canonical generator input; packaged fallback and static staging paths remain unchanged. Focused build-script tests are exposed through `cli/tests/build_script.rs` and cover missing environment/directory, valid copy parity, incomplete payload, and stale canonical inputs. + - Verification evidence: A temporary canonical Pkl handoff was generated outside Cargo with `SHA256SUMS` and `INPUTS.SHA256SUMS`; `nix develop` runs of `cargo test --test build_script` passed 5 tests, `cargo test setup` passed 8 tests, `cargo clippy --test build_script -- -D warnings` passed, and `cargo fmt --check` passed. Source inspection found no Pkl `Command` invocation in `cli/build.rs`, while the valid-copy test asserted identical source and `OUT_DIR/pkl-generated` inventories. + +- [x] T05: `Add a repository pre-Cargo generation entrypoint` (status:complete) + - Task ID: T05 + - Goal: Provide one documented repository command boundary that runs canonical Pkl generation in a temporary directory and invokes a requested Cargo workflow with the generated-input handoff. + - Boundaries (in/out of scope): In — a repository-owned helper or equivalent app, temporary-directory lifecycle, deterministic generation/inventory preparation, environment handoff, support for build, targeted tests, Clippy, and `cargo install --path cli`, failure cleanup, and contributor documentation. Out — `cargo install --git`, package-fallback preparation, and Nix/Crane derivation wiring. + - Dependencies: T04 + - Done when: Contributors outside Nix build sandboxes can use one documented entrypoint for the supported Cargo workflows, each invocation generates before Cargo and passes a validated payload directory, canonical input changes cannot silently reuse stale output, and failures leave no repository-generated tree. + - Verification notes (commands or checks): run the helper with representative `cargo build`, targeted `cargo test`, `cargo clippy --all-targets -- -D warnings`, and `cargo install --path cli` invocations; mutate a temporary canonical input copy to prove regeneration; interrupt or fail Cargo and verify temporary cleanup and a clean `git status --short`. + - Implementation evidence: Added `scripts/run-cli-cargo.sh` as the repository Cargo boundary; each invocation evaluates canonical Pkl twice into a fresh temporary directory, rejects nondeterministic output, writes exact payload and canonical-input SHA-256 inventories, passes the directory only through `SCE_CLI_GENERATED_INPUT_DIR`, forwards Cargo arguments unchanged, preserves failures, and removes the handoff on normal exit or signals. Added a fake-tool behavioral harness covering argument forwarding, fresh regeneration after a canonical-input mutation, inventory validity, Cargo failure propagation, and cleanup; updated contributor and local-checkout documentation to use the wrapper and identify direct `cargo install --git` as unsupported. + - Verification evidence: `bash -n scripts/run-cli-cargo.sh scripts/test-run-cli-cargo.sh` passed; `bash scripts/test-run-cli-cargo.sh` passed, including the temporary canonical-input mutation and exit-42 cleanup case; wrapper-driven Nix-dev-shell `cargo build`, targeted `cargo test setup` (8 passed), and `cargo clippy --all-targets -- -D warnings` all passed; wrapper-driven `cargo install --path cli --locked` installed an executable into a temporary root; `git diff --check`, removed-generated-path assertions, and `git status --short cli/src cli/assets config scripts AGENTS.md cli/README.md` confirmed no generated source tree was left behind. + +- [x] T06: `Pre-generate Pkl payloads for Crane builds` (status:complete) + - Task ID: T06 + - Goal: Move Pkl evaluation for native, release, test, and Clippy derivations into a pre-Cargo Nix boundary and pass the resulting directory to `cli/build.rs` without exposing Pkl inside Cargo build-script execution. + - Boundaries (in/out of scope): In — `flake.nix` source/input partitioning, reusable pre-generated payload derivation or hook, handoff environment, native/release/check derivations, cache/invalidation behavior, and focused Nix assertions. Out — changing dependency-only Cargo artifacts, published-crate fallback generation, Flatpak's existing Pkl-free fallback, and release artifact formats. + - Dependencies: T04 + - Done when: Every Crane derivation that compiles the CLI receives the same canonical pre-generated payload contract, Pkl is absent from the Cargo build-script environment, canonical Pkl changes invalidate generation and dependent builds, dependency artifacts remain shared where applicable, and native, release, test, Clippy, and format topology remains intact. + - Verification notes (commands or checks): inspect derivation inputs/environment; run the narrow Crane package/test/Clippy checks and `nix flake check`; change a canonical Pkl input in a temporary worktree and inspect rebuild boundaries; confirm Flatpak and packaged-crate fallback checks still use their existing Pkl-free path. + - Implementation evidence: `flake.nix` now builds one canonical, deterministic `sce-cli-generated-input` derivation from the isolated Pkl/plugin fileset, writes the payload and canonical-input SHA-256 inventories, and passes its store path through `SCE_CLI_GENERATED_INPUT_DIR` to native, native-release, musl-release, test, and Clippy Cargo derivations. Pkl was removed from `commonCargoArgs`; a pre-Cargo assertion rejects any compiling derivation whose `PATH` still exposes Pkl. Dependency-only artifacts and the format derivation remain outside the generated-input dependency, and a focused `cli-generated-input` check validates target presence plus both inventories. + - Verification evidence: `nix build --no-link .#checks.x86_64-linux.cli-generated-input .#sce .#checks.x86_64-linux.cli-tests .#checks.x86_64-linux.cli-clippy` passed; `nix build --no-link .#sce-release` passed; derivation inspection showed the same generated-input store path on native, release, test, and Clippy derivations, no Pkl native build input, and no handoff on `cli-fmt`. A temporary canonical Pkl comment changed the generated-input, native package, test, and Clippy derivation paths while host and musl dependency-artifact paths plus `cli-fmt` stayed unchanged; the probe was then removed. `nix flake check` passed all checks, `nix run .#sce-flatpak -- validate` passed using its deterministic packaging-only fallback, and diff inspection confirmed no Flatpak or packaged-crate fallback definitions changed. + ## Open questions -None. The user explicitly chose ephemeral `OUT_DIR` generation and removal of all three committed generated target trees, while retaining the earlier packaging requirement for a self-contained crates.io artifact. +None. The user explicitly chose pre-Cargo generation into a separate directory with `build.rs` copying into `OUT_DIR`, excluded `cargo install --git`, and identified sandboxing as the reason to move Pkl out of the build script. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-27 + +### Commands run + +- `test ! -e config/.opencode && test ! -e config/.claude && test ! -e config/.pi` -> exit 0 (all removed generated target trees are absent) +- `bash -n scripts/run-cli-cargo.sh scripts/test-run-cli-cargo.sh && bash scripts/test-run-cli-cargo.sh` -> exit 0 (wrapper syntax, argument forwarding, canonical-input mutation/regeneration, inventory, failure propagation, and cleanup checks passed) +- `nix run .#pkl-check-generated` -> exit 0 (73-file deterministic ephemeral inventory passed with digest `605e7d406bd56047f76b8eecff3f53e4226e208133166225c34d868de032faae`) +- `nix flake check` -> exit 0 (all compatible-system flake checks passed) +- `nix run .#sce-flatpak -- validate` -> exit 0 (deterministic packaging fallback, Flatpak validation, and local manifest check passed) +- `nix develop -c ./scripts/run-cli-cargo.sh clean --manifest-path cli/Cargo.toml && nix develop -c ./scripts/run-cli-cargo.sh build --manifest-path cli/Cargo.toml` -> exit 0 (clean repository build generated the handoff before Cargo and built successfully) +- `git status --short cli/src cli/assets config` -> exit 0 (no build-created source, asset, or config changes) +- `nix develop -c sh -c './scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml config && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml agent_trace && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml auth_db && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml --test build_script'` -> exit 0 (setup 8, config 22, agent_trace 44, auth_db 2, and build-script handoff 5 tests passed) +- `nix develop -c ./scripts/run-cli-cargo.sh clippy --manifest-path cli/Cargo.toml --all-targets -- -D warnings` -> exit 0 (Clippy passed with warnings denied) +- `nix develop -c ./scripts/run-cli-cargo.sh install --path cli --locked --root "$install_root"` plus executable assertion and cleanup -> exit 0 (`sce` installed to a temporary root and was executable) +- Initial temporary package-list harness using `rg` -> exit 2 (`rg` was unavailable outside the Nix command; no product check failed, and the harness was replaced with shell-only inspection) +- Initial shell-only package-list inspection -> exit 1 (the inspection incorrectly rejected expected `package-fallback/pkl-generated/config/**` entries; the corrected inspection rejects only repository-level `config/` paths) +- Corrected clean-copy package preparation, `cargo package --list`, `cargo package`, archive inspection, Pkl removal from `PATH`, and unpacked-crate `cargo build --locked` flow -> exit 0 (296 files packaged, exactly 81 fallback entries inspected, and the unpacked crate built without Pkl or parent `config/` inputs) +- `nix develop -c env -u SCE_CLI_GENERATED_INPUT_DIR cargo check --manifest-path cli/Cargo.toml` -> exit 101 as expected (build failed actionably, requiring `SCE_CLI_GENERATED_INPUT_DIR` with `pkl-generated/`, `SHA256SUMS`, and `INPUTS.SHA256SUMS`) +- Initial `nix derivation show ... | jq` derivation inspection -> exit 5 (inspection used the wrong JSON root; no derivation failed) +- Corrected `nix derivation show .#sce .#sce-release .#checks.x86_64-linux.cli-tests .#checks.x86_64-linux.cli-clippy | jq -e ...` -> exit 0 (all four compiling derivations share one generated-input handoff, omit Pkl from native build inputs, and enforce Pkl absence before Cargo) +- `git diff --check` -> exit 0 (no whitespace errors) + +### Scaffolding removed + +- `/tmp/sce-package-validation.*` — temporary clean repository copy, package list, crate archive, and unpacked build tree used only for validation +- `/tmp/sce-validation-install.*` — temporary Cargo installation root used only for validation +- `/tmp/sce-cli-generated-input.*` — wrapper-generated handoff directories; cleanup assertions confirmed none remained + +### Success-criteria verification + +- [x] AC1: `config/.opencode`, `config/.claude`, and `config/.pi` are absent from the repository, and generated outputs exist only in temporary generation/build/package locations -> absence assertions and post-generation `git status` passed; the ephemeral inventory check did not recreate removed trees. +- [x] AC2: Supported repository builds generate before Cargo, while `build.rs` only validates/copies into `OUT_DIR` and leaves source trees unchanged -> the clean wrapper build passed; `OUT_DIR` contains `pkl-generated/`, `static/`, `setup_embedded_assets.rs`, and `generated_migrations.rs`; source inspection found no Pkl process invocation; focused status was clean. +- [x] AC3: The CLI embeds deterministic OpenCode, Claude, Pi, hook, policy, schema, and migration payloads -> the 73-file deterministic inventory and all authored setup/config/Agent Trace/auth DB suites passed; `OUT_DIR` inspection confirmed all three generated targets, schema, hooks, migrations, and generated manifests. +- [x] AC4: The staged crates.io package carries a packaging-only payload and builds without Pkl or repository parent inputs -> clean-copy packaging produced 296 files with exactly 81 fallback entries, no repository-level `assets/generated`, `migrations`, or `config` paths, and the unpacked crate built with Pkl removed from `PATH`. +- [x] AC5: Nix generates and hands off before Cargo, and Flatpak uses its explicit fallback without committed targets -> both full Nix and Flatpak validation passed; derivation inspection confirmed one pre-Cargo handoff and Pkl exclusion; Nix/Flatpak/release inspection found no reliance on committed generated trees. +- [x] AC6: Documented wrapper workflows support build, tests, Clippy, and local install with freshness and actionable invalid-handoff behavior -> all representative wrapper commands passed; the behavioral harness proved regeneration after canonical-input mutation and cleanup; build-script tests covered valid, missing, incomplete, and stale handoffs; direct Cargo without the handoff emitted the documented diagnostic. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- `nix flake check` reported that `aarch64-darwin`, `aarch64-linux`, and `x86_64-darwin` are incompatible with this host and were not checked locally. +- Flatpak validation skipped optional `flatpak-builder-lint` because it is not installed; required Flatpak validation still passed. diff --git a/context/sce/cli-cargo-distribution-contract.md b/context/sce/cli-cargo-distribution-contract.md index 91a63de9..c39fcabc 100644 --- a/context/sce/cli-cargo-distribution-contract.md +++ b/context/sce/cli-cargo-distribution-contract.md @@ -7,10 +7,12 @@ This file captures the implemented Cargo distribution slice from `context/plans/ - The published crate name is `shared-context-engineering`; it installs the `sce` binary. - `cli/Cargo.toml` keeps crates.io-facing metadata enabled for publication. - `cli/README.md` is the crate-facing install guidance source referenced by Cargo/crates.io surfaces. -- Repository Cargo builds evaluate canonical Pkl inputs directly into Cargo `OUT_DIR` and do not consume `cli/assets/generated/` or the packaging fallback. +- Repository Cargo builds require a pre-Cargo generated-input directory through `SCE_CLI_GENERATED_INPUT_DIR`; `cli/build.rs` never invokes Pkl and does not consume `cli/assets/generated/` or the packaging fallback when canonical repository sources are present. +- The handoff contains `pkl-generated/`, `SHA256SUMS` for that exact payload, and `INPUTS.SHA256SUMS` for canonical `config/pkl` plus referenced `config/lib` inputs. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, then copies the validated payload into `OUT_DIR/pkl-generated`. +- `scripts/run-cli-cargo.sh` is the supported repository Cargo boundary. It generates canonical Pkl twice into a fresh temporary directory, rejects nondeterminism, writes both inventories, exports the handoff only for the requested Cargo process, forwards Cargo arguments unchanged, and removes the directory after success, failure, or a handled signal. Build, targeted-test, Clippy, run, and `cargo install --path cli` workflows use this wrapper rather than direct Cargo. - Before packaging, `scripts/prepare-cli-generated-assets.sh` evaluates canonical Pkl twice, rejects nondeterministic output, stages generated targets plus hooks, schemas, and migrations under ignored `cli/package-fallback/`, and writes `SHA256SUMS` for the exact payload. - Published crates include only the packaging fallback, Rust sources, and crate metadata. In an unpacked crate, `cli/build.rs` validates the fallback inventory and copies it into the consumer's `OUT_DIR`; downstream Cargo builds do not require Pkl or parent repository paths. -- Missing or changed fallback files fail the build with guidance to recreate the package through the preparation script. When canonical repository Pkl sources exist, `build.rs` always prefers direct generation and does not silently fall back when Pkl execution fails. +- Missing or changed fallback files fail the build with guidance to recreate the package through the preparation script. When canonical repository Pkl sources exist, `build.rs` requires the generated-input handoff and does not silently use the packaging fallback. ## Publish workflow @@ -26,8 +28,9 @@ This file captures the implemented Cargo distribution slice from `context/plans/ ## Supported Cargo install paths - crates.io: `cargo install shared-context-engineering --locked` -- Git repository: `cargo install --git https://github.com/crocoder-dev/shared-context-engineering shared-context-engineering --locked` -- Local checkout: `cargo install --path cli --locked` +- Local checkout: `./scripts/run-cli-cargo.sh install --path cli --locked` + +Direct `cargo install --git` is unsupported because Cargo provides no repository-owned pre-generation boundary before compiling the checkout. ## Scope notes diff --git a/context/sce/flake-build-performance.md b/context/sce/flake-build-performance.md index a22d5d88..75c204f7 100644 --- a/context/sce/flake-build-performance.md +++ b/context/sce/flake-build-performance.md @@ -20,6 +20,17 @@ The root flake separates ordinary development from release-only work: Git-commit embedding is release-only. Native packages and normal CLI check derivations do not receive `SCE_GIT_COMMIT`; release packages do. +Generated CLI assets cross a separate pre-Cargo boundary. One deterministic +`cliGeneratedInput` derivation evaluates the canonical Pkl model twice, rejects +nondeterminism, and records exact SHA-256 inventories for both the payload and +its canonical inputs. Native, release, test, and Clippy derivations all receive +the same output through `SCE_CLI_GENERATED_INPUT_DIR`; Pkl is unavailable inside +those Cargo derivations. Host and musl dependency-only derivations and +`cli-fmt` omit the handoff, so generated-input changes invalidate generation +and compiling outputs without rebuilding dependency artifacts or formatting. +The `cli-generated-input` flake check verifies the payload roots and both +inventories independently of Cargo compilation. + ## Benchmark method Measurements were taken on x86_64-linux with 8 logical cores, Nix 2.34.8, and a diff --git a/context/sce/pi-extension-runtime.md b/context/sce/pi-extension-runtime.md index f1d48603..c5780fd1 100644 --- a/context/sce/pi-extension-runtime.md +++ b/context/sce/pi-extension-runtime.md @@ -95,9 +95,11 @@ unprefixed. ## Asset pipeline, install, and doctor coverage -- For repository builds, `cli/build.rs` evaluates the canonical Pkl model into - `OUT_DIR/pkl-generated` and embeds the generated `config/.pi` tree wholesale - as `PI_EMBEDDED_ASSETS`, so `sce setup --pi` installs the extension to +- For repository builds, a pre-Cargo step evaluates the canonical Pkl model and + passes its checksummed payload through `SCE_CLI_GENERATED_INPUT_DIR`. + `cli/build.rs` validates and copies it into `OUT_DIR/pkl-generated`, then + embeds the generated `config/.pi` tree wholesale as `PI_EMBEDDED_ASSETS`, so + `sce setup --pi` installs the extension to repo-root `.pi/extensions/sce/index.ts` with no per-asset enumeration. Pkl-free package fallback preparation is owned by the Cargo distribution path rather than this runtime contract. diff --git a/flake.nix b/flake.nix index 65cf8ef1..1dab5deb 100644 --- a/flake.nix +++ b/flake.nix @@ -143,6 +143,15 @@ ./config/lib/pi-plugin/sce-pi-extension.ts ./config/schema/agent-trace.schema.json ]; + cliGeneratedInputSrc = pkgs.lib.fileset.toSource { + root = workspaceRoot; + fileset = pkgs.lib.fileset.unions [ + ./config/pkl + ./config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts + ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts + ./config/lib/pi-plugin/sce-pi-extension.ts + ]; + }; workspaceSrc = pkgs.lib.fileset.toSource { root = workspaceRoot; fileset = pkgs.lib.fileset.unions [ @@ -271,14 +280,78 @@ SCE_GIT_COMMIT = shortGitCommit; }; - commonCargoArgs = cargoBaseArgs // { + # Generate the canonical Pkl payload before entering any Cargo + # derivation. The output is content-addressed by only the canonical + # generator inputs, so native, release, test, and Clippy builds share + # one handoff while dependency-only and formatting derivations remain + # independent of it. + cliGeneratedInput = pkgs.runCommand "sce-cli-generated-input" + { + src = cliGeneratedInputSrc; + nativeBuildInputs = [ + pkgs.coreutils + pkgs.diffutils + pkgs.findutils + pkgs.pkl + ]; + } + '' + set -euo pipefail + + cp -r "$src" ./repo + chmod -R u+w ./repo + comparison_root="$(mktemp -d)" + mkdir -p "$out/pkl-generated" "$comparison_root/pkl-generated" + + ( + cd ./repo + pkl eval -m "$out/pkl-generated" config/pkl/generate.pkl >/dev/null + pkl eval -m "$comparison_root/pkl-generated" config/pkl/generate.pkl >/dev/null + ) + + diff -qr "$out/pkl-generated" "$comparison_root/pkl-generated" >/dev/null + + ( + cd "$out" + find pkl-generated -type f -print \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "$path" + done + ) > "$out/SHA256SUMS" + + ( + cd ./repo + { + find config/pkl -type f -print + printf '%s\n' \ + config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts \ + config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts \ + config/lib/pi-plugin/sce-pi-extension.ts + } \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "$path" + done + ) > "$out/INPUTS.SHA256SUMS" + ''; + + cliGeneratedInputArgs = { + SCE_CLI_GENERATED_INPUT_DIR = cliGeneratedInput; + }; + + commonCargoArgs = cargoBaseArgs // cliGeneratedInputArgs // { pname = "sce"; src = workspaceSrc; - nativeBuildInputs = cargoBaseArgs.nativeBuildInputs ++ [ pkgs.pkl ]; postUnpack = '' cd "$sourceRoot/cli" sourceRoot="." + + if command -v pkl >/dev/null 2>&1; then + printf 'Pkl must not be available inside CLI Cargo derivations\n' >&2 + exit 1 + fi ''; }; @@ -1156,6 +1229,32 @@ mkdir -p "$out" ''; + cliGeneratedInputCheck = + pkgs.runCommand "sce-cli-generated-input-check" + { + nativeBuildInputs = [ pkgs.coreutils ]; + } + '' + set -euo pipefail + + test -d "${cliGeneratedInput}/pkl-generated/config/.opencode" + test -d "${cliGeneratedInput}/pkl-generated/config/.claude" + test -d "${cliGeneratedInput}/pkl-generated/config/.pi" + + ( + cd "${cliGeneratedInput}" + sha256sum -c SHA256SUMS >/dev/null + ) + + cp -r "${cliGeneratedInputSrc}" ./repo + ( + cd ./repo + sha256sum -c "${cliGeneratedInput}/INPUTS.SHA256SUMS" >/dev/null + ) + + mkdir -p "$out" + ''; + mkCopiedSourceCheck = { name , src @@ -1442,6 +1541,7 @@ } ); + cli-generated-input = cliGeneratedInputCheck; pkl-generated = pklGeneratedCheck; npm-bun-tests = npmTests; diff --git a/scripts/run-cli-cargo.sh b/scripts/run-cli-cargo.sh new file mode 100755 index 00000000..c7d9e1a8 --- /dev/null +++ b/scripts/run-cli-cargo.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd "${script_dir}/.." && pwd)" + +if [ "$#" -eq 0 ]; then + cat >&2 <<'EOF' +Usage: ./scripts/run-cli-cargo.sh + +Examples: + ./scripts/run-cli-cargo.sh build --manifest-path cli/Cargo.toml + ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup + ./scripts/run-cli-cargo.sh clippy --manifest-path cli/Cargo.toml --all-targets -- -D warnings + ./scripts/run-cli-cargo.sh install --path cli --locked +EOF + exit 2 +fi + +for command in pkl cargo sha256sum; do + if ! command -v "${command}" >/dev/null 2>&1; then + printf '%s is required to generate CLI assets and run Cargo.\n' "${command}" >&2 + exit 1 + fi +done + +generator="${repo_root}/config/pkl/generate.pkl" +canonical_inputs=( + "config/pkl" + "config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts" + "config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts" + "config/lib/pi-plugin/sce-pi-extension.ts" +) + +for relative_path in "${canonical_inputs[@]}"; do + if [ ! -e "${repo_root}/${relative_path}" ]; then + printf 'Missing canonical CLI generator input: %s\n' "${repo_root}/${relative_path}" >&2 + exit 1 + fi +done + +tmp_root="$(mktemp -d "${TMPDIR:-/tmp}/sce-cli-generated-input.XXXXXX")" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT +trap 'exit 129' HUP +trap 'exit 130' INT +trap 'exit 143' TERM + +generated_input_root="${tmp_root}/generated-input" +comparison_root="${tmp_root}/comparison" +mkdir -p \ + "${generated_input_root}/pkl-generated" \ + "${comparison_root}/pkl-generated" + +generate_payload() { + local destination="$1" + ( + cd "${repo_root}" + pkl eval -m "${destination}" "${generator}" >/dev/null + ) +} + +generate_payload "${generated_input_root}/pkl-generated" +generate_payload "${comparison_root}/pkl-generated" + +if ! diff -qr \ + "${generated_input_root}/pkl-generated" \ + "${comparison_root}/pkl-generated" >/dev/null; then + printf 'Canonical Pkl generation is not deterministic.\n' >&2 + diff -r \ + "${generated_input_root}/pkl-generated" \ + "${comparison_root}/pkl-generated" >&2 || true + exit 1 +fi + +write_payload_inventory() { + ( + cd "${generated_input_root}" + find pkl-generated -type f -print \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "${path}" + done + ) > "${generated_input_root}/SHA256SUMS" +} + +write_canonical_input_inventory() { + ( + cd "${repo_root}" + { + find config/pkl -type f -print + printf '%s\n' \ + config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts \ + config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts \ + config/lib/pi-plugin/sce-pi-extension.ts + } \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "${path}" + done + ) > "${generated_input_root}/INPUTS.SHA256SUMS" +} + +write_payload_inventory +write_canonical_input_inventory +rm -rf "${comparison_root}" + +printf 'Prepared temporary CLI generated-input handoff at %s\n' "${generated_input_root}" +( + cd "${repo_root}" + SCE_CLI_GENERATED_INPUT_DIR="${generated_input_root}" cargo "$@" +) diff --git a/scripts/test-run-cli-cargo.sh b/scripts/test-run-cli-cargo.sh new file mode 100755 index 00000000..5321e8a8 --- /dev/null +++ b/scripts/test-run-cli-cargo.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +helper="${script_dir}/run-cli-cargo.sh" +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT + +test_repo="${tmp_root}/repo" +fake_bin="${tmp_root}/bin" +state_root="${tmp_root}/state" +tmp_dir="${tmp_root}/tmp" +mkdir -p \ + "${test_repo}/scripts" \ + "${test_repo}/config/pkl" \ + "${test_repo}/config/lib/agent-trace-plugin" \ + "${test_repo}/config/lib/bash-policy-plugin" \ + "${test_repo}/config/lib/pi-plugin" \ + "${fake_bin}" \ + "${state_root}" \ + "${tmp_dir}" +cp "${helper}" "${test_repo}/scripts/run-cli-cargo.sh" + +printf 'generator-v1\n' > "${test_repo}/config/pkl/generate.pkl" +printf 'agent-trace\n' > "${test_repo}/config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts" +printf 'bash-policy\n' > "${test_repo}/config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts" +printf 'pi-extension\n' > "${test_repo}/config/lib/pi-plugin/sce-pi-extension.ts" + +cat > "${fake_bin}/pkl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +destination="" +generator="" +while [ "$#" -gt 0 ]; do + case "$1" in + eval) shift ;; + -m) + destination="$2" + shift 2 + ;; + *) + generator="$1" + shift + ;; + esac +done +mkdir -p "${destination}/config/.opencode" +sha256sum "${generator}" > "${destination}/config/.opencode/generator.sha256" +EOF + +cat > "${fake_bin}/cargo" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +: "${SCE_CLI_GENERATED_INPUT_DIR:?missing generated-input handoff}" +: "${FAKE_CARGO_STATE:?missing test state directory}" +mkdir -p "${FAKE_CARGO_STATE}" +printf '%s\n' "$@" > "${FAKE_CARGO_STATE}/arguments" +( + cd "${SCE_CLI_GENERATED_INPUT_DIR}" + sha256sum -c SHA256SUMS >/dev/null +) +( + cd "${PWD}" + sha256sum -c "${SCE_CLI_GENERATED_INPUT_DIR}/INPUTS.SHA256SUMS" >/dev/null +) +cp "${SCE_CLI_GENERATED_INPUT_DIR}/SHA256SUMS" "${FAKE_CARGO_STATE}/SHA256SUMS" +cp "${SCE_CLI_GENERATED_INPUT_DIR}/INPUTS.SHA256SUMS" "${FAKE_CARGO_STATE}/INPUTS.SHA256SUMS" +exit "${FAKE_CARGO_EXIT_CODE:-0}" +EOF +chmod +x "${fake_bin}/pkl" "${fake_bin}/cargo" "${test_repo}/scripts/run-cli-cargo.sh" + +run_helper() { + env \ + PATH="${fake_bin}:${PATH}" \ + TMPDIR="${tmp_dir}" \ + FAKE_CARGO_STATE="$1" \ + FAKE_CARGO_EXIT_CODE="${2:-0}" \ + "${test_repo}/scripts/run-cli-cargo.sh" "${@:3}" +} + +assert_tmp_dir_empty() { + local entries=("${tmp_dir}"/*) + if [ -e "${entries[0]}" ]; then + printf 'Temporary generated-input directories were not cleaned up.\n' >&2 + exit 1 + fi +} + +first_state="${state_root}/first" +run_helper "${first_state}" 0 test --manifest-path cli/Cargo.toml setup +expected_arguments=$'test\n--manifest-path\ncli/Cargo.toml\nsetup' +if [ "$(cat "${first_state}/arguments")" != "${expected_arguments}" ]; then + printf 'Cargo arguments were not forwarded unchanged.\n' >&2 + exit 1 +fi +assert_tmp_dir_empty + +printf 'generator-v2\n' > "${test_repo}/config/pkl/generate.pkl" +second_state="${state_root}/second" +run_helper "${second_state}" 0 build --manifest-path cli/Cargo.toml +if cmp -s "${first_state}/SHA256SUMS" "${second_state}/SHA256SUMS"; then + printf 'Canonical input changes did not regenerate the payload.\n' >&2 + exit 1 +fi +if cmp -s "${first_state}/INPUTS.SHA256SUMS" "${second_state}/INPUTS.SHA256SUMS"; then + printf 'Canonical input changes did not refresh the input inventory.\n' >&2 + exit 1 +fi +assert_tmp_dir_empty + +set +e +run_helper "${state_root}/failure" 42 clippy --manifest-path cli/Cargo.toml --all-targets +failure_status=$? +set -e +if [ "${failure_status}" -ne 42 ]; then + printf 'Cargo failure status was not preserved: expected 42, got %s.\n' "${failure_status}" >&2 + exit 1 +fi +assert_tmp_dir_empty + +printf 'run-cli-cargo helper tests passed.\n' From 2726542f21c5b2e32116608c9bea14cdb7c876c1 Mon Sep 17 00:00:00 2001 From: David Abram Date: Tue, 28 Jul 2026 00:23:00 +0200 Subject: [PATCH 09/21] context-sync: Simplify task synchronization reports Reduce task sync output to the durable changes, unresolved gaps, and next workflow command that users need. Update the canonical Pkl template and all rendered skill references to share the same concise contract. Plan: simplify-task-context-sync-report (T01) Co-authored-by: SCE --- .../references/sync-report.md | 41 ++++----- .../references/sync-report.md | 41 ++++----- .../references/sync-report.md | 41 ++++----- config/pkl/base/workflow-context-sync.pkl | 81 +++++++++++------ .../simplify-task-context-sync-report.md | 88 +++++++++++++++++++ context/sce/context-workflow-rules.md | 11 ++- context/sce/shared-context-code-workflow.md | 3 + 7 files changed, 198 insertions(+), 108 deletions(-) create mode 100644 context/plans/simplify-task-context-sync-report.md diff --git a/.claude/skills/sce-task-context-sync/references/sync-report.md b/.claude/skills/sce-task-context-sync/references/sync-report.md index 7d5acb94..581177da 100644 --- a/.claude/skills/sce-task-context-sync/references/sync-report.md +++ b/.claude/skills/sce-task-context-sync/references/sync-report.md @@ -20,26 +20,15 @@ as a separate workflow state. **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} ## Updated context - `{context file}` — {concise description of the durable truth updated} -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}` @@ -65,9 +54,12 @@ Omit this section when unnecessary.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} -**Classification:** none +## Synchronization result {Explain why the completed implementation did not introduce durable, non-obvious repository knowledge requiring an update.} @@ -76,14 +68,6 @@ non-obvious repository knowledge requiring an update.} - `{context file or area}` — {what was checked and why it remains accurate} -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}`, already present. @@ -102,6 +86,11 @@ non-obvious repository knowledge requiring an update.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + ## Blocker **Problem:** {specific synchronization blocker} @@ -120,8 +109,8 @@ again.} ## Report rules - Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. +- Under **Updated files**, list every changed file from the execution handoff + except paths under `context/`. - Report the missing context root as `blocked`, with `sce setup --bootstrap-context` as the required action and the existence of `context/` as the retry condition. diff --git a/.opencode/skills/sce-task-context-sync/references/sync-report.md b/.opencode/skills/sce-task-context-sync/references/sync-report.md index 7d5acb94..581177da 100644 --- a/.opencode/skills/sce-task-context-sync/references/sync-report.md +++ b/.opencode/skills/sce-task-context-sync/references/sync-report.md @@ -20,26 +20,15 @@ as a separate workflow state. **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} ## Updated context - `{context file}` — {concise description of the durable truth updated} -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}` @@ -65,9 +54,12 @@ Omit this section when unnecessary.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} -**Classification:** none +## Synchronization result {Explain why the completed implementation did not introduce durable, non-obvious repository knowledge requiring an update.} @@ -76,14 +68,6 @@ non-obvious repository knowledge requiring an update.} - `{context file or area}` — {what was checked and why it remains accurate} -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}`, already present. @@ -102,6 +86,11 @@ non-obvious repository knowledge requiring an update.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + ## Blocker **Problem:** {specific synchronization blocker} @@ -120,8 +109,8 @@ again.} ## Report rules - Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. +- Under **Updated files**, list every changed file from the execution handoff + except paths under `context/`. - Report the missing context root as `blocked`, with `sce setup --bootstrap-context` as the required action and the existence of `context/` as the retry condition. diff --git a/.pi/skills/sce-task-context-sync/references/sync-report.md b/.pi/skills/sce-task-context-sync/references/sync-report.md index 7d5acb94..581177da 100644 --- a/.pi/skills/sce-task-context-sync/references/sync-report.md +++ b/.pi/skills/sce-task-context-sync/references/sync-report.md @@ -20,26 +20,15 @@ as a separate workflow state. **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required synchronization.} +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} ## Updated context - `{context file}` — {concise description of the durable truth updated} -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}` @@ -65,9 +54,12 @@ Omit this section when unnecessary.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` -## Context impact +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} -**Classification:** none +## Synchronization result {Explain why the completed implementation did not introduce durable, non-obvious repository knowledge requiring an update.} @@ -76,14 +68,6 @@ non-obvious repository knowledge requiring an update.} - `{context file or area}` — {what was checked and why it remains accurate} -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - ## Feature existence - `{feature}` — `{context file that canonically describes it}`, already present. @@ -102,6 +86,11 @@ non-obvious repository knowledge requiring an update.} **Plan:** `{plan path}` **Task:** `{task id} — {task title}` +## Updated files + +- {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + ## Blocker **Problem:** {specific synchronization blocker} @@ -120,8 +109,8 @@ again.} ## Report rules - Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. +- Under **Updated files**, list every changed file from the execution handoff + except paths under `context/`. - Report the missing context root as `blocked`, with `sce setup --bootstrap-context` as the required action and the existence of `context/` as the retry condition. diff --git a/config/pkl/base/workflow-context-sync.pkl b/config/pkl/base/workflow-context-sync.pkl index 166bb915..78b6c615 100644 --- a/config/pkl/base/workflow-context-sync.pkl +++ b/config/pkl/base/workflow-context-sync.pkl @@ -859,19 +859,22 @@ local planReportRole3 = """ local reportCommon3 = """ - ## Context impact - - **Classification:** `{local | domain | root}`\(" ") - **Affected areas:** `{comma-separated areas}` - - {Explain which durable behavior, architecture, terminology, operation, or """ local taskReportRole4 = """ - constraint required synchronization.} + ## Updated files + + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} """ local planReportRole4 = """ + ## Context impact + + **Classification:** `{local | domain | root}`\(" ") + **Affected areas:** `{comma-separated areas}` + + {Explain which durable behavior, architecture, terminology, operation, or constraint required plan-level synchronization after validation.} ## Plan context requirements @@ -885,6 +888,19 @@ local reportCommon4 = """ - `{context file}` — {concise description of the durable truth updated} + """ + +local taskReportRole5 = """ + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}` + + ## Verification + + - {How the edited context was checked against implementation and execution evidence.} + """ + +local planReportRole5 = """ ## Root pass - `context/overview.md` — {verified | edited | absent} @@ -899,13 +915,6 @@ local reportCommon4 = """ ## Verification - """ - -local taskReportRole5 = """ - - {How the edited context was checked against implementation and execution evidence.} - """ - -local planReportRole5 = """ - {How the edited context was checked against the finished implementation and validation evidence.} """ @@ -948,18 +957,25 @@ local planReportRole7 = """ local reportCommon7 = """ - ## Context impact - - **Classification:** none - """ local taskReportRole8 = """ + ## Updated files + + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + + ## Synchronization result + {Explain why the completed implementation did not introduce durable, non-obvious repository knowledge requiring an update.} """ local planReportRole8 = """ + ## Context impact + + **Classification:** none + {Explain why the finished plan introduced no durable, non-obvious repository knowledge requiring an update, or why existing context already matched.} @@ -975,6 +991,19 @@ local reportCommon8 = """ - `{context file or area}` — {what was checked and why it remains accurate} + """ + +local taskReportRole9 = """ + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}`, already present. + + ## Verification + + - {How existing context was compared with implementation and execution evidence.} + """ + +local planReportRole9 = """ ## Root pass - `context/overview.md` — {verified | absent} @@ -989,13 +1018,6 @@ local reportCommon8 = """ ## Verification - """ - -local taskReportRole9 = """ - - {How existing context was compared with implementation and execution evidence.} - """ - -local planReportRole9 = """ - {How existing context was compared with the finished implementation and validation evidence.} """ @@ -1023,6 +1045,11 @@ local reportCommon10 = """ local taskReportRole11 = """ **Plan:** `{plan path}`\(" ") **Task:** `{task id} — {task title}` + + ## Updated files + + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} """ local planReportRole11 = """ @@ -1063,8 +1090,8 @@ local reportCommon12 = """ """ local taskReportRole13 = """ - - Report every file in the root pass, including any that is absent. A root pass - with a file missing from the list reads as a file that was never checked. + - Under **Updated files**, list every changed file from the execution handoff + except paths under `context/`. """ local planReportRole13 = """ diff --git a/context/plans/simplify-task-context-sync-report.md b/context/plans/simplify-task-context-sync-report.md new file mode 100644 index 00000000..680849a6 --- /dev/null +++ b/context/plans/simplify-task-context-sync-report.md @@ -0,0 +1,88 @@ +# Plan: simplify-task-context-sync-report + +## Change summary + +Simplify only the `sce-task-context-sync` report contract: stop rendering context-impact classification and the mandatory root-pass checklist, and add an `Updated files` section listing changed files outside `context/`. The plan-level context-sync report and its `Plan context requirements` section remain unchanged. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: Every task context-sync report variant shows the implementation's changed non-context files under `Updated files` and does not render a context-impact classification or root-pass checklist. + - Validate: Generate the workflow payload and inspect the task `references/sync-report.md` output for all three variants. +- [x] AC2: The plan context-sync report contract retains its existing classification, plan context requirements, and root-pass sections. + - Validate: Generate the workflow payload and compare the plan `references/sync-report.md` structure with the unchanged plan-specific contract. +- [x] AC3: The project-root `.pi` task sync report baseline matches the canonical Pkl-rendered task report contract. + - Validate: `nix run .#pkl-check-generated` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- `context/sce/context-workflow-rules.md` and `context/sce/shared-context-code-workflow.md` must describe the task synchronization behavior accurately if their report-output wording is affected. +- `context/architecture.md` and `context/patterns.md` must remain accurate about shared Pkl ownership and the project-root `.pi` behavioral baseline. + +## Constraints and non-goals + +- **In scope:** The task-specific report template in `config/pkl/base/workflow-context-sync.pkl` and `.pi/skills/sce-task-context-sync/references/sync-report.md`, including all task report status variants. +- **Out of scope:** The plan context-sync report template and other workflow result/report contracts. +- **Constraints:** Preserve the mandatory root-pass synchronization behavior; remove only its rendered report section. `Updated files` lists changed files from the execution handoff after excluding every path under `context/`. +- **Non-goal:** Removing context-impact classification from the task execution handoff or changing how task context synchronization decides which context to inspect or edit. + +## Assumptions + +- “Only in task context sync” means `Plan context requirements` requires no change because that section exists only in the plan report. +- `Updated files` belongs in each task report status variant so the invoking workflow can see non-context implementation changes whether synchronization is synced, unnecessary, or blocked. + +## Task stack + +- [x] T01: `Simplify the task context-sync report contract` (status:complete) + - Task ID: T01 + - Goal: Update the canonical and project-root task context-sync report templates to omit classification/root-pass output and report changed non-context files. + - Boundaries (in/out of scope): In — task-specific report composition in `workflow-context-sync.pkl`, the `.pi` task report baseline, and focused contract assertions/inspection. Out — plan report output and synchronization decision behavior. + - Dependencies: none + - Done when: All task report variants contain `Updated files` with non-context-file semantics, omit `Classification` and `Root pass`, the plan report remains structurally unchanged, and targeted generation/parity checks pass. + - Verification notes (commands or checks): Evaluate `config/pkl/base/workflow-context-sync.pkl`; inspect or extract both task and plan `references/sync-report.md` documents; run `nix run .#pkl-check-generated`. + - Implementation evidence: Split task-specific report fragments from the shared plan report structure, added `Updated files` filtering semantics to all three task variants, removed rendered task classification/root-pass sections, and updated the project-root `.pi` baseline. + - Verification evidence: + - `nix develop -c pkl eval config/pkl/base/workflow-context-sync.pkl` — passed; generated task and plan packages evaluated successfully. + - Generated report inspection — passed; all three task variants contain `Updated files`, omit classification/root-pass sections, and the generated plan report is unchanged from its project-root baseline. + - `nix run .#pkl-check-generated` — passed; deterministic ephemeral generation produced 73 files. + +## Open questions + +None. The clarification limits the change to task context sync, and the repository already has a role-parameterized source seam that can preserve the plan report contract. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-28 + +### Commands run + +- `nix develop -c pkl eval -f json config/pkl/base/workflow-context-sync.pkl` plus generated-report inspection and baseline comparison -> exit 0 (all three task variants contain `Updated files` and omit context-impact/root-pass sections; the plan report retains context impact, plan context requirements, and root pass; both project-root `.pi` report baselines are byte-identical to canonical output) +- `nix run .#pkl-check-generated` -> exit 0 (deterministic ephemeral generation passed for 73 files; inventory SHA-256 `bad74106e457b66ac461e1f39a3e89be2bf2345276295d55dd35cf2259fdb64c`) +- `nix flake check` -> exit 0 (all checks passed on x86_64-linux) + +### Scaffolding removed + +None. + +### Success-criteria verification + +- [x] AC1: Every task context-sync report variant shows changed non-context files under `Updated files` and omits context-impact classification and root-pass output -> generated report inspection found three `Updated files` sections and no task `Context impact` or `Root pass` sections. +- [x] AC2: The plan context-sync report retains classification, plan context requirements, and root-pass sections -> generated report inspection found the expected sections in both applicable plan variants and confirmed byte identity with `.pi/skills/sce-plan-context-sync/references/sync-report.md`. +- [x] AC3: The project-root `.pi` task sync report baseline matches the canonical Pkl-rendered task report contract -> direct byte comparison with canonical generated output passed. + +### Failed checks and follow-ups + +None. + +### Residual risks + +- `nix run .#pkl-check-generated` validates deterministic generation but not project-root baseline parity; AC3 therefore also used a direct byte comparison. diff --git a/context/sce/context-workflow-rules.md b/context/sce/context-workflow-rules.md index 3038794b..f851ec45 100644 --- a/context/sce/context-workflow-rules.md +++ b/context/sce/context-workflow-rules.md @@ -127,9 +127,14 @@ makes the smallest coherent documentation change: ownership, or terminology changes. Every pass also accounts for feature existence, adds glossary entries for new -domain language, verifies relative links and line limits, and reports each root -file as verified, edited, or absent. Task synchronization does not run full-plan -validation, and plan synchronization does not rerun final validation. +domain language, and verifies relative links and line limits. Task reports list +the execution handoff's changed files outside `context/` under `Updated files`; +they do not render impact classification or the root-pass checklist, although +task synchronization still uses the classification and performs the mandatory +pass. Plan reports continue to render impact classification, plan context +requirements, and each root file as verified, edited, or absent. Task +synchronization does not run full-plan validation, and plan synchronization does +not rerun final validation. ## Canonical sources diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index 62d64852..f2d4d692 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -29,6 +29,9 @@ The implementation lifecycle executes at most one reviewed task per `/next-task` - Runs only from the complete successful execution handoff. - Reconciles one task with durable context and performs the mandatory root-file pass. - Returns a Markdown report with `synced`, `no_context_change`, or `blocked`. + - Every report variant lists changed files outside `context/` under `Updated files`; + task reports omit the impact classification and rendered root-pass checklist + without changing synchronization behavior. 4. Command continuation - Emits exactly one next-task command for the first unchecked task in plan order, or a `/validate` command when all implementation tasks are complete. - Never executes the continuation in the same invocation. From 873b114c85100e8bfe63c792920f24577bd01e75 Mon Sep 17 00:00:00 2001 From: David Abram Date: Tue, 28 Jul 2026 01:31:07 +0200 Subject: [PATCH 10/21] commit: Restore the atomic commit workflow Reintroduce /commit as a fourth canonical workflow with explicit ownership: the command handles staging and the single commit, while sce-atomic-commit analyzes staged changes and proposes repository-style messages. Render the self-contained package for Pi, OpenCode, and Claude and enforce the expanded workflow inventory. Plan: commit-workflow (T01, T02, T03) Co-authored-by: SCE --- .claude/commands/commit.md | 131 ++++ .claude/skills/sce-atomic-commit/SKILL.md | 167 +++++ .../references/commit-contract.yaml | 205 ++++++ .../references/commit-message-style.md | 63 ++ .gitignore | 9 + .opencode/command/commit.md | 134 ++++ .opencode/skills/sce-atomic-commit/SKILL.md | 167 +++++ .../references/commit-contract.yaml | 205 ++++++ .../references/commit-message-style.md | 63 ++ .pi/prompts/commit.md | 130 ++++ .pi/skills/sce-atomic-commit/SKILL.md | 166 +++++ .../references/commit-contract.yaml | 205 ++++++ .../references/commit-message-style.md | 63 ++ config/pkl/README.md | 15 +- config/pkl/base/workflow-commit.pkl | 611 ++++++++++++++++++ config/pkl/renderers/claude-content.pkl | 2 + config/pkl/renderers/claude-metadata.pkl | 1 + .../pkl/renderers/metadata-coverage-check.pkl | 6 +- config/pkl/renderers/opencode-content.pkl | 14 +- config/pkl/renderers/pi-content.pkl | 2 + context/context-map.md | 1 + context/glossary.md | 1 + context/plans/commit-workflow.md | 125 ++++ context/sce/atomic-commit-workflow.md | 135 ++++ context/sce/dedup-ownership-table.md | 3 +- 25 files changed, 2614 insertions(+), 10 deletions(-) create mode 100644 .claude/commands/commit.md create mode 100644 .claude/skills/sce-atomic-commit/SKILL.md create mode 100644 .claude/skills/sce-atomic-commit/references/commit-contract.yaml create mode 100644 .claude/skills/sce-atomic-commit/references/commit-message-style.md create mode 100644 .opencode/command/commit.md create mode 100644 .opencode/skills/sce-atomic-commit/SKILL.md create mode 100644 .opencode/skills/sce-atomic-commit/references/commit-contract.yaml create mode 100644 .opencode/skills/sce-atomic-commit/references/commit-message-style.md create mode 100644 .pi/prompts/commit.md create mode 100644 .pi/skills/sce-atomic-commit/SKILL.md create mode 100644 .pi/skills/sce-atomic-commit/references/commit-contract.yaml create mode 100644 .pi/skills/sce-atomic-commit/references/commit-message-style.md create mode 100644 config/pkl/base/workflow-commit.pkl create mode 100644 context/plans/commit-workflow.md create mode 100644 context/sce/atomic-commit-workflow.md diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md new file mode 100644 index 00000000..2975a132 --- /dev/null +++ b/.claude/commands/commit.md @@ -0,0 +1,131 @@ +--- +description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" +allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash +--- + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; `sce-atomic-commit` owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the +commit context. + +`sce-atomic-commit` exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of `sce-atomic-commit`. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when `sce-atomic-commit` returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. diff --git a/.claude/skills/sce-atomic-commit/SKILL.md b/.claude/skills/sce-atomic-commit/SKILL.md new file mode 100644 index 00000000..0365ae94 --- /dev/null +++ b/.claude/skills/sce-atomic-commit/SKILL.md @@ -0,0 +1,167 @@ +--- +name: sce-atomic-commit +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one YAML + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. +compatibility: claude +--- + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Returning one terminal YAML result. + +Write messages matching: + +`references/commit-message-style.md` + +Return a result matching: + +`references/commit-contract.yaml` + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Return `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/commit-message-style.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, return `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return YAML + +Return exactly one YAML document matching `references/commit-contract.yaml`: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal YAML result matching `references/commit-contract.yaml` was + returned. diff --git a/.claude/skills/sce-atomic-commit/references/commit-contract.yaml b/.claude/skills/sce-atomic-commit/references/commit-contract.yaml new file mode 100644 index 00000000..5ffdd9ff --- /dev/null +++ b/.claude/skills/sce-atomic-commit/references/commit-contract.yaml @@ -0,0 +1,205 @@ +version: 1 +name: sce-atomic-commit-result + +description: > + Output contract for sce-atomic-commit. The skill returns exactly one YAML + document representing proposal, bypass_message, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be proposal, bypass_message, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. + - Return proposal only in regular mode, and bypass_message only in bypass + mode. blocked is valid in both. + - Every staged file must appear under exactly one commit's files. + - Report file paths exactly as `git diff --cached --name-only` reports them. + - Carry the message body inside message, separated from the subject by one + blank line. Do not split it into a separate field. + - Do not include a commit hash. This skill never commits. + - Do not report guidance the mode forbids. + +variants: + + proposal: + meaning: > + The staged changes were analyzed in regular mode and one or more atomic + commit messages were written. Proposal-only: nothing was committed. + + required_fields: + - status + - mode + - commits + + optional_fields: + - split_rationale + - scope_classification + - notes + + field_rules: + - Include split_rationale only when commits holds more than one entry. + - scope_classification reports the context-file guidance gate as + context_only or mixed. + + shape: + status: proposal + mode: regular + + commits: + - id: string + message: string + files: + - string + cites_plan: boolean + + split_rationale: string + scope_classification: context_only | mixed + + notes: + - string + + example: + status: proposal + mode: regular + + commits: + - id: C01 + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full + re-login. Adds the refresh handler and reuses the existing token + issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + - id: C02 + + message: | + build: Pin the formatter to the toolchain version + + The formatter floated across environments and produced diff noise + unrelated to any change. + + files: + - flake.nix + + cites_plan: false + + split_rationale: > + The refresh endpoint and the formatter pin pursue unrelated goals and + share no files. Committing them together would hide the build change + behind a feature subject. + + scope_classification: mixed + + bypass_message: + meaning: > + The staged changes were analyzed in bypass mode and exactly one commit + message covering all staged files was written. The invoking workflow + executes the commit. + + required_fields: + - status + - mode + - message + - files + + optional_fields: + - cites_plan + - notes + + field_rules: + - files lists every staged file, because one message covers all of them. + - Never include commits, split_rationale, or scope_classification. + + shape: + status: bypass_message + mode: bypass + + message: string + + files: + - string + + cites_plan: boolean + + notes: + - string + + example: + status: bypass_message + mode: bypass + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full re-login. + Adds the refresh handler and reuses the existing token issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + blocked: + meaning: > + Faithful commit messages cannot be written from the staged changes. + + required_fields: + - status + - issues + + optional_fields: + - mode + - files + + field_rules: + - Include mode whenever the workflow supplied one. + - Include files when staged files were read before blocking. + - Plan-citation ambiguity blocks in regular mode only. In bypass mode the + citation is omitted instead. + + shape: + status: blocked + mode: regular | bypass + + files: + - string + + issues: + - id: string + category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context + problem: string + impact: string + decision_required: string + + example: + status: blocked + mode: regular + + files: + - context/plans/authentication.md + + issues: + - id: B01 + category: plan_citation_ambiguity + + problem: > + The staged plan diff changes two task checkboxes and does not + expose which task this commit completes. + + impact: > + The commit body would cite a task ID the staged diff does not + support. + + decision_required: > + State the completed task ID, or stage only that task's plan edit. diff --git a/.claude/skills/sce-atomic-commit/references/commit-message-style.md b/.claude/skills/sce-atomic-commit/references/commit-message-style.md new file mode 100644 index 00000000..7a1b5084 --- /dev/null +++ b/.claude/skills/sce-atomic-commit/references/commit-message-style.md @@ -0,0 +1,63 @@ +# Commit message style + +The wording rules for every message `sce-atomic-commit` returns, in either +mode. This file is the only authority for message content and shape. + +Messages are carried in the result's `message` field, subject first, then one +blank line, then the body. + +## Subject + +Pattern: + +`: ` + +- Scope is the smallest stable subsystem or module name recognizable in the + repository. When no such name applies, use the primary directory or package + of the change. +- Start the summary with an imperative verb: Fix, Add, Remove, Implement, + Refactor, Simplify, Rename, Update, Ensure, Allow. +- Capitalize the verb. Do not end the subject with a period. +- Keep it concrete and technical. Name what changed, not how it felt. + +## Body + +Include a body whenever the subject alone leaves the change unexplained. Omit +it for changes whose subject is self-evident. + +A body says what was wrong or missing, why it mattered, what changed +conceptually, and the impact. It does not restate the subject in longer words, +and it does not narrate the editing process. + +Wrap the body at a readable width and separate paragraphs with a blank line. + +## Issue references + +Put each issue reference on its own line at the end of the body, for example +`Fixes #123`. + +Reference only issues the staged diff or the supplied commit context names. Do +not infer an issue number from a branch name. + +## Plan citations + +When a commit's staged files include `context/plans/*.md`, the body must also +cite: + +- The affected plan slug. +- Every updated task ID (`T0X`). + +Cite only what the staged plan diff shows. When the diff does not expose the +slug or task IDs clearly enough to cite faithfully, the skill's mode decides +what happens — the ambiguity is not resolved here by guessing. + +## Anti-patterns + +- Vague subjects: "cleanup", "updates", "various fixes". +- A body that repeats the subject without adding why or impact. +- Playful tone in a fix, security change, or architectural change. +- Mentioning `context/` synchronization activity. +- Inventing plan slugs, task IDs, or issue references. +- Splitting changes that already form one coherent unit. +- Forcing unrelated goals into a single commit. +- Describing intent the staged diff does not support. diff --git a/.gitignore b/.gitignore index 6314d21c..2a3968ed 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,12 @@ cli/package-fallback/ integrations/**/target/ result* dist/ + +# Pkl generator output. Generation is ephemeral (Cargo OUT_DIR); running +# `pkl eval -m .` from the repo root writes these paths, and +# config/pkl/check-generated.sh fails if they are ever committed. +# Deliberately file-scoped: config/schema/agent-trace.schema.json is source. +config/.opencode/ +config/.claude/ +config/.pi/ +config/schema/sce-config.schema.json diff --git a/.opencode/command/commit.md b/.opencode/command/commit.md new file mode 100644 index 00000000..d1593d32 --- /dev/null +++ b/.opencode/command/commit.md @@ -0,0 +1,134 @@ +--- +description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" +agent: "Shared Context Code" +entry-skill: "sce-atomic-commit" +skills: + - "sce-atomic-commit" +--- + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; `sce-atomic-commit` owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the +commit context. + +`sce-atomic-commit` exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of `sce-atomic-commit`. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when `sce-atomic-commit` returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. diff --git a/.opencode/skills/sce-atomic-commit/SKILL.md b/.opencode/skills/sce-atomic-commit/SKILL.md new file mode 100644 index 00000000..98921e66 --- /dev/null +++ b/.opencode/skills/sce-atomic-commit/SKILL.md @@ -0,0 +1,167 @@ +--- +name: sce-atomic-commit +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one YAML + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. +compatibility: opencode +--- + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Returning one terminal YAML result. + +Write messages matching: + +`references/commit-message-style.md` + +Return a result matching: + +`references/commit-contract.yaml` + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Return `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/commit-message-style.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, return `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return YAML + +Return exactly one YAML document matching `references/commit-contract.yaml`: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal YAML result matching `references/commit-contract.yaml` was + returned. diff --git a/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml b/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml new file mode 100644 index 00000000..5ffdd9ff --- /dev/null +++ b/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml @@ -0,0 +1,205 @@ +version: 1 +name: sce-atomic-commit-result + +description: > + Output contract for sce-atomic-commit. The skill returns exactly one YAML + document representing proposal, bypass_message, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be proposal, bypass_message, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. + - Return proposal only in regular mode, and bypass_message only in bypass + mode. blocked is valid in both. + - Every staged file must appear under exactly one commit's files. + - Report file paths exactly as `git diff --cached --name-only` reports them. + - Carry the message body inside message, separated from the subject by one + blank line. Do not split it into a separate field. + - Do not include a commit hash. This skill never commits. + - Do not report guidance the mode forbids. + +variants: + + proposal: + meaning: > + The staged changes were analyzed in regular mode and one or more atomic + commit messages were written. Proposal-only: nothing was committed. + + required_fields: + - status + - mode + - commits + + optional_fields: + - split_rationale + - scope_classification + - notes + + field_rules: + - Include split_rationale only when commits holds more than one entry. + - scope_classification reports the context-file guidance gate as + context_only or mixed. + + shape: + status: proposal + mode: regular + + commits: + - id: string + message: string + files: + - string + cites_plan: boolean + + split_rationale: string + scope_classification: context_only | mixed + + notes: + - string + + example: + status: proposal + mode: regular + + commits: + - id: C01 + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full + re-login. Adds the refresh handler and reuses the existing token + issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + - id: C02 + + message: | + build: Pin the formatter to the toolchain version + + The formatter floated across environments and produced diff noise + unrelated to any change. + + files: + - flake.nix + + cites_plan: false + + split_rationale: > + The refresh endpoint and the formatter pin pursue unrelated goals and + share no files. Committing them together would hide the build change + behind a feature subject. + + scope_classification: mixed + + bypass_message: + meaning: > + The staged changes were analyzed in bypass mode and exactly one commit + message covering all staged files was written. The invoking workflow + executes the commit. + + required_fields: + - status + - mode + - message + - files + + optional_fields: + - cites_plan + - notes + + field_rules: + - files lists every staged file, because one message covers all of them. + - Never include commits, split_rationale, or scope_classification. + + shape: + status: bypass_message + mode: bypass + + message: string + + files: + - string + + cites_plan: boolean + + notes: + - string + + example: + status: bypass_message + mode: bypass + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full re-login. + Adds the refresh handler and reuses the existing token issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + blocked: + meaning: > + Faithful commit messages cannot be written from the staged changes. + + required_fields: + - status + - issues + + optional_fields: + - mode + - files + + field_rules: + - Include mode whenever the workflow supplied one. + - Include files when staged files were read before blocking. + - Plan-citation ambiguity blocks in regular mode only. In bypass mode the + citation is omitted instead. + + shape: + status: blocked + mode: regular | bypass + + files: + - string + + issues: + - id: string + category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context + problem: string + impact: string + decision_required: string + + example: + status: blocked + mode: regular + + files: + - context/plans/authentication.md + + issues: + - id: B01 + category: plan_citation_ambiguity + + problem: > + The staged plan diff changes two task checkboxes and does not + expose which task this commit completes. + + impact: > + The commit body would cite a task ID the staged diff does not + support. + + decision_required: > + State the completed task ID, or stage only that task's plan edit. diff --git a/.opencode/skills/sce-atomic-commit/references/commit-message-style.md b/.opencode/skills/sce-atomic-commit/references/commit-message-style.md new file mode 100644 index 00000000..7a1b5084 --- /dev/null +++ b/.opencode/skills/sce-atomic-commit/references/commit-message-style.md @@ -0,0 +1,63 @@ +# Commit message style + +The wording rules for every message `sce-atomic-commit` returns, in either +mode. This file is the only authority for message content and shape. + +Messages are carried in the result's `message` field, subject first, then one +blank line, then the body. + +## Subject + +Pattern: + +`: ` + +- Scope is the smallest stable subsystem or module name recognizable in the + repository. When no such name applies, use the primary directory or package + of the change. +- Start the summary with an imperative verb: Fix, Add, Remove, Implement, + Refactor, Simplify, Rename, Update, Ensure, Allow. +- Capitalize the verb. Do not end the subject with a period. +- Keep it concrete and technical. Name what changed, not how it felt. + +## Body + +Include a body whenever the subject alone leaves the change unexplained. Omit +it for changes whose subject is self-evident. + +A body says what was wrong or missing, why it mattered, what changed +conceptually, and the impact. It does not restate the subject in longer words, +and it does not narrate the editing process. + +Wrap the body at a readable width and separate paragraphs with a blank line. + +## Issue references + +Put each issue reference on its own line at the end of the body, for example +`Fixes #123`. + +Reference only issues the staged diff or the supplied commit context names. Do +not infer an issue number from a branch name. + +## Plan citations + +When a commit's staged files include `context/plans/*.md`, the body must also +cite: + +- The affected plan slug. +- Every updated task ID (`T0X`). + +Cite only what the staged plan diff shows. When the diff does not expose the +slug or task IDs clearly enough to cite faithfully, the skill's mode decides +what happens — the ambiguity is not resolved here by guessing. + +## Anti-patterns + +- Vague subjects: "cleanup", "updates", "various fixes". +- A body that repeats the subject without adding why or impact. +- Playful tone in a fix, security change, or architectural change. +- Mentioning `context/` synchronization activity. +- Inventing plan slugs, task IDs, or issue references. +- Splitting changes that already form one coherent unit. +- Forcing unrelated goals into a single commit. +- Describing intent the staged diff does not support. diff --git a/.pi/prompts/commit.md b/.pi/prompts/commit.md new file mode 100644 index 00000000..85ece4bd --- /dev/null +++ b/.pi/prompts/commit.md @@ -0,0 +1,130 @@ +--- +description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" +--- + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; `sce-atomic-commit` owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the +commit context. + +`sce-atomic-commit` exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of `sce-atomic-commit`. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when `sce-atomic-commit` returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. diff --git a/.pi/skills/sce-atomic-commit/SKILL.md b/.pi/skills/sce-atomic-commit/SKILL.md new file mode 100644 index 00000000..1ddda9e5 --- /dev/null +++ b/.pi/skills/sce-atomic-commit/SKILL.md @@ -0,0 +1,166 @@ +--- +name: sce-atomic-commit +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one YAML + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. +--- + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Returning one terminal YAML result. + +Write messages matching: + +`references/commit-message-style.md` + +Return a result matching: + +`references/commit-contract.yaml` + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Return `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/commit-message-style.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, return `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return YAML + +Return exactly one YAML document matching `references/commit-contract.yaml`: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Return only the YAML document. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal YAML result matching `references/commit-contract.yaml` was + returned. diff --git a/.pi/skills/sce-atomic-commit/references/commit-contract.yaml b/.pi/skills/sce-atomic-commit/references/commit-contract.yaml new file mode 100644 index 00000000..5ffdd9ff --- /dev/null +++ b/.pi/skills/sce-atomic-commit/references/commit-contract.yaml @@ -0,0 +1,205 @@ +version: 1 +name: sce-atomic-commit-result + +description: > + Output contract for sce-atomic-commit. The skill returns exactly one YAML + document representing proposal, bypass_message, or blocked. + +output_rules: + - Return exactly one result variant. + - The top-level status must be proposal, bypass_message, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. + - Return proposal only in regular mode, and bypass_message only in bypass + mode. blocked is valid in both. + - Every staged file must appear under exactly one commit's files. + - Report file paths exactly as `git diff --cached --name-only` reports them. + - Carry the message body inside message, separated from the subject by one + blank line. Do not split it into a separate field. + - Do not include a commit hash. This skill never commits. + - Do not report guidance the mode forbids. + +variants: + + proposal: + meaning: > + The staged changes were analyzed in regular mode and one or more atomic + commit messages were written. Proposal-only: nothing was committed. + + required_fields: + - status + - mode + - commits + + optional_fields: + - split_rationale + - scope_classification + - notes + + field_rules: + - Include split_rationale only when commits holds more than one entry. + - scope_classification reports the context-file guidance gate as + context_only or mixed. + + shape: + status: proposal + mode: regular + + commits: + - id: string + message: string + files: + - string + cites_plan: boolean + + split_rationale: string + scope_classification: context_only | mixed + + notes: + - string + + example: + status: proposal + mode: regular + + commits: + - id: C01 + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full + re-login. Adds the refresh handler and reuses the existing token + issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + - id: C02 + + message: | + build: Pin the formatter to the toolchain version + + The formatter floated across environments and produced diff noise + unrelated to any change. + + files: + - flake.nix + + cites_plan: false + + split_rationale: > + The refresh endpoint and the formatter pin pursue unrelated goals and + share no files. Committing them together would hide the build change + behind a feature subject. + + scope_classification: mixed + + bypass_message: + meaning: > + The staged changes were analyzed in bypass mode and exactly one commit + message covering all staged files was written. The invoking workflow + executes the commit. + + required_fields: + - status + - mode + - message + - files + + optional_fields: + - cites_plan + - notes + + field_rules: + - files lists every staged file, because one message covers all of them. + - Never include commits, split_rationale, or scope_classification. + + shape: + status: bypass_message + mode: bypass + + message: string + + files: + - string + + cites_plan: boolean + + notes: + - string + + example: + status: bypass_message + mode: bypass + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full re-login. + Adds the refresh handler and reuses the existing token issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + blocked: + meaning: > + Faithful commit messages cannot be written from the staged changes. + + required_fields: + - status + - issues + + optional_fields: + - mode + - files + + field_rules: + - Include mode whenever the workflow supplied one. + - Include files when staged files were read before blocking. + - Plan-citation ambiguity blocks in regular mode only. In bypass mode the + citation is omitted instead. + + shape: + status: blocked + mode: regular | bypass + + files: + - string + + issues: + - id: string + category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context + problem: string + impact: string + decision_required: string + + example: + status: blocked + mode: regular + + files: + - context/plans/authentication.md + + issues: + - id: B01 + category: plan_citation_ambiguity + + problem: > + The staged plan diff changes two task checkboxes and does not + expose which task this commit completes. + + impact: > + The commit body would cite a task ID the staged diff does not + support. + + decision_required: > + State the completed task ID, or stage only that task's plan edit. diff --git a/.pi/skills/sce-atomic-commit/references/commit-message-style.md b/.pi/skills/sce-atomic-commit/references/commit-message-style.md new file mode 100644 index 00000000..7a1b5084 --- /dev/null +++ b/.pi/skills/sce-atomic-commit/references/commit-message-style.md @@ -0,0 +1,63 @@ +# Commit message style + +The wording rules for every message `sce-atomic-commit` returns, in either +mode. This file is the only authority for message content and shape. + +Messages are carried in the result's `message` field, subject first, then one +blank line, then the body. + +## Subject + +Pattern: + +`: ` + +- Scope is the smallest stable subsystem or module name recognizable in the + repository. When no such name applies, use the primary directory or package + of the change. +- Start the summary with an imperative verb: Fix, Add, Remove, Implement, + Refactor, Simplify, Rename, Update, Ensure, Allow. +- Capitalize the verb. Do not end the subject with a period. +- Keep it concrete and technical. Name what changed, not how it felt. + +## Body + +Include a body whenever the subject alone leaves the change unexplained. Omit +it for changes whose subject is self-evident. + +A body says what was wrong or missing, why it mattered, what changed +conceptually, and the impact. It does not restate the subject in longer words, +and it does not narrate the editing process. + +Wrap the body at a readable width and separate paragraphs with a blank line. + +## Issue references + +Put each issue reference on its own line at the end of the body, for example +`Fixes #123`. + +Reference only issues the staged diff or the supplied commit context names. Do +not infer an issue number from a branch name. + +## Plan citations + +When a commit's staged files include `context/plans/*.md`, the body must also +cite: + +- The affected plan slug. +- Every updated task ID (`T0X`). + +Cite only what the staged plan diff shows. When the diff does not expose the +slug or task IDs clearly enough to cite faithfully, the skill's mode decides +what happens — the ambiguity is not resolved here by guessing. + +## Anti-patterns + +- Vague subjects: "cleanup", "updates", "various fixes". +- A body that repeats the subject without adding why or impact. +- Playful tone in a fix, security change, or architectural change. +- Mentioning `context/` synchronization activity. +- Inventing plan slugs, task IDs, or issue references. +- Splitting changes that already form one coherent unit. +- Forcing unrelated goals into a single commit. +- Describing intent the staged diff does not support. diff --git a/config/pkl/README.md b/config/pkl/README.md index 5dae64ad..ae3a7387 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -1,6 +1,6 @@ # Pkl Generation Workflow -Canonical generation pipeline for the three SCE workflows across OpenCode, Claude, and Pi. +Canonical generation pipeline for the four SCE workflows across OpenCode, Claude, and Pi. ## Ownership and target matrix @@ -9,6 +9,7 @@ Author workflow behavior in: - `config/pkl/base/workflow-change-to-plan.pkl` - `config/pkl/base/workflow-next-task.pkl` - `config/pkl/base/workflow-validate.pkl` +- `config/pkl/base/workflow-commit.pkl` - `config/pkl/base/workflow-content.pkl` for command and self-contained skill-package types - `config/pkl/base/workflow-context-sync.pkl` for the shared task/plan synchronization skeleton @@ -18,14 +19,14 @@ Apply target-specific rendering and supported metadata under `config/pkl/rendere | Target | Workflow Markdown | Retained non-Markdown | | --- | --- | --- | -| OpenCode | Three commands, seven self-contained skill packages, two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | -| Claude | Three commands and seven self-contained skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | -| Pi | Three prompts and seven self-contained skill packages; no agent-role prompts | `extensions/sce/index.ts` | +| OpenCode | Four commands, eight self-contained skill packages, two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | +| Claude | Four commands and eight self-contained skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | +| Pi | Four prompts and eight self-contained skill packages; no agent-role prompts | `extensions/sce/index.ts` | | SCE config | None | `config/schema/sce-config.schema.json` | Each skill package includes its package-local `SKILL.md` and any nested `references/` documents. Generated skill trees must remain self-contained; a generated skill must not depend on a sibling skill package. -The automated OpenCode profile, generated `/commit` and `/handover` commands, legacy bootstrap/commit/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. +The automated OpenCode profile, the generated `/handover` command, legacy bootstrap/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. Not generated by this pipeline: dependency artifacts such as `node_modules`, lockfiles, install outputs, and manifests outside the paths above. @@ -68,7 +69,7 @@ nix run .#pkl-check-generated The check: - rejects committed `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, and `cli/assets/generated` outputs; -- evaluates `metadata-coverage-check.pkl` for the exact three-command, seven-skill-package, nested-reference, and two-agent OpenCode inventory; +- evaluates `metadata-coverage-check.pkl` for the exact four-command, eight-skill-package, nested-reference, and two-agent OpenCode inventory; - generates twice into temporary directories and compares sorted SHA-256 inventories; - requires all generated target roots and the SCE config schema while rejecting removed surfaces such as `config/automated/.opencode` and `config/.claude/agents`; - prints the stable inventory count and digest without preserving generated files. @@ -88,7 +89,7 @@ Pkl dependencies are vendored under `config/pkl/deps/` for Nix sandbox compatibi **`pkl: command not found`** — Run the documented commands through `nix develop -c`. -**Inventory check failure** — Compare the three workflow modules and renderer output mappings with the expected commands, agents, skill entrypoints, and package-local reference paths in `metadata-coverage-check.pkl`. +**Inventory check failure** — Compare the four workflow modules and renderer output mappings with the expected commands, agents, skill entrypoints, and package-local reference paths in `metadata-coverage-check.pkl`. **Nondeterministic output** — Generate twice into separate temporary directories, compare their inventories, and correct the canonical Pkl or renderer input responsible for the difference. diff --git a/config/pkl/base/workflow-commit.pkl b/config/pkl/base/workflow-commit.pkl new file mode 100644 index 00000000..334ee98b --- /dev/null +++ b/config/pkl/base/workflow-commit.pkl @@ -0,0 +1,611 @@ +import "workflow-content.pkl" as model + +/// Canonical `/commit` workflow command and its self-contained skill package. +/// Text mirrors the project-root `.pi/` behavioral baseline; target renderers +/// consume this model in later workflow-rendering tasks. + +local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { + path = documentPath + text = documentText +} + +local packageDocuments = (documents: Listing) -> new Mapping { + for (item in documents) { + [item.path] = item + } +} + +local atomicCommitPackage = new model.SkillPackage { + slug = "sce-atomic-commit" + title = "SCE Atomic Commit" + documents = packageDocuments.apply(new Listing { + makeDocument.apply("SKILL.md", ATOMIC_COMMIT_SKILL) + makeDocument.apply("references/commit-contract.yaml", COMMIT_CONTRACT) + makeDocument.apply("references/commit-message-style.md", COMMIT_MESSAGE_STYLE) + }) +} + +local COMMAND = """ + --- + description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" + argument-hint: "[oneshot|skip] [commit context]" + --- + + SCE COMMIT `$ARGUMENTS` + + ## Input + + `$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + + `[mode-token] [commit context]` + + - `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. + - `commit context` is everything else: free-form prose that refines message + wording only. + + A `mode-token` selects the bypass path. Its absence selects the regular path. + Do not infer the bypass path from anything else — not from the commit context, + not from repository state, and not from the conversation. + + Empty `$ARGUMENTS` is valid. It selects the regular path with no commit + context, and commit intent is inferred from the staged changes alone. + + Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, + summarize, or pre-scope it. Never pass the `mode-token` as commit context. + + Staged changes are the source of truth for what is being committed. This + command never stages, unstages, or modifies files. + + ## Workflow + + Follow exactly one path. + + ### Bypass path (`oneshot` or `skip`) + + #### 1. Validate that staged content exists + + Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + + When nothing is staged, stop with exactly: + + `No staged changes. Stage changes before commit.` + + Do not stage anything. Do not proceed to the skill. + + #### 2. Request one commit message + + Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. + + Bypass mode is the skill's contract for producing exactly one message. Do not + restate its overrides here; `sce-atomic-commit` owns them. + + The skill must return a result matching its commit contract. Branch on + `status`: + + `blocked` -> Present the issue and stop. Do not commit. + + `bypass_message` -> Continue to the next step. + + The skill never returns `proposal` in bypass mode. Treat a `proposal` result as + a contract violation: report it and stop without committing. + + #### 3. Execute exactly one commit + + Run `git commit` once with the returned message. + + On success, report the resulting commit hash and stop. + + On failure, report the failure as returned by Git and stop. Do not retry, do + not amend, do not stage additional files, and do not invent a fallback commit. + + ### Regular path (no mode token) + + #### 1. Confirm staging + + Before invoking the skill, stop and prompt the user: + + ``` + Please run `git add ` for all changes you want included in this commit. + Atomic commits should only include intentionally staged changes. + Confirm once staging is complete. + ``` + + Wait for the user's confirmation. Do not stage files on their behalf, and do + not skip this prompt because the working tree looks ready. + + #### 2. Propose commits + + After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the + commit context. + + `sce-atomic-commit` exclusively owns: + + - Reading and analyzing the staged diff. + - Deciding whether staged changes form one coherent unit or several. + - Classifying staged scope and applying context-file guidance gating. + - Writing every commit message subject and body. + - Applying the plan-citation body rule. + + Do not duplicate any of it. Do not write commit messages yourself. + + The skill must return a result matching its commit contract. Branch on + `status`: + + `blocked` -> Present the issue and the decision it requires. Stop. + + `proposal` -> Present each proposed commit: its message, the files it covers, + and, when more than one commit is proposed, why the split is recommended. + + Then stop. The regular path is proposal-only. + + Do not run `git commit`. Do not offer to commit on the user's behalf. The user + runs the commits they accept. + + ## Rules + + - Produce at most one commit per invocation, and only on the bypass path. + - Never commit on the regular path. + - Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. + - Do not duplicate the internal instructions of `sce-atomic-commit`. + - Do not stage, unstage, restore, or otherwise modify files. + - Do not amend, reset, revert, rebase, or push. + - Do not read unstaged or untracked changes as commit input. + - Do not infer success when `sce-atomic-commit` returns a non-success status. + - Do not proceed past a failed `git commit`. + - Do not run plan, task, or validation workflows from this command. + """ +local ATOMIC_COMMIT_SKILL = """ + --- + name: sce-atomic-commit + description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one YAML + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. + --- + + # SCE Atomic Commit + + ## Purpose + + Turn the current staged changes into atomic repository-style commit messages. + + This skill owns: + + - Reading and analyzing the staged diff. + - Deciding whether staged changes form one coherent unit or several. + - Choosing the scope and writing the subject and body of every message. + - Applying the plan-citation body rule. + - Classifying staged scope and applying context-file guidance gating. + - Returning one terminal YAML result. + + Write messages matching: + + `references/commit-message-style.md` + + Return a result matching: + + `references/commit-contract.yaml` + + Committing is not this skill's job. The invoking `/commit` workflow decides + whether a returned message is committed, and it is the only thing that runs + `git commit`. + + ## Input + + The invoking workflow provides: + + - A mode: `regular` or `bypass`. + - Optional commit context, in free-form prose. + + The mode is supplied by the workflow from an explicit user-supplied token. + Never infer it, and never switch modes mid-analysis. + + Commit context refines wording only. The staged diff decides what the change + is; context never overrides staged truth, and never adds a claim the diff does + not support. + + Do not accept an unstaged diff, a working-tree summary, or a conversational + description as a substitute for the staged diff. + + ## Workflow + + ### 1. Read the staged diff + + Read the staged changes with `git diff --cached`, and the staged file list with + `git diff --cached --name-status`. + + Read staged file contents only when the diff alone does not explain the change. + + Return `blocked` when nothing is staged. + + ### 2. Identify coherent units + + Infer the main reason for the staged change from the diff first. + + A coherent unit is one goal a reviewer would accept as a single commit. Group + staged files by that goal, not by directory. + + In `bypass` mode, stop grouping here: the result is exactly one message + covering all staged files, whether or not the diff is coherent. Do not propose + splits, and do not report split guidance. + + ### 3. Choose a scope for each unit + + Use the smallest stable subsystem or module name recognizable in the repository. + + When no such name applies, use the primary directory or package of the unit's + changes. + + ### 4. Write each message + + Follow `references/commit-message-style.md` for the subject pattern, the body + rules, issue references, the plan-citation rule, and the anti-patterns. + + ### 5. Apply the plan-citation rule + + When the unit's staged files include `context/plans/*.md`, cite the affected + plan slug and updated task IDs in the body. + + When the staged plan diff does not expose the slug or task ID clearly enough to + cite faithfully: + + - In `regular` mode, return `blocked` and ask for the reference to be stated or + staged explicitly. + - In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + + ### 6. Apply context-file guidance gating + + This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do + not classify staged scope there. + + Classify the staged diff: + + - Context-only (`context/**`): context-file-focused guidance is allowed. + - Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + + ### 7. Propose split guidance + + This step applies in `regular` mode only. + + When the units found in step 2 pursue unrelated goals, return one message per + unit, and state why the split is recommended and which staged files belong to + each. + + When the staged changes form one unit, return one message and no split + guidance. Do not split coherent work to appear thorough. + + ### 8. Validate the result + + Confirm before returning that: + + - Every message describes its unit faithfully and covers only that unit's files. + - Every staged file belongs to exactly one returned message. + - No plan slug or task ID appears that the staged diff does not support. + - The mode's own constraints hold. + + ### 9. Return YAML + + Return exactly one YAML document matching `references/commit-contract.yaml`: + + - `proposal` in `regular` mode, with one or more messages. + - `bypass_message` in `bypass` mode, with exactly one message. + - `blocked` when messages cannot be written faithfully. + + Return only the YAML document. Do not add explanatory prose before or after it. + + ## Boundaries + + Do not: + + - Run `git commit`, or any command that writes to the repository or its index. + - Stage, unstage, or modify files. + - Ask the user to stage or confirm staging. + - Analyze unstaged or untracked changes. + - Return more than one message in `bypass` mode. + - Return split guidance in `bypass` mode. + - Stop for plan-citation ambiguity in `bypass` mode. + - Invent plan slugs, task IDs, or issue references. + - Mention `context/` synchronization activity in a commit message. + - Claim a message was committed. + - Run plan, task, or validation workflows. + + ## Completion + + The skill is complete after: + + - The staged diff was read, or reading it failed and was reported. + - Messages were written for every staged file, or a blocker prevented it. + - One valid terminal YAML result matching `references/commit-contract.yaml` was + returned. + """ +local COMMIT_CONTRACT = """ + version: 1 + name: sce-atomic-commit-result + + description: > + Output contract for sce-atomic-commit. The skill returns exactly one YAML + document representing proposal, bypass_message, or blocked. + + output_rules: + - Return exactly one result variant. + - The top-level status must be proposal, bypass_message, or blocked. + - Return YAML only, without a Markdown code fence or explanatory prose. + - Include only fields belonging to the selected variant. + - Omit optional fields that do not apply rather than sending them empty. + - Do not return empty strings or null placeholders. + - Return proposal only in regular mode, and bypass_message only in bypass + mode. blocked is valid in both. + - Every staged file must appear under exactly one commit's files. + - Report file paths exactly as `git diff --cached --name-only` reports them. + - Carry the message body inside message, separated from the subject by one + blank line. Do not split it into a separate field. + - Do not include a commit hash. This skill never commits. + - Do not report guidance the mode forbids. + + variants: + + proposal: + meaning: > + The staged changes were analyzed in regular mode and one or more atomic + commit messages were written. Proposal-only: nothing was committed. + + required_fields: + - status + - mode + - commits + + optional_fields: + - split_rationale + - scope_classification + - notes + + field_rules: + - Include split_rationale only when commits holds more than one entry. + - scope_classification reports the context-file guidance gate as + context_only or mixed. + + shape: + status: proposal + mode: regular + + commits: + - id: string + message: string + files: + - string + cites_plan: boolean + + split_rationale: string + scope_classification: context_only | mixed + + notes: + - string + + example: + status: proposal + mode: regular + + commits: + - id: C01 + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full + re-login. Adds the refresh handler and reuses the existing token + issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + - id: C02 + + message: | + build: Pin the formatter to the toolchain version + + The formatter floated across environments and produced diff noise + unrelated to any change. + + files: + - flake.nix + + cites_plan: false + + split_rationale: > + The refresh endpoint and the formatter pin pursue unrelated goals and + share no files. Committing them together would hide the build change + behind a feature subject. + + scope_classification: mixed + + bypass_message: + meaning: > + The staged changes were analyzed in bypass mode and exactly one commit + message covering all staged files was written. The invoking workflow + executes the commit. + + required_fields: + - status + - mode + - message + - files + + optional_fields: + - cites_plan + - notes + + field_rules: + - files lists every staged file, because one message covers all of them. + - Never include commits, split_rationale, or scope_classification. + + shape: + status: bypass_message + mode: bypass + + message: string + + files: + - string + + cites_plan: boolean + + notes: + - string + + example: + status: bypass_message + mode: bypass + + message: | + auth: Add token refresh endpoint + + Sessions expired without a way to renew them, forcing a full re-login. + Adds the refresh handler and reuses the existing token issuer. + + files: + - src/auth/refresh.ts + - tests/auth/refresh.test.ts + + cites_plan: false + + blocked: + meaning: > + Faithful commit messages cannot be written from the staged changes. + + required_fields: + - status + - issues + + optional_fields: + - mode + - files + + field_rules: + - Include mode whenever the workflow supplied one. + - Include files when staged files were read before blocking. + - Plan-citation ambiguity blocks in regular mode only. In bypass mode the + citation is omitted instead. + + shape: + status: blocked + mode: regular | bypass + + files: + - string + + issues: + - id: string + category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context + problem: string + impact: string + decision_required: string + + example: + status: blocked + mode: regular + + files: + - context/plans/authentication.md + + issues: + - id: B01 + category: plan_citation_ambiguity + + problem: > + The staged plan diff changes two task checkboxes and does not + expose which task this commit completes. + + impact: > + The commit body would cite a task ID the staged diff does not + support. + + decision_required: > + State the completed task ID, or stage only that task's plan edit. + """ +local COMMIT_MESSAGE_STYLE = """ + # Commit message style + + The wording rules for every message `sce-atomic-commit` returns, in either + mode. This file is the only authority for message content and shape. + + Messages are carried in the result's `message` field, subject first, then one + blank line, then the body. + + ## Subject + + Pattern: + + `: ` + + - Scope is the smallest stable subsystem or module name recognizable in the + repository. When no such name applies, use the primary directory or package + of the change. + - Start the summary with an imperative verb: Fix, Add, Remove, Implement, + Refactor, Simplify, Rename, Update, Ensure, Allow. + - Capitalize the verb. Do not end the subject with a period. + - Keep it concrete and technical. Name what changed, not how it felt. + + ## Body + + Include a body whenever the subject alone leaves the change unexplained. Omit + it for changes whose subject is self-evident. + + A body says what was wrong or missing, why it mattered, what changed + conceptually, and the impact. It does not restate the subject in longer words, + and it does not narrate the editing process. + + Wrap the body at a readable width and separate paragraphs with a blank line. + + ## Issue references + + Put each issue reference on its own line at the end of the body, for example + `Fixes #123`. + + Reference only issues the staged diff or the supplied commit context names. Do + not infer an issue number from a branch name. + + ## Plan citations + + When a commit's staged files include `context/plans/*.md`, the body must also + cite: + + - The affected plan slug. + - Every updated task ID (`T0X`). + + Cite only what the staged plan diff shows. When the diff does not expose the + slug or task IDs clearly enough to cite faithfully, the skill's mode decides + what happens — the ambiguity is not resolved here by guessing. + + ## Anti-patterns + + - Vague subjects: "cleanup", "updates", "various fixes". + - A body that repeats the subject without adding why or impact. + - Playful tone in a fix, security change, or architectural change. + - Mentioning `context/` synchronization activity. + - Inventing plan slugs, task IDs, or issue references. + - Splitting changes that already form one coherent unit. + - Forcing unrelated goals into a single commit. + - Describing intent the staged diff does not support. + """ + +workflow = new model.WorkflowPackage { + slug = "commit" + command = new model.WorkflowCommand { + slug = "commit" + title = "SCE Commit" + document = makeDocument.apply("commit.md", COMMAND) + } + skills = new Mapping { + [atomicCommitPackage.slug] = atomicCommitPackage + } +} diff --git a/config/pkl/renderers/claude-content.pkl b/config/pkl/renderers/claude-content.pkl index c5f22383..f5725717 100644 --- a/config/pkl/renderers/claude-content.pkl +++ b/config/pkl/renderers/claude-content.pkl @@ -1,6 +1,7 @@ import "../base/workflow-change-to-plan.pkl" as changeToPlan import "../base/workflow-next-task.pkl" as nextTask import "../base/workflow-validate.pkl" as validate +import "../base/workflow-commit.pkl" as commit import "../base/workflow-content.pkl" as model import "common.pkl" as common import "claude-metadata.pkl" as metadata @@ -15,6 +16,7 @@ local workflows = new Listing { changeToPlan.workflow nextTask.workflow validate.workflow + commit.workflow } local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { diff --git a/config/pkl/renderers/claude-metadata.pkl b/config/pkl/renderers/claude-metadata.pkl index b93653c5..52684fc2 100644 --- a/config/pkl/renderers/claude-metadata.pkl +++ b/config/pkl/renderers/claude-metadata.pkl @@ -2,6 +2,7 @@ commandAllowedTools = new Mapping { ["next-task"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" ["change-to-plan"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" ["validate"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" + ["commit"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" } skillCompatibility = "claude" diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index d9f93a55..5e365e93 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -5,7 +5,8 @@ import "pi-content.pkl" as pi local expectedCommandSlugs = Set( "change-to-plan", "next-task", - "validate" + "validate", + "commit" ) local expectedAgentSlugs = Set( @@ -14,6 +15,9 @@ local expectedAgentSlugs = Set( ) local expectedSkillDocumentPaths = Set( + "sce-atomic-commit/SKILL.md", + "sce-atomic-commit/references/commit-contract.yaml", + "sce-atomic-commit/references/commit-message-style.md", "sce-context-load/SKILL.md", "sce-context-load/references/context-brief.yaml", "sce-plan-authoring/SKILL.md", diff --git a/config/pkl/renderers/opencode-content.pkl b/config/pkl/renderers/opencode-content.pkl index 95011076..cbfd0299 100644 --- a/config/pkl/renderers/opencode-content.pkl +++ b/config/pkl/renderers/opencode-content.pkl @@ -1,6 +1,7 @@ import "../base/workflow-change-to-plan.pkl" as changeToPlan import "../base/workflow-next-task.pkl" as nextTask import "../base/workflow-validate.pkl" as validate +import "../base/workflow-commit.pkl" as commit import "../base/workflow-content.pkl" as model import "common.pkl" as common import "opencode-metadata.pkl" as metadata @@ -11,12 +12,15 @@ local workflows = new Listing { changeToPlan.workflow nextTask.workflow validate.workflow + commit.workflow } +/// Commands routed by a thin agent declare it here. local commandAgentBySlug = new Mapping { ["change-to-plan"] = "Shared Context Plan" ["next-task"] = "Shared Context Code" ["validate"] = "Shared Context Code" + ["commit"] = "Shared Context Code" } local commandSkillMetadataBySlug = new Mapping { @@ -38,14 +42,22 @@ entry-skill: "sce-validation" skills: - "sce-validation" - "sce-plan-context-sync" +""" + ["commit"] = """ +entry-skill: "sce-atomic-commit" +skills: + - "sce-atomic-commit" """ } +local commandAgentLine = (slug: String) -> + if (commandAgentBySlug.containsKey(slug)) "agent: \"\(commandAgentBySlug[slug])\"\n" else "" + local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { path = command.document.path text = command.document.text.replaceFirst( "\n---\n", - "\nagent: \"\(commandAgentBySlug[command.slug])\"\n\(commandSkillMetadataBySlug[command.slug])\n---\n" + "\n\(commandAgentLine.apply(command.slug))\(commandSkillMetadataBySlug[command.slug])\n---\n" ) } diff --git a/config/pkl/renderers/pi-content.pkl b/config/pkl/renderers/pi-content.pkl index 09874f3f..7af64a01 100644 --- a/config/pkl/renderers/pi-content.pkl +++ b/config/pkl/renderers/pi-content.pkl @@ -1,6 +1,7 @@ import "../base/workflow-change-to-plan.pkl" as changeToPlan import "../base/workflow-next-task.pkl" as nextTask import "../base/workflow-validate.pkl" as validate +import "../base/workflow-commit.pkl" as commit /// Pi consumes the canonical workflow documents directly because those /// documents are authored against the project-root `.pi/` baseline. @@ -8,6 +9,7 @@ local workflows = new Listing { changeToPlan.workflow nextTask.workflow validate.workflow + commit.workflow } commands { diff --git a/context/context-map.md b/context/context-map.md index 3c1572a5..6e5c0169 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -27,6 +27,7 @@ Feature/domain context: - [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) - `context/sce/plan-code-overlap-map.md` (current overlap matrix for thin OpenCode Plan/Code routing agents, the three workflow commands, and their phase-skill ownership boundaries) - `context/sce/dedup-ownership-table.md` (current canonical owner-vs-consumer matrix for the three workflow packages, seven phase skills, shared sync skeleton, and thin OpenCode agents) +- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, command-vs-`sce-atomic-commit` ownership boundary, staged-truth rule, plan-citation rule, and result contract; currently a project-root `.pi/` baseline only, not yet canonical Pkl or generated) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) diff --git a/context/glossary.md b/context/glossary.md index dbcdc173..2ddd57d8 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -9,6 +9,7 @@ - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, and `/validate` this way and has no generated agent-role prompts. +- `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. - `repository identity`: Stable identity of a logical Git repository used to select the active repository-scoped Agent Trace DB path `/sce/repos//agent-trace.db` through the `agent_trace_storage` resolver. Resolved by `cli/src/services/repository_identity/` with precedence: explicit `agent_trace.repository_id` config value, then the URL of the configured Git remote (`agent_trace.repository_remote`, default `origin`), otherwise an actionable `.sce/config.json` error. Remote URLs canonicalize to a scheme-neutral, credential-free `host[:port]/path` form so equivalent SSH/SCP/HTTPS remotes converge, and the repository ID is `sha256("sce-repository-id-v1\0" + canonical_identity)` hex. Distinct from `checkout identity`, which stays per clone/worktree for diagnostics. See `context/cli/repository-identity.md`. diff --git a/context/plans/commit-workflow.md b/context/plans/commit-workflow.md new file mode 100644 index 00000000..bf931c22 --- /dev/null +++ b/context/plans/commit-workflow.md @@ -0,0 +1,125 @@ +# Plan: commit-workflow + +## Change summary + +Restore `/commit` as a fourth canonical SCE workflow, modernized to the current command-plus-self-contained-skill package model. The workflow will preserve the old regular proposal path and `oneshot`/`skip` bypass behavior while giving the command and `sce-atomic-commit` skill an explicit ownership boundary and structured result contract. + +The project-root `.pi/` package will remain the behavioral baseline, canonical Pkl will mirror it, and the OpenCode, Claude, and Pi renderers will emit the workflow with target-supported metadata. No new routing agent or Rust CLI behavior is introduced. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: The project-root `.pi/` surface contains a `/commit` prompt and self-contained `sce-atomic-commit` package whose regular mode requires staging confirmation, analyzes staged truth, returns atomic proposal and split guidance without committing, and preserves the plan-citation and context-guidance rules from the supplied workflow. + - Validate: inspect `.pi/prompts/commit.md`, `.pi/skills/sce-atomic-commit/SKILL.md`, and every package-local reference named by the skill; confirm the regular-mode branch and structured result variants are complete and internally consistent. +- [x] AC2: `/commit oneshot` and `/commit skip` validate that staged content exists, request exactly one best-effort commit message without split/context gates, execute exactly one `git commit`, and report either the resulting commit hash or the unretried commit failure. + - Validate: inspect the generated Pi prompt and skill package for exact first-token, case-insensitive bypass routing, the `No staged changes. Stage changes before commit.` stop, single-message handoff, best-effort plan citations, and success/failure termination rules. +- [x] AC3: OpenCode, Claude, and Pi generated payloads each contain the `/commit` command and one complete `sce-atomic-commit` package with all local references and target-supported metadata, while the existing three workflows remain unchanged and no new agent is generated. + - Validate: generate a temporary payload with `nix run .#pkl-generate -- "$(mktemp -d)"`; inspect each target inventory and compare the generated Pi commit command/skill package with the project-root `.pi/` baseline. +- [x] AC4: The canonical generator and metadata coverage enforce an exact four-command/eight-skill workflow inventory, including the new package references, and generation remains deterministic. + - Validate: `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/context-map.md`, `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` where their exact three-workflow/seven-skill inventory or workflow-package terminology changes. +- Add focused durable context for the restored atomic commit workflow and update `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (or a superseding decision) to record why `/commit` is restored after its earlier removal. + +## Constraints and non-goals + +- **In scope:** Project-root `.pi/` commit prompt and self-contained skill package; a canonical `workflow-commit.pkl` package; OpenCode, Claude, and Pi renderer metadata/wiring; generator and exact-inventory coverage updates. +- **Out of scope:** Rust CLI changes, Git hook behavior, a new OpenCode routing agent, restoration of `/handover` or the automated OpenCode profile, and compatibility generated trees. +- **Constraints:** Preserve the supplied regular and bypass semantics; keep staged changes as the source of truth; keep commands thin and the skill responsible for diff analysis, atomicity, and message wording; follow the current self-contained package/reference and ephemeral-generation architecture; use Nix-managed validation. +- **Non-goal:** Generalize this work into an arbitrary Git workflow engine or change the existing `/change-to-plan`, `/next-task`, or `/validate` lifecycle semantics. + +## Assumptions + +- “Modernize it to look and format like current ones” means adding `/commit` to the same project-root `.pi/` baseline and canonical cross-target Pkl workflow model used by the existing three workflows. +- The restored workflow is available directly as a command on all three targets and does not belong to either thin OpenCode Plan/Code routing agent. +- A package-local structured result contract will distinguish regular proposals, bypass single-message readiness, and blocked analysis; the command remains responsible for user prompting and `git commit` execution. +- The aliases `oneshot` and `skip` remain behaviorally identical and are recognized only as the case-insensitive first argument token. + +## Task stack + +- [x] T01: `Define the modern commit workflow baseline` (status:done) + - Task ID: T01 + - Goal: Add the project-root `.pi/` `/commit` command and self-contained `sce-atomic-commit` skill package in the same orchestration/result-contract style as current workflows while preserving the supplied regular and bypass behavior. + - Boundaries (in/out of scope): In — `.pi/prompts/commit.md`, `.pi/skills/sce-atomic-commit/SKILL.md`, and package-local result/reference documents needed for a structured command-to-skill handoff. Out — Pkl sources, generated payload wiring, durable context updates, and Git execution during implementation. + - Dependencies: none + - Done when: The command has explicit input and regular/bypass branches; command-vs-skill ownership is non-duplicative; the skill analyzes only staged truth and returns contract-valid proposal, bypass-message, or blocked results; regular mode remains proposal-only; bypass mode permits one command-owned commit; all skill references resolve within the package. + - Verification notes (commands or checks): `git diff --check -- .pi/prompts/commit.md .pi/skills/sce-atomic-commit`; inspect the command, skill, and result contract together for every supplied regular/bypass rule and package-local reference. + - Completed: 2026-07-28 + - Files changed: `.pi/prompts/commit.md`, `.pi/skills/sce-atomic-commit/SKILL.md`, `.pi/skills/sce-atomic-commit/references/commit-contract.yaml`, `.pi/skills/sce-atomic-commit/references/commit-message-style.md` (all new). + - Evidence: Recovered the behavioral baseline from `git show 2a947b2^:.pi/prompts/commit.md` and `git show 2a947b2^:.pi/skills/sce-atomic-commit/SKILL.md`, then re-authored it in the current command-plus-self-contained-skill style modeled on `.pi/prompts/validate.md`, `.pi/skills/sce-validation/SKILL.md`, and `.pi/skills/sce-plan-review/references/readiness-contract.yaml`. `git add -N` + `git diff --check -- .pi/prompts/commit.md .pi/skills/sce-atomic-commit` -> exit 0 (index restored afterwards with `git reset`). `nix run nixpkgs#yq -- '.variants | keys' .pi/skills/sce-atomic-commit/references/commit-contract.yaml` -> exit 0, reporting `blocked`, `bypass_message`, `proposal`. Both references named by the skill resolve inside the package (`ls -R .pi/skills/sce-atomic-commit`). Cross-read confirms every supplied rule: exact case-insensitive first-token `oneshot`/`skip` routing, the `No staged changes. Stage changes before commit.` stop, the verbatim staging-confirmation prompt, skipped context gate and single best-effort message in bypass mode, one command-owned `git commit` reporting the hash or the unretried failure, and proposal-only regular mode with split guidance. + - Notes: Deviation from the old text — the bypass overrides and message rules are stated once by their owner instead of being duplicated across the command and skill, as the task's non-duplicative-ownership done check requires. Additions the old workflow lacked: a structured `proposal`/`bypass_message`/`blocked` result contract and a package-local message-style reference, both of which T02 must mirror in Pkl. No Pkl, generated payload, or `context/` file outside this plan was touched, and no `git commit` ran. + +- [x] T02: `Model the canonical commit workflow package` (status:done) + - Task ID: T02 + - Goal: Add a canonical Pkl workflow package that mirrors the complete project-root commit baseline without changing emitted target inventories yet. + - Boundaries (in/out of scope): In — `config/pkl/base/workflow-commit.pkl` and only the minimal shared workflow-model changes needed to represent its command and self-contained skill documents. Out — renderer imports, target metadata, generator mappings, generated payloads, and existing workflow semantics. + - Dependencies: T01 + - Done when: The focused Pkl module exposes one `commit` command and one complete `sce-atomic-commit` package; every package-relative document is deterministic and matches the corresponding `.pi/` baseline text; the module introduces no sibling-package dependency. + - Verification notes (commands or checks): `nix develop -c pkl eval -f json config/pkl/base/workflow-commit.pkl`; extract and compare all exposed documents with `.pi/prompts/commit.md` and `.pi/skills/sce-atomic-commit/`; `git diff --check -- config/pkl/base/workflow-commit.pkl`. + - Completed: 2026-07-28 + - Files changed: `config/pkl/base/workflow-commit.pkl` (new). `config/pkl/base/workflow-content.pkl` was not modified — the existing `WorkflowDocument`/`SkillPackage`/`WorkflowCommand`/`WorkflowPackage` classes represent the commit package without change. + - Evidence: Modeled on `config/pkl/base/workflow-validate.pkl` (local `makeDocument`/`packageDocuments` helpers, one multiline `String` constant per document, one top-level `workflow`). `nix develop -c pkl eval -f json -o /commit.json config/pkl/base/workflow-commit.pkl` -> exit 0, exposing `workflow.slug = commit`, `workflow.command.slug = commit`, `workflow.command.document.path = commit.md`, and exactly one skill package `sce-atomic-commit` with documents `SKILL.md`, `references/commit-contract.yaml`, `references/commit-message-style.md`. Each `.text` extracted with `jq -r` (which appends the single newline the generator adds via `"\(document.text)\n"`) `diff`s clean against `.pi/prompts/commit.md`, `.pi/skills/sce-atomic-commit/SKILL.md`, and both package references — four MATCH, zero DIFF. A second `pkl eval` is byte-identical to the first (`cmp` -> equal), so the module is deterministic. The only import is `workflow-content.pkl`; no sibling workflow package is imported. `git add -N` + `git diff --check -- config/pkl/base/workflow-commit.pkl` -> exit 0 (index restored with `git reset`). + - Notes: Deviation from existing workflow modules — blank lines inside the multiline strings are emitted empty rather than carrying the 4-space block indent that `workflow-validate.pkl` and its siblings use. Pkl strips indentation identically either way and the emitted text is byte-identical to the baseline, but the existing style leaves whitespace-only lines that `git diff --check` would flag, and this task verifies with that command. No renderer, generator mapping, metadata inventory, or generated payload was touched, so target inventories are unchanged and the new module is not yet reachable from `config/pkl/generate.pkl`; T03 wires it in. + +- [x] T03: `Render and enforce the fourth workflow` (status:done) + - Task ID: T03 + - Goal: Wire the canonical commit package into OpenCode, Claude, and Pi rendering and update exact generation coverage for the expanded workflow matrix. + - Boundaries (in/out of scope): In — target renderer imports/lists, OpenCode command skill-chain metadata without a new agent assignment, Claude command tool metadata, `config/pkl/generate.pkl` as needed, metadata coverage inventories, and focused generation documentation/tooling claims tied to exact counts. Out — edits to commit behavior authored in T01/T02, new agents, generated repository trees, Rust CLI, hooks, and unrelated assets. + - Dependencies: T02 + - Done when: Temporary generation emits `/commit` plus its complete skill package for all three targets; Pi output matches the root baseline; OpenCode records `sce-atomic-commit` as the entry/only skill without adding an agent; Claude grants the Git-inspection/commit tool capability required by the workflow; exact coverage expects four commands, eight skill packages, and all package documents; retained workflows and non-Markdown outputs are unchanged. + - Verification notes (commands or checks): `nix develop -c pkl eval config/pkl/renderers/{pi-content,opencode-content,claude-content,metadata-coverage-check}.pkl`; generate to a temporary root and inspect exact target inventories, local reference resolution, Pi baseline parity, OpenCode metadata, Claude tool metadata, unchanged existing workflow documents, and absence of any added agent. + - Completed: 2026-07-28 + - Files changed: `config/pkl/renderers/pi-content.pkl`, `config/pkl/renderers/opencode-content.pkl`, `config/pkl/renderers/claude-content.pkl`, `config/pkl/renderers/claude-metadata.pkl`, `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/README.md`. `config/pkl/generate.pkl` and `config/pkl/renderers/opencode-metadata.pkl` were not modified — the generator's emission loops are generic over the renderer output mappings, and no agent metadata changed. + - Evidence: Each content renderer imports `../base/workflow-commit.pkl` and appends `commit.workflow` to its `workflows` listing. `opencode-content.pkl` adds a `commit` skill-chain entry (`entry-skill`/`skills` = `sce-atomic-commit` only) and makes the `agent:` front-matter line conditional via `commandAgentLine`, so `/commit` is emitted without an agent while the three routed commands keep theirs. `claude-metadata.pkl` grants `/commit` the same allowed-tools string as `/next-task` and `/validate`, including `Bash` for Git inspection and commit execution. `metadata-coverage-check.pkl` now expects four command slugs and 21 skill document paths across eight packages. `config/pkl/README.md` count and removed-surface claims updated from three/seven to four/eight. All four `nix develop -c pkl eval config/pkl/renderers/{pi-content,opencode-content,claude-content,metadata-coverage-check}.pkl` -> exit 0, with all seven inventory checks reporting `complete`. `nix run .#pkl-generate -- ` -> exit 0, emitting per target exactly four commands and eight skill packages, including `sce-atomic-commit/{SKILL.md,references/commit-contract.yaml,references/commit-message-style.md}`, which are the only two reference paths the skill names. Baseline comparison against a detached HEAD worktree generation -> `diff -rq` reports only six additions (the commit command and skill package in each of `.opencode`, `.claude`, `.pi`) and zero modifications, so retained workflows, agents, and non-Markdown outputs are byte-identical. `diff -r .pi/prompts` and `diff -r .pi/skills` against the generated Pi tree -> full match. Generated agent directory still contains exactly `Shared Context Code.md` and `Shared Context Plan.md`. `git add -N` + `git diff --check -- config/pkl/renderers config/pkl/README.md` -> exit 0 (index restored with `git reset`). + - Notes: The renderer, metadata, coverage, and README edits were already present uncommitted in the working tree at the start of this task; they were verified in place rather than reauthored, and no gap required filling. The only structural deviation from the previous rendering model is that OpenCode's `agent:` line is now optional instead of required for every command, which was necessary because `/commit` belongs to neither routing agent; the retained commands' output is unchanged, as the baseline diff proves. Full-plan validation (`nix run .#pkl-check-generated`, `nix flake check`) was deliberately not run — it belongs to `/validate`. + +## Open questions + +None. The supplied old workflow fixes the behavior to preserve, and the repository’s current workflow-package conventions determine the modernization and cross-target scope. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-28 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral generation passed: 85 files, inventory sha256 `4cfd88cb…5d52b18`) +- `nix flake check` -> exit 1, then exit 0 (first run failed only because the new files were untracked, so the flake's Git source copy could not resolve `config/pkl/base/workflow-commit.pkl`; rerun after `git add -N` on the new commit-workflow paths passed all 5 checks, and the index was restored with `git reset`) +- `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` -> exit 0 (all 7 inventory checks report `complete`) +- `nix run .#pkl-generate -- ` -> exit 0 (twice, to a clean temporary root) +- `diff -rq ` -> exit 0 (byte-identical generations) +- `diff -r .pi/prompts /.pi/prompts`, `diff -r .pi/skills /.pi/skills` -> exit 0 (full Pi baseline parity) +- `diff -rq .opencode /.opencode`, `diff -rq .claude /.claude` -> additions only + +### Scaffolding removed + +- `/gen`, `/gen2` — temporary generation roots created for AC3/AC4 verification, outside the repository. + +No temporary scaffolding remained inside the repository; the working tree contains only the plan's intended files. + +### Success-criteria verification + +- [x] AC1: Project-root `.pi/` contains a `/commit` prompt and self-contained `sce-atomic-commit` package with a complete regular-mode branch -> Inspected `.pi/prompts/commit.md`, `.pi/skills/sce-atomic-commit/SKILL.md`, and both package references. The regular path stops for the verbatim staging-confirmation prompt before invoking the skill, the skill reads only `git diff --cached`, and the regular branch is proposal-only with split guidance (SKILL steps 2/7) and never runs `git commit`. The plan-citation rule (SKILL step 5) and context-file guidance gating (`context_only`/`mixed`, SKILL step 6) are preserved. Both references named by the skill — `references/commit-contract.yaml` and `references/commit-message-style.md` — resolve inside the package, and the contract's `proposal`/`bypass_message`/`blocked` variants are internally consistent with the command's status branching. +- [x] AC2: `oneshot`/`skip` bypass validates staged content, requests one best-effort message without split/context gates, executes exactly one `git commit`, and reports hash or unretried failure -> Inspected the generated Pi prompt and skill package (byte-identical to the root baseline). Routing recognizes `oneshot`/`skip` only as an exact case-insensitive first whitespace-separated token; the bypass path runs `git diff --cached --quiet` and stops with exactly `No staged changes. Stage changes before commit.`; the skill stops grouping in bypass mode (one message, no split guidance) and skips the context-file gate entirely; plan citations are best-effort (infer when supported, otherwise omit, never stop or invent); the command runs `git commit` once and terminates on either the reported hash or the Git failure, with no retry, amend, or fallback. +- [x] AC3: All three generated payloads contain `/commit` and one complete `sce-atomic-commit` package with target-supported metadata, existing workflows unchanged, no new agent -> Temporary generation emits exactly 4 commands and 8 skill packages per target. `sce-atomic-commit` ships `SKILL.md` plus both references under `.opencode/skills/`, `.claude/skills/`, and `.pi/skills/`. Claude's `/commit` carries the same `allowed-tools` string as `/next-task` and `/validate` (including `Bash`); OpenCode's records `entry-skill`/`skills` = `sce-atomic-commit` only and emits no `agent:` line, while `/next-task` keeps `agent: "Shared Context Code"`. The generated agent directory still holds exactly `Shared Context Code.md` and `Shared Context Plan.md`. `diff -rq` against the repository's committed `.opencode`/`.claude` trees reports only the commit additions and zero modifications; the Pi tree matches the root baseline exactly. +- [x] AC4: Exact four-command/eight-skill coverage including the new package references, generation deterministic -> `metadata-coverage-check.pkl` declares `expectedCommandSlugs` of 4 (including `commit`) and 21 `expectedSkillDocumentPaths` across 8 packages (including all three `sce-atomic-commit` documents), enforced by `assertExactKeys`, which compares length and membership so unexpected keys fail too. Evaluation exits 0 with all 7 checks `complete`, and `nix run .#pkl-check-generated` exits 0. Two independent generations are byte-identical. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- The repository's committed `.opencode/` and `.claude/` trees do not yet contain `/commit` or the `sce-atomic-commit` package. `.pi/` is in parity, but the other two generated trees are stale relative to canonical Pkl. No repository check enforces that parity — `pkl-check-generated` verifies ephemeral generation only — so this is not a validation failure, but the trees should be regenerated before release. +- `nix flake check` only sees Git-tracked files. Until the new commit-workflow files are committed (or at least `git add`-ed), a plain `nix flake check` on this working tree fails on the missing `workflow-commit.pkl` import. diff --git a/context/sce/atomic-commit-workflow.md b/context/sce/atomic-commit-workflow.md new file mode 100644 index 00000000..b3ff9aa0 --- /dev/null +++ b/context/sce/atomic-commit-workflow.md @@ -0,0 +1,135 @@ +# Atomic Commit Workflow + +Behavior contract for the `/commit` workflow and its `sce-atomic-commit` skill +package. + +## Current surface + +The workflow currently exists only as the project-root `.pi/` behavioral +baseline: + +- `.pi/prompts/commit.md` — the command. +- `.pi/skills/sce-atomic-commit/SKILL.md` — the skill. +- `.pi/skills/sce-atomic-commit/references/commit-contract.yaml` — the result + contract. +- `.pi/skills/sce-atomic-commit/references/commit-message-style.md` — the + message wording rules. + +Canonical Pkl ownership and generated OpenCode/Claude/Pi payloads do not carry +it yet. Until they do, the emitted workflow inventory described in +[the ownership table](dedup-ownership-table.md) remains three commands and seven +skill packages. + +Per the root `.pi/` baseline convention in `context/patterns.md`, this package is +the authoring source for the canonical Pkl workflow package, not the reverse. + +## Modes + +`/commit` takes an optional argument. Its first whitespace-separated token +selects the mode; everything else is free-form commit context that refines +message wording only. + +- `oneshot` or `skip` as the exact first token, compared case-insensitively, + selects **bypass mode**. The two aliases are behaviorally identical. +- Any other first token, or no argument at all, selects **regular mode**. + +Nothing else selects bypass — not the commit context, not repository state. + +```mermaid +flowchart TD + A["/commit [mode-token] [context]"] --> B{First token is
oneshot or skip?} + B -- no --> C[Regular mode] + B -- yes --> D[Bypass mode] + + C --> C1[Stop and prompt for staging confirmation] + C1 --> C2[sce-atomic-commit mode: regular] + C2 --> C3[Present proposals + split guidance] + C3 --> C4([Stop — never commits]) + + D --> D1{git diff --cached
non-empty?} + D1 -- no --> D2([Stop: No staged changes.
Stage changes before commit.]) + D1 -- yes --> D3[sce-atomic-commit mode: bypass] + D3 --> D4[Exactly one git commit] + D4 --> D5([Report hash, or report failure
with no retry or amend]) +``` + +## Regular mode + +Proposal-only. The command stops before invoking the skill and asks the user to +stage everything they intend to commit, because atomic commits should contain +only intentionally staged changes. After confirmation, the skill analyzes the +staged diff and returns one or more messages. + +When the staged changes pursue unrelated goals, the skill returns one message +per coherent unit plus the rationale and file grouping for the split. When they +form one unit, it returns one message and no split guidance. + +The command presents the proposals and stops. It never runs `git commit`; the +user runs the commits they accept. + +## Bypass mode + +Single-message, command-committed. The command first checks that staged content +exists and stops with `No staged changes. Stage changes before commit.` when +nothing is staged. It then requests exactly one message covering all staged +files and runs `git commit` once. + +On success it reports the commit hash. On failure it reports the failure and +stops — no retry, no amend, no fallback commit. + +Bypass mode relaxes three regular-mode rules: no split proposals, no +context-file guidance gating, and plan citations are best-effort rather than +blocking. + +## Ownership boundary + +The command owns user prompting, mode routing, the staged-content precondition, +and the single `git commit`. The skill owns everything about what the commit +says: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing scope and writing every subject and body. +- The plan-citation body rule. +- Staged-scope classification and context-file guidance gating. + +Each rule is stated once by its owner. The skill never commits and never asks +about staging. + +## Staged truth + +Staged changes are the only input describing what is being committed. Neither +document reads unstaged or untracked changes, and neither stages, unstages, or +otherwise modifies files. Supplied commit context refines wording but never +overrides the diff and never adds a claim the diff does not support. + +## Plan citations + +When a commit's staged files include `context/plans/*.md`, its body cites the +affected plan slug and every updated task ID. Plan slugs and task IDs are never +invented. + +When the staged plan diff does not expose them clearly enough to cite +faithfully, regular mode blocks and asks for the reference to be stated or +staged explicitly; bypass mode omits the citation instead of stopping. + +## Result contract + +The skill returns exactly one YAML result: + +- `proposal` — regular mode, one or more messages, optional split rationale and + staged-scope classification. +- `bypass_message` — bypass mode, exactly one message plus the full staged file + list. +- `blocked` — messages cannot be written faithfully. Categories are + `no_staged_changes`, `plan_citation_ambiguity`, `unreadable_diff`, and + `contradictory_context`. + +Every staged file appears under exactly one returned commit. No result carries a +commit hash, because the skill never commits. + +## Related context + +- [SCE workflow ownership table](dedup-ownership-table.md) +- [Plan/Code overlap map](plan-code-overlap-map.md) +- [Context workflow rules](context-workflow-rules.md) diff --git a/context/sce/dedup-ownership-table.md b/context/sce/dedup-ownership-table.md index 03512f5a..e45cf3e6 100644 --- a/context/sce/dedup-ownership-table.md +++ b/context/sce/dedup-ownership-table.md @@ -26,4 +26,5 @@ - Keep Plan and Code routing roles separate without placing workflow doctrine in agent bodies. - Keep commands at sequencing, branching, and handoff scope; phase behavior remains skill-owned. - Keep task and plan synchronization packages self-contained even though one Pkl skeleton owns their shared policy. -- Do not reintroduce removed `/commit`, `/handover`, legacy context-sync, or automated-profile Markdown ownership. +- Do not reintroduce removed `/handover`, legacy context-sync, or automated-profile Markdown ownership. +- `/commit` is being restored as a fourth workflow. Its behavioral baseline exists in the project-root `.pi/` package (see [Atomic commit workflow](atomic-commit-workflow.md)); canonical Pkl ownership and generated target inventories still carry only the three workflows above. From 67d913ab9292bc60f31b57bb2fae650426a8dc28 Mon Sep 17 00:00:00 2001 From: David Abram Date: Tue, 28 Jul 2026 13:16:23 +0200 Subject: [PATCH 11/21] setup: Add additive context baseline bootstrap Add --bootstrap-context for context-only initialization and ensure every successful setup path creates missing durable context files without replacing existing content. Document the setup contract and cover the new command surface and filesystem behavior. Plan: setup-bootstrap-context (T01, T02) Co-authored-by: SCE --- cli/src/cli_schema.rs | 4 + cli/src/command_surface.rs | 3 +- cli/src/services/command_registry.rs | 1 + cli/src/services/default_paths.rs | 5 + cli/src/services/parse/command_runtime.rs | 14 +- cli/src/services/setup/command.rs | 16 +- cli/src/services/setup/mod.rs | 292 ++++++++++++++++++ context/architecture.md | 2 +- context/cli/cli-command-surface.md | 6 +- context/cli/default-path-catalog.md | 2 +- context/context-map.md | 2 +- context/glossary.md | 5 +- context/overview.md | 4 +- context/patterns.md | 1 + context/plans/setup-bootstrap-context.md | 114 +++++++ context/sce/context-workflow-rules.md | 10 +- .../sce/setup-repo-local-config-bootstrap.md | 25 +- 17 files changed, 484 insertions(+), 22 deletions(-) create mode 100644 context/plans/setup-bootstrap-context.md diff --git a/cli/src/cli_schema.rs b/cli/src/cli_schema.rs index 49ebb203..f98a0104 100644 --- a/cli/src/cli_schema.rs +++ b/cli/src/cli_schema.rs @@ -187,6 +187,10 @@ pub enum Commands { #[arg(long, requires = "hooks")] repo: Option, + + /// Create the baseline durable-context tree without installing integrations + #[arg(long)] + bootstrap_context: bool, }, #[command(about = DOCTOR_CLAP_ABOUT, hide = !DOCTOR_SHOW_IN_TOP_LEVEL_HELP)] diff --git a/cli/src/command_surface.rs b/cli/src/command_surface.rs index 9c626191..4e55075f 100644 --- a/cli/src/command_surface.rs +++ b/cli/src/command_surface.rs @@ -51,7 +51,7 @@ const HELP_SECTIONS: &[HelpSection] = &[ body: &[HelpSectionBodyLine::Command { cmd: " sce setup", suffix: - " [--opencode|--claude|--pi|--all] [--non-interactive] [--hooks] [--repo ]", + " [--opencode|--claude|--pi|--all] [--non-interactive] [--hooks] [--repo ] [--bootstrap-context]", }], }, HelpSection { @@ -89,6 +89,7 @@ const HELP_SECTIONS: &[HelpSection] = &[ HelpSectionBodyLine::Text(" sce setup"), HelpSectionBodyLine::Text(" sce setup --opencode --non-interactive --hooks"), HelpSectionBodyLine::Text(" sce setup --hooks --repo ../demo-repo"), + HelpSectionBodyLine::Text(" sce setup --bootstrap-context"), HelpSectionBodyLine::Text(" sce doctor --format json"), HelpSectionBodyLine::Text(" sce doctor --fix"), HelpSectionBodyLine::Text(" sce version --format json"), diff --git a/cli/src/services/command_registry.rs b/cli/src/services/command_registry.rs index 2a43406d..3ea2cd43 100644 --- a/cli/src/services/command_registry.rs +++ b/cli/src/services/command_registry.rs @@ -137,6 +137,7 @@ pub fn default_runtime_command(name: &str) -> Option { config_mode: Some(services::setup::SetupMode::Interactive), install_hooks: true, hooks_repo_path: None, + context_only: false, }, }, )), diff --git a/cli/src/services/default_paths.rs b/cli/src/services/default_paths.rs index 2ebd37c7..4d6cc1e4 100644 --- a/cli/src/services/default_paths.rs +++ b/cli/src/services/default_paths.rs @@ -406,6 +406,7 @@ pub(crate) mod context_file { pub const GLOSSARY: &str = "glossary.md"; pub const PATTERNS: &str = "patterns.md"; pub const CONTEXT_MAP: &str = "context-map.md"; + pub const TMP_GITIGNORE: &str = ".gitignore"; pub const SKILL_DEFINITION: &str = "SKILL.md"; } @@ -509,6 +510,10 @@ impl RepoPaths { pub(crate) fn context_map_file(&self) -> PathBuf { self.context_dir().join(context_file::CONTEXT_MAP) } + + pub(crate) fn context_tmp_gitignore_file(&self) -> PathBuf { + self.context_tmp_dir().join(context_file::TMP_GITIGNORE) + } } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/cli/src/services/parse/command_runtime.rs b/cli/src/services/parse/command_runtime.rs index 6bd82d67..2bceb22c 100644 --- a/cli/src/services/parse/command_runtime.rs +++ b/cli/src/services/parse/command_runtime.rs @@ -222,7 +222,17 @@ fn convert_clap_command(command: cli_schema::Commands) -> Result convert_setup_command(opencode, claude, pi, all, non_interactive, hooks, repo), + bootstrap_context, + } => convert_setup_command( + opencode, + claude, + pi, + all, + non_interactive, + hooks, + repo, + bootstrap_context, + ), cli_schema::Commands::Doctor { fix, format } => Ok(convert_doctor_command(fix, format)), cli_schema::Commands::Hooks { subcommand } => convert_hooks_subcommand(subcommand), cli_schema::Commands::Policy { subcommand } => Ok(convert_policy_subcommand(&subcommand)), @@ -401,6 +411,7 @@ fn convert_setup_command( non_interactive: bool, hooks: bool, repo: Option, + bootstrap_context: bool, ) -> Result { let options = services::setup::SetupCliOptions { help: false, @@ -411,6 +422,7 @@ fn convert_setup_command( all, hooks, repo_path: repo, + bootstrap_context, }; let request = services::setup::resolve_setup_request(options) diff --git a/cli/src/services/setup/command.rs b/cli/src/services/setup/command.rs index e0d19a48..4aee14a3 100644 --- a/cli/src/services/setup/command.rs +++ b/cli/src/services/setup/command.rs @@ -13,7 +13,9 @@ pub struct SetupCommand { impl SetupCommand { pub fn execute(&self, context: &C) -> Result { - let setup_dispatch = if let Some(mode) = self.request.config_mode { + let setup_dispatch = if self.request.context_only { + None + } else if let Some(mode) = self.request.config_mode { match setup::resolve_setup_dispatch(mode, &setup::InquireSetupTargetPrompter) .map_err(|error| ClassifiedError::runtime(format!("{error:#}")))? { @@ -36,13 +38,23 @@ impl SetupCommand { let repository_root = setup::ensure_git_repository(&setup_start_path) .map_err(|error| ClassifiedError::runtime(format!("{error:#}")))?; + let mut sections = Vec::new(); + + // Every successful setup path ensures the durable-context baseline exists. + let context_message = setup::bootstrap_context_baseline(&repository_root) + .map_err(|error| ClassifiedError::runtime(format!("{error:#}")))?; + sections.push(context_message); + + if self.request.context_only { + return Ok(sections.join("\n\n")); + } + // Scope the runtime AppContext to the resolved repository root for lifecycle providers. let ctx = context.with_repo_root(repository_root.clone()); // Aggregate setup steps from lifecycle providers in order: // config → local_db → auth_db → agent_trace_db → hooks (when requested). let providers = lifecycle_providers(self.request.install_hooks); - let mut sections = Vec::new(); for provider in &providers { let outcome = provider diff --git a/cli/src/services/setup/mod.rs b/cli/src/services/setup/mod.rs index aeeb4b01..0ebef83f 100644 --- a/cli/src/services/setup/mod.rs +++ b/cli/src/services/setup/mod.rs @@ -129,6 +129,7 @@ pub struct SetupCliOptions { pub all: bool, pub hooks: bool, pub repo_path: Option, + pub bootstrap_context: bool, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -136,6 +137,7 @@ pub struct SetupRequest { pub config_mode: Option, pub install_hooks: bool, pub hooks_repo_path: Option, + pub context_only: bool, } pub fn resolve_setup_request(options: SetupCliOptions) -> Result { @@ -145,6 +147,28 @@ pub fn resolve_setup_request(options: SetupCliOptions) -> Result { ); } + if options.bootstrap_context { + let has_other_setup_options = options.non_interactive + || options.opencode + || options.claude + || options.pi + || options.all + || options.hooks + || options.repo_path.is_some(); + if has_other_setup_options { + bail!( + "Option '--bootstrap-context' must be used alone. Try: run 'sce setup --bootstrap-context', or omit it because normal setup paths ensure the context baseline automatically." + ); + } + + return Ok(SetupRequest { + config_mode: None, + install_hooks: false, + hooks_repo_path: None, + context_only: true, + }); + } + let mut selected_targets = Vec::new(); if options.opencode { @@ -185,6 +209,7 @@ pub fn resolve_setup_request(options: SetupCliOptions) -> Result { config_mode, install_hooks, hooks_repo_path: options.repo_path, + context_only: false, }) } @@ -251,6 +276,86 @@ pub fn bootstrap_repo_local_config(repository_root: &Path) -> Result<()> { Ok(()) } +const CONTEXT_TMP_GITIGNORE_CONTENT: &str = "*\n!.gitignore\n"; + +const CONTEXT_OVERVIEW_TEMPLATE: &str = "# Overview\n\n"; +const CONTEXT_ARCHITECTURE_TEMPLATE: &str = "# Architecture\n\n"; +const CONTEXT_PATTERNS_TEMPLATE: &str = "# Patterns\n\n"; +const CONTEXT_GLOSSARY_TEMPLATE: &str = "# Glossary\n\n"; +const CONTEXT_MAP_TEMPLATE: &str = "\ +# Context Map + +Primary context files: + +- `context/overview.md` +- `context/architecture.md` +- `context/patterns.md` +- `context/glossary.md` + +Working areas: + +- `context/plans/` +- `context/handovers/` +- `context/decisions/` +- `context/tmp/` +"; + +/// Creates the baseline durable-context tree additively. +/// +/// Missing directories and baseline files are created with neutral templates. +/// Existing files and directory contents are never overwritten. +pub fn bootstrap_context_baseline(repository_root: &Path) -> Result { + let repo_paths = RepoPaths::new(repository_root); + + ensure_context_directory(&repo_paths.context_dir())?; + ensure_context_directory(&repo_paths.context_plans_dir())?; + ensure_context_directory(&repo_paths.context_handovers_dir())?; + ensure_context_directory(&repo_paths.context_decisions_dir())?; + ensure_context_directory(&repo_paths.context_tmp_dir())?; + + ensure_context_file( + &repo_paths.context_overview_file(), + CONTEXT_OVERVIEW_TEMPLATE, + )?; + ensure_context_file( + &repo_paths.context_architecture_file(), + CONTEXT_ARCHITECTURE_TEMPLATE, + )?; + ensure_context_file( + &repo_paths.context_patterns_file(), + CONTEXT_PATTERNS_TEMPLATE, + )?; + ensure_context_file( + &repo_paths.context_glossary_file(), + CONTEXT_GLOSSARY_TEMPLATE, + )?; + ensure_context_file(&repo_paths.context_map_file(), CONTEXT_MAP_TEMPLATE)?; + ensure_context_file( + &repo_paths.context_tmp_gitignore_file(), + CONTEXT_TMP_GITIGNORE_CONTENT, + )?; + + Ok(success("Context baseline ensured.")) +} + +fn ensure_context_directory(path: &Path) -> Result<()> { + fs::create_dir_all(path) + .with_context(|| format!("Failed to create context directory '{}'", path.display())) +} + +fn ensure_context_file(path: &Path, content: &str) -> Result<()> { + if path.exists() { + return Ok(()); + } + + if let Some(parent) = path.parent() { + ensure_context_directory(parent)?; + } + + fs::write(path, content) + .with_context(|| format!("Failed to write context baseline file '{}'", path.display())) +} + fn format_setup_install_success_message(outcome: &SetupInstallOutcome) -> String { let selected_targets = outcome .target_results @@ -1215,6 +1320,13 @@ pub fn setup_cancelled_text() -> String { #[cfg(test)] mod tests { use super::*; + use std::process::Command; + use std::time::{SystemTime, UNIX_EPOCH}; + + use crate::command_surface; + use crate::services::command_registry::CommandRegistry; + use crate::services::command_registry::RuntimeCommand; + use crate::services::parse::command_runtime::parse_runtime_command; fn options_with(mutate: impl FnOnce(&mut SetupCliOptions)) -> SetupCliOptions { let mut options = SetupCliOptions::default(); @@ -1222,6 +1334,52 @@ mod tests { options } + fn unique_temp_dir(label: &str) -> PathBuf { + let nonce = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after Unix epoch") + .as_nanos(); + let dir = std::env::temp_dir().join(format!( + "sce-setup-context-{label}-{}-{nonce}", + std::process::id() + )); + fs::create_dir_all(&dir).expect("create temp dir"); + dir + } + + fn init_git_repo(label: &str) -> PathBuf { + let repo = unique_temp_dir(label); + let output = Command::new("git") + .args(["init", "-q"]) + .current_dir(&repo) + .output() + .expect("git init should spawn"); + assert!( + output.status.success(), + "git init failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + repo + } + + fn assert_baseline_paths_exist(repo: &Path) { + let paths = RepoPaths::new(repo); + for path in [ + paths.context_overview_file(), + paths.context_architecture_file(), + paths.context_patterns_file(), + paths.context_glossary_file(), + paths.context_map_file(), + paths.context_plans_dir(), + paths.context_handovers_dir(), + paths.context_decisions_dir(), + paths.context_tmp_dir(), + paths.context_tmp_gitignore_file(), + ] { + assert!(path.exists(), "expected baseline path {}", path.display()); + } + } + #[test] fn resolve_setup_request_accepts_pi_target() { let request = resolve_setup_request(options_with(|options| { @@ -1234,6 +1392,7 @@ mod tests { request.config_mode, Some(SetupMode::NonInteractive(SetupTarget::Pi)) ); + assert!(!request.context_only); } #[test] @@ -1248,6 +1407,32 @@ mod tests { request.config_mode, Some(SetupMode::NonInteractive(SetupTarget::All)) ); + assert!(!request.context_only); + } + + #[test] + fn resolve_setup_request_accepts_bootstrap_context_alone() { + let request = resolve_setup_request(options_with(|options| { + options.bootstrap_context = true; + })) + .expect("bootstrap-context alone should resolve"); + + assert!(request.context_only); + assert_eq!(request.config_mode, None); + assert!(!request.install_hooks); + assert_eq!(request.hooks_repo_path, None); + } + + #[test] + fn resolve_setup_request_rejects_bootstrap_context_with_target() { + let error = resolve_setup_request(options_with(|options| { + options.bootstrap_context = true; + options.opencode = true; + })) + .expect_err("bootstrap-context with target must be rejected"); + + assert!(error.to_string().contains("--bootstrap-context")); + assert!(error.to_string().contains("alone")); } #[test] @@ -1273,6 +1458,113 @@ mod tests { assert!(message.contains("--all")); } + #[test] + fn parser_routes_bootstrap_context_to_context_only_request() { + let registry = CommandRegistry::default(); + let command = parse_runtime_command( + [ + "sce".to_string(), + "setup".to_string(), + "--bootstrap-context".to_string(), + ], + ®istry, + None, + ) + .expect("bootstrap-context should parse"); + + match command { + RuntimeCommand::Setup(setup_command) => { + assert!(setup_command.request.context_only); + assert_eq!(setup_command.request.config_mode, None); + assert!(!setup_command.request.install_hooks); + } + _ => panic!("expected Setup command for --bootstrap-context"), + } + } + + #[test] + fn help_documents_bootstrap_context_flag() { + let top_level_help = command_surface::help_text(); + assert!( + top_level_help.contains("--bootstrap-context"), + "top-level help should document --bootstrap-context" + ); + + let registry = CommandRegistry::default(); + let command = parse_runtime_command( + ["sce".to_string(), "setup".to_string(), "--help".to_string()], + ®istry, + None, + ) + .expect("setup --help should parse"); + + match command { + RuntimeCommand::HelpText(help) => { + assert!( + help.text.contains("--bootstrap-context"), + "setup --help should document --bootstrap-context:\n{}", + help.text + ); + } + _ => panic!("expected HelpText for setup --help"), + } + } + + #[test] + fn bootstrap_context_baseline_creates_expected_paths() { + let repo = init_git_repo("create-baseline"); + let message = bootstrap_context_baseline(&repo).expect("bootstrap should create baseline"); + assert!(message.contains("Context baseline ensured.")); + assert_baseline_paths_exist(&repo); + + let paths = RepoPaths::new(&repo); + assert!(!paths.opencode_dir().exists()); + assert!(!paths.claude_dir().exists()); + assert!(!paths.pi_dir().exists()); + + let gitignore = fs::read_to_string(paths.context_tmp_gitignore_file()) + .expect("tmp gitignore should be readable"); + assert_eq!(gitignore, CONTEXT_TMP_GITIGNORE_CONTENT); + + let _ = fs::remove_dir_all(&repo); + } + + #[test] + fn bootstrap_context_baseline_is_additive_and_idempotent() { + let repo = init_git_repo("idempotent-baseline"); + bootstrap_context_baseline(&repo).expect("initial bootstrap"); + + let paths = RepoPaths::new(&repo); + let sentinel = "SENTINEL_OVERVIEW_CONTENT\n"; + fs::write(paths.context_overview_file(), sentinel).expect("seed overview sentinel"); + fs::write(paths.context_map_file(), "SENTINEL_CONTEXT_MAP\n") + .expect("seed context-map sentinel"); + fs::write(paths.context_tmp_gitignore_file(), "SENTINEL_GITIGNORE\n") + .expect("seed gitignore sentinel"); + + fs::remove_file(paths.context_architecture_file()).expect("remove architecture"); + fs::remove_dir_all(paths.context_plans_dir()).expect("remove plans"); + + bootstrap_context_baseline(&repo).expect("rerun bootstrap"); + + assert_eq!( + fs::read_to_string(paths.context_overview_file()).expect("read overview"), + sentinel + ); + assert_eq!( + fs::read_to_string(paths.context_map_file()).expect("read context-map"), + "SENTINEL_CONTEXT_MAP\n" + ); + assert_eq!( + fs::read_to_string(paths.context_tmp_gitignore_file()).expect("read gitignore"), + "SENTINEL_GITIGNORE\n" + ); + assert!(paths.context_architecture_file().exists()); + assert!(paths.context_plans_dir().is_dir()); + + let _ = fs::remove_dir_all(&repo); + } + #[test] fn concrete_targets_for_all_expands_to_three_targets() { assert_eq!( diff --git a/context/architecture.md b/context/architecture.md index 9be414dd..411c5c52 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -112,7 +112,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/auth_db/mod.rs` provides the encrypted auth DB spec and `AuthDb` type alias over `EncryptedTursoDb`. `AuthDbSpec` resolves `/sce/auth.db` through the shared default-path seam and embeds ordered auth migrations. Auth DB lifecycle setup/doctor integration is wired through `AuthDbLifecycle`; auth command/token-storage reads/writes are directed through `token_storage.rs`. - `cli/src/services/agent_trace_db/mod.rs` owns the shared Agent Trace insert payloads, SQL constants, and typed row helpers (diff-trace/intersection/Agent Trace/message/part) plus `ensure_schema_ready_for_hooks()` consumed by the repository adapter. `cli/src/services/agent_trace_db/repository.rs` defines the sole `RepositoryAgentTraceDb` adapter over `TursoDb` with one fresh `agent-trace-repository/001_repository_schema.sql` baseline for `diff_traces` (including `payload_type`), `post_commit_patch_intersections`, `agent_traces`, `messages`, `parts`, indexes, and triggers, `repository_metadata` validation, no trace-table `checkout_id` columns, `agent_traces.agent_trace_id NOT NULL UNIQUE`, and `recent_diff_trace_patches(cutoff_time_ms, end_time_ms)` using the inclusive chronological parser without checkout filtering. Active hook runtime, setup/lifecycle storage, and trace status/list/shell flows resolve through `agent_trace_storage` and use `RepositoryAgentTraceDb`. The checkout-scoped `AgentTraceDb`/`AgentTraceDbSpec` adapter, its `agent_trace_db_path()`/`agent_trace_db_path_for_checkout()` helpers, the 15-file `cli/migrations/agent-trace/` chain, and the `sce trace --legacy` surface were removed by the `retire-legacy-agent-trace-db` plan. - `cli/src/test_support.rs` provides a shared test-only temp-directory helper (`TestTempDir`) used by service tests that need filesystem fixtures. -- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), and compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups). For repository builds, `cli/build.rs` validates the `SCE_CLI_GENERATED_INPUT_DIR` payload and canonical-input inventories, copies the payload into Cargo `OUT_DIR/pkl-generated`, stages `cli/assets/hooks/**` under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; focused internal seams separate install-flow from prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). The setup command derives a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. +- `cli/src/services/setup/mod.rs` defines the setup command contract (`SetupMode`, `SetupTarget`, `SetupRequest`, CLI flag parser/validator), an `inquire`-backed interactive target prompter (`InquireSetupTargetPrompter`), setup dispatch outcomes (proceed/cancelled), additive durable-context bootstrap (`bootstrap_context_baseline` for standalone `--bootstrap-context` and every normal successful setup path), and compile-time embedded asset access (`EmbeddedAsset`, target-scoped iterators, required-hook asset iterators/lookups). For repository builds, `cli/build.rs` validates the `SCE_CLI_GENERATED_INPUT_DIR` payload and canonical-input inventories, copies the payload into Cargo `OUT_DIR/pkl-generated`, stages `cli/assets/hooks/**` under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; focused internal seams separate install-flow from prompt-flow logic; `cli/src/services/setup/command.rs` owns the `SetupCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Its install engine/orchestrator stages embedded files and uses a unified remove-and-replace policy (removing existing targets before swapping staged content, with deterministic recovery guidance on swap failure and no backup artifact creation), and formats deterministic completion messaging; required-hook install orchestration (`install_required_git_hooks`) follows the same remove-and-replace policy (removing existing hooks before swapping staged content, with deterministic recovery guidance on swap failure). After the Git gate, setup always ensures the context baseline; context-only requests return there, while normal modes derive a repo-root-scoped context before aggregating static lifecycle provider `setup` dispatch across providers (config → local_db → auth_db → agent_trace_db → hooks when requested), so setup providers consume only repo-root access from the scoped context. - `cli/src/services/setup/mod.rs` keeps those responsibilities inside one file for now, but the current ownership split is explicit: the inline `install` module owns repository-path normalization, staging/swap install behavior, required-hook installation, and filesystem safety guards, while the inline `prompt` module owns interactive target selection and prompt styling. - `cli/src/services/security.rs` provides shared security utilities for deterministic secret redaction (`redact_sensitive_text`) and directory write-permission probes (`ensure_directory_is_writable`) used by app/setup/observability surfaces. - `cli/src/services/doctor/mod.rs` owns the current doctor request/report surface while focused submodules (`doctor/inspect.rs`, `doctor/render.rs`, `doctor/fixes.rs`, `doctor/types.rs`) split report fact collection, rendering, manual fix reporting, and doctor-owned domain types into smaller seams; `cli/src/services/doctor/command.rs` owns the `DoctorCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Runtime doctor execution resolves a repository root, derives a scoped context, requests the shared static lifecycle provider catalog with hooks included for service-owned `diagnose` and `fix` behavior, adapts lifecycle-owned health/fix records into doctor-owned problem/fix records, and then renders stable text/JSON problem records with category/severity/fixability/remediation fields plus deterministic fix-result reporting in fix mode. Checkout DB discovery no longer lives in `doctor`; it moved to the `trace` group (`sce trace db list`) in `cli/src/services/trace/`. Report fact collection preserves environment/repository/hook/integration display data and checkout identity facts, while service-owned lifecycle providers own config validation, local DB and repository-scoped Agent Trace DB readiness/bootstrap, and hook rollout diagnosis/repair. diff --git a/context/cli/cli-command-surface.md b/context/cli/cli-command-surface.md index dc7da026..c90f9b14 100644 --- a/context/cli/cli-command-surface.md +++ b/context/cli/cli-command-surface.md @@ -57,7 +57,7 @@ Deferred or gated command surfaces currently avoid claiming unimplemented behavi `config` exposes deterministic inspect/validate entrypoints (`sce config show`, `sce config validate`) with explicit precedence (`flags > env > config file > defaults`), a shared auth-runtime resolver for supported keys that declare env/config/optional baked-default inputs starting with `workos_client_id`, first-class `policies.bash` reporting for preset/custom blocked-command rules, and deterministic text/JSON output modes where `show` reports resolved values with provenance while `validate` reports pass/fail plus validation issues and warnings only. `version` exposes deterministic runtime identification output in text mode by default and JSON mode via `--format json`. `completion` exposes deterministic shell completion generation via `sce completion --shell `. -`setup` defaults to an `inquire` interactive target selection (OpenCode, Claude, Pi, All) and accepts mutually-exclusive non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`); the former `--both` flag was removed in favor of `--all` (opencode+claude+pi); the interactive prompt title and target labels reuse shared prompt styling helpers when stdout color is enabled. +`setup` defaults to an `inquire` interactive target selection (OpenCode, Claude, Pi, All) and accepts mutually-exclusive non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`); the former `--both` flag was removed in favor of `--all` (opencode+claude+pi); the interactive prompt title and target labels reuse shared prompt styling helpers when stdout color is enabled. `setup` also accepts `--bootstrap-context` as a standalone context-only mode that ensures the durable-context baseline without prompts or integration installs; every normal successful setup path also ensures that baseline after the Git gate. `auth` now emits auth-local guidance for bare `sce auth` and `sce auth --help`, listing `login`, `logout`, and `status` plus copy-ready next steps. `setup`, `doctor`, `hooks`, `version`, and `completion` all support command-local `--help`/`-h` usage output via top-level parser routing in `cli/src/app.rs`. `setup` now also exposes compile-time embedded config assets for OpenCode/Claude/Pi targets, sourced from the generated `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**` trees via `cli/build.rs` with normalized forward-slash relative paths and target-scoped iteration APIs; the embedded asset set includes the OpenCode bash-policy plugin wrapper plus Claude settings `PreToolUse` Bash policy hook, both delegating to the Rust `sce policy bash` path. @@ -79,13 +79,13 @@ A user-invocable `sync` command is not wired in the current CLI surface; local D - `sce doctor --help` and `sce hooks --help` return command-local usage output and deterministic copy-ready examples. - Interactive `sce setup` prompt cancellation/interrupt exits cleanly with: `Setup cancelled. No files were changed.` - Command handlers return deterministic status messaging: -- `setup`: `Setup completed successfully.` plus selected targets and per-target install destinations/counts. +- `setup`: `Context baseline ensured.` on every successful path; context-only `--bootstrap-context` stops there. Normal modes continue with `Setup completed successfully.` plus selected targets and per-target install destinations/counts. - `doctor`: current runtime emits `SCE doctor diagnose` / `SCE doctor fix` human text headers plus ordered `Environment`, `Configuration` (including checkout identity plus repository-scoped Agent Trace DB rows with repository ID, identity source, safe canonical identity, configured remote, and path when available), `Repository`, `Git Hooks`, and `Integrations` sections with bracketed `[PASS]`/`[FAIL]`/`[MISS]` row tokens, shared-style green pass plus red fail/miss colorization when enabled, simplified `label (path)` rows, top-level-only hook rows, and a deterministic summary footer; JSON output carries stable problem/fixability records plus deterministic fix-result records in fix mode and reports `checkout_identity` plus the resolved repository-scoped Agent Trace DB record with credential-safe metadata. - `hooks`: deterministic hook subcommand status messaging for runtime entrypoint invocation and argument/STDIN contract validation. ## Service contracts -- `cli/src/services/setup/mod.rs` defines setup parsing/selection contracts plus runtime install orchestration (`run_setup_for_mode`) over the embedded asset install engine; `cli/src/services/setup/command.rs` owns the setup runtime command handler. Setup now aggregates `ServiceLifecycle::setup` calls across registered providers (`config`, `local_db`, `auth_db`, `agent_trace_db`, `hooks`) in order, using a `ContextWithRepoRoot`-scoped context with resolved repository root. +- `cli/src/services/setup/mod.rs` defines setup parsing/selection contracts, additive `bootstrap_context_baseline`, and runtime install orchestration (`run_setup_for_mode`) over the embedded asset install engine; `cli/src/services/setup/command.rs` owns the setup runtime command handler. After the Git gate, setup always ensures the context baseline; context-only requests return there, while normal modes aggregate `ServiceLifecycle::setup` calls across registered providers (`config`, `local_db`, `auth_db`, `agent_trace_db`, `hooks`) in order, using a `ContextWithRepoRoot`-scoped context with resolved repository root. - `cli/src/services/setup/mod.rs` now keeps its larger internal responsibilities behind focused inline support modules: `install` owns repository canonicalization, staging/swap install flows, required-hook installation, and repo/writeability guards, while `prompt` owns interactive target selection and styled prompt labels. - `cli/src/services/config/mod.rs` defines config parser/runtime contracts (`show`, `validate`, `--help`), strict config-file key/type validation, deterministic text/JSON rendering, repo-configured bash-policy preset/custom validation and reporting under `policies.bash`, and shared auth-key metadata that declares env key, config-file key, and optional baked-default eligibility for supported auth runtime values starting with `workos_client_id` (`WORKOS_CLIENT_ID` vs `workos_client_id`); auth-key provenance/preference metadata stays on `show`, while `validate` stays trimmed to validation status plus issues/warnings. `cli/src/services/config/lifecycle.rs` implements `ServiceLifecycle` for config health checks and setup (global/local config validation and repo-local config bootstrap). - `cli/src/services/doctor/mod.rs` defines the implemented doctor request/report contract (`DoctorRequest`, `DoctorAction`, `DoctorMode`, `run_doctor`) while focused submodules under `cli/src/services/doctor/` handle runtime command dispatch (`command.rs`), diagnosis (`inspect.rs`), rendering (`render.rs`), fix execution (`fixes.rs`), and doctor-owned domain types (`types.rs`). Together they preserve explicit fix-mode parsing, checkout-database discovery, stable text/JSON problem and database-record rendering, deterministic fix-result reporting, and aggregation of `ServiceLifecycle::diagnose`/`ServiceLifecycle::fix` across registered providers (`config`, `local_db`, `auth_db`, `agent_trace_db`, `hooks`). The doctor module coordinates state-root/config/database reporting and validation, path-source detection plus required-hook presence/executable/content checks when a repository target is detected, repo-root installed OpenCode, Claude, and Pi integration inventory derived from embedded setup asset catalogs, shared-style bracketed human status token rendering (`[PASS]`, `[FAIL]`, `[MISS]`) with simplified `label (path)` text rows, and repair-mode delegation to service-owned fix implementations. Claude grouping is path-based: `settings.json`/`hooks/**` as `ClaudeCode plugins` (including `.claude/hooks/run-sce-or-show-install-guidance.sh`), plus `ClaudeCode agents`, `ClaudeCode commands`, and `ClaudeCode skills`; Pi grouping is path-based: `prompts/**` as `Pi prompts` and `skills/**` as `Pi skills`. diff --git a/context/cli/default-path-catalog.md b/context/cli/default-path-catalog.md index 4b468fa7..53558c64 100644 --- a/context/cli/default-path-catalog.md +++ b/context/cli/default-path-catalog.md @@ -25,7 +25,7 @@ - `.claude/` - `.pi/` - `.git/`, `.git/hooks/`, `.git/COMMIT_EDITMSG` -- `context/`, `context/plans/`, `context/decisions/`, `context/handovers/`, `context/tmp/` +- `context/`, `context/plans/`, `context/decisions/`, `context/handovers/`, `context/tmp/`, `context/tmp/.gitignore` via `RepoPaths::context_tmp_gitignore_file()` ### Install paths diff --git a/context/context-map.md b/context/context-map.md index 6e5c0169..07ab554a 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -43,7 +43,7 @@ Feature/domain context: - `context/sce/setup-githooks-hook-asset-packaging.md` (compile-time `sce setup --hooks` required-hook template packaging contract, including all-hook non-blocking missing-`sce` install guidance, available-CLI argument forwarding, post-commit-only origin remote lookup plus remote-URL forwarding/fallback behavior, setup-service accessor surface, and current validation posture) - `context/sce/setup-githooks-install-flow.md` (setup-service required-hook install orchestration with git-truth hooks-path resolution, canonical missing-CLI payload installation, per-hook installed/updated/skipped outcomes, and remove-and-replace behavior with recovery guidance) - `context/sce/setup-githooks-cli-ux.md` (T04 composable `sce setup` target+`--hooks` / `--repo` command-surface contract, option compatibility validation, and deterministic setup/hook output semantics) -- `context/sce/setup-repo-local-config-bootstrap.md` (setup local bootstrap behavior: repo-local `.sce/config.json` create-if-missing via config lifecycle, additive `integrations.target` persistence after successful target installs, plus lifecycle-owned local DB initialization before hooks/config asset dispatch) +- `context/sce/setup-repo-local-config-bootstrap.md` (setup local bootstrap behavior: additive durable-context baseline via `sce setup --bootstrap-context` and every normal setup path, repo-local `.sce/config.json` create-if-missing via config lifecycle, additive `integrations.target` persistence after successful target installs, plus lifecycle-owned local DB initialization before hooks/config asset dispatch) - `context/sce/cli-security-hardening-contract.md` (T06 CLI redaction contract, setup `--repo` canonicalization/validation, and setup write-permission probe behavior) - `context/sce/agent-trace-post-rewrite-local-remap-ingestion.md` (current post-rewrite no-op baseline plus historical remap-ingestion reference) - `context/sce/agent-trace-rewrite-trace-transformation.md` (current post-rewrite no-op baseline plus historical rewrite-transformation reference) diff --git a/context/glossary.md b/context/glossary.md index 2ddd57d8..67ea09cb 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -69,7 +69,7 @@ - `CLI generated migration manifest`: Build-time Rust source at `OUT_DIR/generated_migrations.rs` written by `cli/build.rs` from immediate `cli/migrations//*.sql` directories after staging SQL under `OUT_DIR/static/migrations`; constants are named from the database directory (for example `AGENT_TRACE_REPOSITORY_MIGRATIONS`, `AUTH_MIGRATIONS`), sorted by the numeric filename prefix before `_`, and embed staged SQL via `include_str!`. - `sync command deferral`: Current plan/state note that a user-invocable `sce sync` command is not wired yet and is deferred to `0.4.0`; local DB bootstrap and setup-time repository-scoped Agent Trace DB initialization flow through lifecycle providers aggregated by the setup command, while hook runtime keeps a lazy repository Agent Trace DB fallback for repositories where setup has not run or schema metadata is incomplete, and DB health/repair flows through the doctor surface. - `CLI bounded resilience wrapper`: Shared policy in `cli/src/services/resilience.rs` (`RetryPolicy`, async `run_with_retry`, sync `run_with_retry_sync`) that applies deterministic retries/timeouts/capped backoff to transient operations, emits retry observability events, and returns actionable terminal failure guidance. The sync helper is currently wired into shared database constructors for local open/connect retry and into `TursoDb`/`EncryptedTursoDb` operation retry for `execute()`/`query()`/`query_map()`. -- `setup service orchestration`: Setup execution logic in `cli/src/services/setup/command.rs` that resolves the repository root, derives a repo-root-scoped `AppContext` from the runtime command context, dispatches `setup` through the static lifecycle provider catalog (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive target selection for config asset installation, and emits deterministic success messaging per target. +- `setup service orchestration`: Setup execution logic in `cli/src/services/setup/command.rs` that resolves the repository root, always ensures the durable-context baseline, then for normal modes derives a repo-root-scoped `AppContext` from the runtime command context, dispatches `setup` through the static lifecycle provider catalog (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive target selection for config asset installation, and emits deterministic success messaging per target. - `setup target flags`: Mutually-exclusive `sce setup` target selectors (`--opencode`, `--claude`, `--pi`, `--all`) that force non-interactive mode for automation; `--all` expands to opencode+claude+pi and replaced the removed `--both` flag. - `setup mode contract`: `cli/src/services/setup/mod.rs` model where `SetupMode::Interactive` is the default and `SetupMode::NonInteractive(SetupTarget)` is selected only when exactly one target flag is provided. - `setup interactive target prompt`: `inquire::Select` flow in `cli/src/services/setup/mod.rs` (`InquireSetupTargetPrompter`) that presents OpenCode, Claude, Pi, and All (OpenCode + Claude + Pi) when `sce setup` runs without target flags. @@ -79,7 +79,8 @@ - `setup required-hook install orchestration`: Setup-service flow in `cli/src/services/setup/mod.rs` (`install_required_git_hooks`) that resolves repository root + effective hooks directory via git truth, installs canonical required hooks with deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`), enforces executable permissions, and uses a unified remove-and-replace policy that removes existing hooks before swapping staged content with deterministic recovery guidance on swap failure. - `setup hooks CLI mode`: `sce setup` behavior activated by `--hooks` (with optional `--repo `), supporting both hooks-only runs and composable target+hooks runs in one invocation; implemented through `cli/src/services/setup/command.rs` + `cli/src/services/setup/mod.rs`, enforces deterministic compatibility validation (`--repo` requires `--hooks`; target flags remain mutually exclusive), and emits stable setup/hook status output. - `setup repo gate`: Preflight check in `cli/src/services/setup/command.rs` that calls `cli/src/services/setup/mod.rs` (`ensure_git_repository`) before any setup writes begin; enforces that all `sce setup` modes (config-only, hooks-only, combined, and interactive) require the current directory to be inside a git repository, failing with actionable guidance to run `git init` and rerun `sce setup` when the precondition is not met. -- `setup local bootstrap`: Pre-install setup bootstrap behavior now owned by lifecycle providers: `ConfigLifecycle::setup` creates missing `.sce/config.json` with the canonical schema-only payload (`{"$schema": "https://sce.crocoder.dev/config.json"}`), `LocalDbLifecycle::setup` initializes the canonical local DB via `LocalDb::new()`, and `AgentTraceDbLifecycle::setup` creates/reuses checkout identity, resolves repository identity, initializes the repository-scoped Agent Trace DB via `agent_trace_storage`, and records repository ID, checkout ID, and `database_path`; the setup command aggregates these calls before config/hooks dispatch across all setup modes. +- `setup local bootstrap`: Pre-install setup bootstrap behavior now owned by lifecycle providers: `ConfigLifecycle::setup` creates missing `.sce/config.json` with the canonical schema-only payload (`{"$schema": "https://sce.crocoder.dev/config.json"}`), `LocalDbLifecycle::setup` initializes the canonical local DB via `LocalDb::new()`, and `AgentTraceDbLifecycle::setup` creates/reuses checkout identity, resolves repository identity, initializes the repository-scoped Agent Trace DB via `agent_trace_storage`, and records repository ID, checkout ID, and `database_path`; the setup command aggregates these calls before config/hooks dispatch across all normal setup modes after context baseline bootstrap. +- `setup context baseline bootstrap`: Additive durable-context tree bootstrap in `cli/src/services/setup/mod.rs` (`bootstrap_context_baseline`) that create-if-missing writes neutral baseline Markdown files, working directories, and `context/tmp/.gitignore` via `RepoPaths` accessors. `sce setup --bootstrap-context` is the dedicated context-only mode and must be used alone; every normal successful setup path also ensures the same baseline after the Git gate and before lifecycle/config install work without overwriting existing content. - `CLI redaction-safe diagnostics contract`: baseline security behavior implemented via `cli/src/services/security.rs` (`redact_sensitive_text`) and applied to app-level errors, setup git-diagnostic surfacing, and observability output sinks so common secret-bearing token forms are masked before emission. - `setup directory write-permission probe`: deterministic pre-write guard implemented in `cli/src/services/security.rs` (`ensure_directory_is_writable`) and used by setup install/hook flows to fail fast with actionable remediation when target directories are not writable. - `setup --repo canonical path guard`: setup-hook runtime behavior in `cli/src/services/setup/mod.rs` that canonicalizes and validates user-supplied `--repo` paths as existing directories before git-root/hooks-path resolution. diff --git a/context/overview.md b/context/overview.md index a9f0c560..496addca 100644 --- a/context/overview.md +++ b/context/overview.md @@ -23,9 +23,9 @@ The app command dispatcher now enforces a centralized stdout/stderr stream contr The CLI now also enforces a shared output-format parser contract in `cli/src/services/output_format.rs`, with canonical `--format ` parsing and command-specific actionable invalid-value guidance reused by `config` and `version` services. A compile-safe service lifecycle seam also exists in `cli/src/services/lifecycle.rs`: `ServiceLifecycle` exposes default no-op `diagnose`, `fix`, and `setup` methods against the narrow `HasRepoRoot` accessor, uses lifecycle-owned health/fix/setup result types, and owns the shared static `LifecycleProvider` enum catalog/factory with deterministic config → local_db → auth_db → agent_trace_db → hooks ordering and no boxed provider aggregation. Hooks has a `services/hooks/lifecycle.rs` provider for hook rollout diagnosis/fix/setup, config has a `services/config/lifecycle.rs` provider for global/repo-local config validation plus repo-local config bootstrap, local_db has a `services/local_db/lifecycle.rs` provider for canonical local DB path health, parent-directory readiness/bootstrap, and `LocalDb::new()` setup, auth_db has a `services/auth_db/lifecycle.rs` provider for canonical auth DB path health, parent-directory readiness/bootstrap, and `AuthDb::new()` setup, and agent_trace_db has a `services/agent_trace_db/lifecycle.rs` provider for repository-scoped Agent Trace DB setup and repository DB path health/parent readiness from resolved repository identity, returning an actionable "requires a Git repository" diagnostic outside repository context (no global/checkout fallback path). Doctor runtime aggregates the full shared provider catalog for `diagnose` and `fix` and adapts lifecycle records into doctor-owned output records; setup command aggregates the shared provider catalog for `setup` with hooks included only when requested and adapts lifecycle setup outcomes before rendering setup-owned messages. Agent Trace lifecycle setup now resolves repository storage, creates/reuses checkout identity for diagnostics, and initializes `/sce/repos//agent-trace.db` via `RepositoryAgentTraceDb`; hook runtime lazy initialization uses the same repository storage resolver when setup has not prepared the DB or schema metadata is incomplete. The CLI now also includes a shared text styling service in `cli/src/services/style.rs` that provides deterministic color enablement via `owo-colors`, automatic TTY detection, and `NO_COLOR` compliance for human-facing text output; stdout help/text surfaces, stderr diagnostics, and interactive prompt-adjacent text now reuse that shared styling policy while JSON, completion, and other non-interactive/machine-readable flows remain unstyled. The service exports color-detection, conditional styling, help/diagnostic/label/prompt styling, and `banner_with_gradient()` helpers for use across command surfaces while preserving pipe-safe output for non-interactive environments. -The `setup` command includes an `inquire`-backed target-selection flow: default interactive selection for OpenCode/Claude/Pi/All with required-hook installation in the same run, explicit non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`), deterministic mutually-exclusive validation, and non-destructive cancellation exits; the former `--both` flag was removed in favor of `--all` (opencode+claude+pi). +The `setup` command includes an `inquire`-backed target-selection flow: default interactive selection for OpenCode/Claude/Pi/All with required-hook installation in the same run, explicit non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`), standalone `--bootstrap-context` for additive durable-context baseline creation without integration installs, deterministic mutually-exclusive validation, and non-destructive cancellation exits; the former `--both` flag was removed in favor of `--all` (opencode+claude+pi). Every normal successful setup path also ensures the same context baseline after the Git gate. For repository Cargo builds, `scripts/run-cli-cargo.sh` evaluates the canonical `config/pkl/generate.pkl` model twice into a fresh temporary generated-input directory, rejects nondeterminism, and records SHA-256 inventories for both the payload and canonical generator inputs before invoking the requested Cargo workflow with `SCE_CLI_GENERATED_INPUT_DIR`. The wrapper cleans up after Cargo success, failure, or handled signals. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, copies the validated payload into Cargo `OUT_DIR/pkl-generated`, stages hook templates, the Agent Trace schema, and SQL migrations under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`; it never invokes Pkl. `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths, embedded bytes, and target-scoped iteration without runtime reads from `config/`; production setup, policy, config-schema, Agent Trace, and migration includes all resolve through `OUT_DIR`. Published crates instead carry an ignored, packaging-only fallback generated deterministically from the same canonical inputs before `cargo package`; unpacked downstream builds validate and copy that payload into their own `OUT_DIR` without requiring Pkl or parent repository paths. -The setup service also provides repository-root install orchestration: it resolves the repository root, derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup uses a unified remove-and-replace policy for all write flows — it removes existing targets before swapping staged content and returns deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs` now separates install-flow logic from interactive prompt logic through focused support seams. +The setup service also provides repository-root install orchestration: it resolves the repository root, ensures the additive durable-context baseline, then for normal modes derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup uses a unified remove-and-replace policy for all write flows — it removes existing targets before swapping staged content and returns deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs` now separates install-flow logic from interactive prompt logic through focused support seams. The CLI now also applies baseline security hardening for reliability-driven automation: diagnostics/logging paths use deterministic secret redaction, `sce setup --hooks --repo ` canonicalizes and validates repository paths before execution, and setup write flows run explicit directory write-permission probes before staging/swap operations. The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_file`, `log_file_mode`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config_root}/sce/config.json` then `.sce/config.json` with local override, where `config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_file_mode=truncate`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by` wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as `nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json` JSON Schema generated beneath Cargo `OUT_DIR` and embedded by `cli/src/services/config/mod.rs` for both `sce config validate` and doctor-time config checks. Runtime startup config loading now keeps parity with that schema by accepting the canonical `"$schema": "https://sce.crocoder.dev/config.json"` declaration in repo-local and global config files, so startup commands such as `sce version` no longer fail before dispatch on that field. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for file logging; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/data/bash-policy-presets.json` and `context/sce/bash-tool-policy-enforcement-contract.md`. Invalid default-discovered config files now also degrade gracefully at startup: `sce` keeps running with degraded observability defaults, logs `sce.config.invalid_config` warnings, and reserves hard failures for explicit `--config` / `SCE_CONFIG_FILE` targets or other truly invalid runtime observability inputs. diff --git a/context/patterns.md b/context/patterns.md index eb7f74c9..e87eeffb 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -108,6 +108,7 @@ - For runtime CLI configuration, keep precedence deterministic and explicit (`flags > env > config file > defaults`) and expose inspect/validate command entrypoints with stable text/JSON outputs. - For commands that support text/JSON dual output, centralize `--format ` parsing in one shared contract and pass command-specific `--help` guidance into invalid-value errors instead of duplicating parser logic per command. - For setup-style command contracts, keep interactive mode as the zero-flag default and enforce mutually-exclusive explicit target flags for non-interactive automation. +- For durable-context bootstrap, keep create-if-missing additive semantics: ensure baseline paths on every successful setup path, offer a dedicated standalone `--bootstrap-context` mode, and never overwrite existing context content. - For security-sensitive CLI UX, redact common secret-bearing token/value forms before emitting diagnostics/log lines, including app-level errors, setup git stderr diagnostics, and observability sink output. - For user-supplied setup repository paths (`sce setup --hooks --repo `), canonicalize/validate the path as an existing directory before git command execution, and run deterministic write-permission probes on setup write targets before staging/swap operations. - For interactive setup flows, isolate prompt handling behind a service-layer prompter seam so selection mapping and cancellation behavior can be tested without a live TTY. diff --git a/context/plans/setup-bootstrap-context.md b/context/plans/setup-bootstrap-context.md new file mode 100644 index 00000000..73e5be0a --- /dev/null +++ b/context/plans/setup-bootstrap-context.md @@ -0,0 +1,114 @@ +# Plan: setup-bootstrap-context + +## Change summary + +Add an additive context bootstrap mode to `sce setup`. `sce setup --bootstrap-context` creates the baseline durable-context files and working directories without entering interactive integration setup, while every normal successful setup path also ensures the same baseline exists before continuing. Existing context files and directory contents remain untouched. + +This closes a documented-but-unimplemented seam: durable workflow rules already name `sce setup --bootstrap-context` as the bootstrap boundary, while the setup CLI today only bootstraps repo-local config and lifecycle DBs. Path accessors for the baseline tree already live in `cli/src/services/default_paths.rs`; the change wires create-if-missing filesystem bootstrap, request routing, and focused tests on top of that catalog. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: `sce setup --bootstrap-context` creates `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, `context/context-map.md`, `context/plans/`, `context/handovers/`, `context/decisions/`, `context/tmp/`, and `context/tmp/.gitignore` in a Git repository without prompting for an integration target or installing integration assets. + - Validate: Run the packaged CLI in a temporary initialized Git repository with `sce setup --bootstrap-context`, then assert that every listed path exists and no `.opencode/`, `.claude/`, or `.pi/` directory was created. +- [x] AC2: Context bootstrap is additive and idempotent: rerunning it fills missing baseline paths but does not overwrite existing context documents, plans, decisions, handovers, or scratch-ignore content. + - Validate: Run the targeted bootstrap integration coverage that seeds sentinel content, removes selected baseline paths, reruns bootstrap, and asserts sentinel content is unchanged while missing paths are restored. +- [x] AC3: Normal `sce setup` modes ensure the baseline context tree exists in addition to their existing setup behavior. + - Validate: Run targeted setup request/orchestration coverage for a normal non-interactive setup and assert the baseline context paths are created while the selected integration setup still runs. +- [x] AC4: `sce setup --help` documents `--bootstrap-context`, and parser/request conversion routes the flag to a deterministic context-only setup request when used alone. + - Validate: Run targeted parser/help tests and inspect `sce setup --help` for `--bootstrap-context`. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/sce/context-workflow-rules.md` with the implemented additive/idempotent bootstrap semantics. +- Update `context/sce/setup-repo-local-config-bootstrap.md` and `context/cli/cli-command-surface.md` with the setup flag, context-only behavior, and automatic normal-setup bootstrap. +- Update `context/cli/default-path-catalog.md` if the implementation adds a named `context/tmp/.gitignore` path accessor. +- Update `context/context-map.md` annotations when the setup/bootstrap ownership descriptions change. + +## Constraints and non-goals + +- **In scope:** The setup clap schema, setup request conversion and execution, canonical context paths in `cli/src/services/default_paths.rs`, additive baseline file/directory creation, deterministic help/output, and focused Rust/integration coverage. +- **Out of scope:** Generating repository-specific architecture or application knowledge, changing `/change-to-plan` workflow behavior, or modifying integration asset contents. +- **Constraints:** Keep path ownership in `default_paths.rs`; require the existing Git-repository gate; never overwrite existing context content; use repository Nix/Cargo wrapper conventions and stable CLI diagnostics. +- **Non-goal:** This change does not populate durable context with inferred codebase facts or turn `context/tmp/` into persisted runtime storage. + +## Assumptions + +- Used alone, `--bootstrap-context` is a non-interactive context-only setup mode; combining it with target or hook options is unnecessary because normal setup paths bootstrap context automatically. +- Missing individual baseline files or directories are repaired additively even when `context/` already exists. +- New Markdown files use deterministic neutral headings/placeholders, `context/context-map.md` links the baseline entry points and working directories without inventing repository details, and `context/tmp/.gitignore` ignores scratch content while retaining itself. +- Existing `RepoPaths` context accessors and constants in `default_paths.rs` are reused; a named accessor for `context/tmp/.gitignore` is added only if production code needs one. + +## Task stack + +- [x] T01: `Add additive context bootstrap to setup` (status:done) + - Task ID: T01 + - Goal: Implement the dedicated `sce setup --bootstrap-context` path and make normal setup ensure the same durable-context baseline without changing existing content. + - Boundaries (in/out of scope): In — canonical context path accessors/constants, baseline templates, additive/idempotent filesystem bootstrap, setup request/parser/help wiring, context-only execution, normal setup orchestration, and focused tests. Out — generated agent assets, application-specific context generation, and workflow-command changes. + - Dependencies: none + - Done when: The dedicated flag creates exactly the requested baseline without prompting or installing integrations; normal setup also ensures the baseline; reruns preserve existing content and restore missing paths; parser/help and filesystem behavior have focused automated coverage. + - Verification notes (commands or checks): `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup`; targeted packaged-CLI smoke run in a temporary Git repository if the integration assertions are not fully covered by the Rust test target. + - Completed: 2026-07-28 + - Files changed: `cli/src/cli_schema.rs`, `cli/src/command_surface.rs`, `cli/src/services/default_paths.rs`, `cli/src/services/parse/command_runtime.rs`, `cli/src/services/command_registry.rs`, `cli/src/services/setup/mod.rs`, `cli/src/services/setup/command.rs` + - Evidence: `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup` -> exit 0 (14 passed). Coverage includes resolve/parser routing for `--bootstrap-context`, help documentation, additive baseline creation without integration dirs, and idempotent restore of missing paths while preserving sentinel content. + - Notes: `--bootstrap-context` is context-only and must be used alone; every normal successful setup path calls the same additive `bootstrap_context_baseline` after the Git gate. Added `RepoPaths::context_tmp_gitignore_file` for `context/tmp/.gitignore`. + +- [x] T02: `Fix rustfmt drift in setup bootstrap code` (status:done) + - Task ID: T02 + - Goal: Resolve the `cli-fmt` failure recorded in the prior Validation Report by formatting `cli/src/services/setup/mod.rs` with the project's rustfmt configuration, with no behavior change. + - Boundaries (in/out of scope): In — running `cargo fmt` (or equivalent) over `cli/src/services/setup/mod.rs` and any other files it touches, confirming no functional diffs. Out — any change to bootstrap behavior, task T01 scope, or other services. + - Dependencies: T01 + - Done when: `nix develop -c sh -c 'cd cli && cargo fmt --check'` reports no diffs and `nix flake check`'s `cli-fmt` derivation passes. + - Verification notes (commands or checks): `nix develop -c sh -c 'cd cli && cargo fmt'`; `nix develop -c sh -c 'cd cli && cargo fmt --check'`; `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup`. + - Completed: 2026-07-28 + - Files changed: `cli/src/services/setup/mod.rs` + - Evidence: `nix develop -c sh -c 'cd cli && cargo fmt'` applied formatting-only changes (compact `with_context` closures, import order, multi-line literal formatting) with no functional diff; `nix build .#checks.x86_64-linux.cli-fmt --no-link` -> exit 0; `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup` -> exit 0 (14 passed). + - Notes: `nix flake check` still reports an unrelated `cli-clippy` failure (`convert_setup_command` has 8/7 arguments in `cli/src/services/parse/command_runtime.rs:406`), pre-existing from T01 and out of scope for this formatting-only task. + +## Open questions + +None. This task closes the one outstanding failed check (`cli-fmt`) from the prior validation attempt; no new scope or ambiguity is introduced. + +## Validation Report + +**Status:** failed +**Date:** 2026-07-28 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral Pkl generation passed; inventory sha256 f465ad7139a66f8530581186b8db77405afa7203be9a6ce9e6de9624e238cd0b) +- `nix flake check` -> exit 1 (`checks.x86_64-linux.cli-clippy` failed: `error: this function has too many arguments (8/7)` at `cli/src/services/parse/command_runtime.rs:406` in `convert_setup_command`; `-D clippy::too-many-arguments` implied by `-D clippy::all`) +- `nix build .#checks.x86_64-linux.cli-tests --no-link` -> exit 0 (180 passed; 0 failed; includes `bootstrap_context_baseline_creates_expected_paths` and `bootstrap_context_baseline_is_additive_and_idempotent`) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: `--bootstrap-context` creates the full baseline without integration assets -> packaged CLI smoke in temp Git repo (prior run); unit test `bootstrap_context_baseline_creates_expected_paths` (rerun, passing) +- [x] AC2: additive and idempotent bootstrap -> unit test `bootstrap_context_baseline_is_additive_and_idempotent` (rerun, passing; sentinels preserved, missing paths restored) +- [x] AC3: normal setup also ensures baseline while integration still runs -> packaged CLI `setup --pi --non-interactive` created full baseline and installed Pi (prior run); request resolution tests keep normal modes non-`context_only` (rerun, passing) +- [x] AC4: help and parser route `--bootstrap-context` -> unit tests `help_documents_bootstrap_context_flag`, `parser_routes_bootstrap_context_to_context_only_request`, `resolve_setup_request_accepts_bootstrap_context_alone` (rerun, passing); packaged `setup --help` lists the flag (prior run) + +### Failed checks and follow-ups + +- `nix flake check` / `cli-clippy`: `convert_setup_command` in `cli/src/services/parse/command_runtime.rs:406` has 8 parameters, exceeding clippy's `too_many_arguments` threshold of 7 under `-D clippy::all`; evidence: `nix build .#checks.x86_64-linux.cli-clippy` builder log (`error: this function has too many arguments (8/7)`); required: reduce the parameter count (e.g. group the setup flags into a request/options struct) or apply a scoped `#[allow(clippy::too_many_arguments)]` if the signature is intentional, then rerun full validation. This surfaced only now because the prior `cli-fmt` failure (fixed by T02) previously stopped `nix flake check` before it reached `cli-clippy`; it is pre-existing from T01, not introduced by T02, but it still blocks required full validation and must be resolved before the plan can validate. + +### Residual risks + +- Normal packaged setup without a repository identity (`origin` remote or `agent_trace.repository_id`) still fails later lifecycle steps after context baseline is ensured; that is pre-existing identity gating, not a bootstrap regression, but empty-repo smoke must supply identity when asserting end-to-end normal setup. + +### Retry + +After repairs, rerun: + +`/validate context/plans/setup-bootstrap-context.md` diff --git a/context/sce/context-workflow-rules.md b/context/sce/context-workflow-rules.md index f851ec45..b1752252 100644 --- a/context/sce/context-workflow-rules.md +++ b/context/sce/context-workflow-rules.md @@ -18,7 +18,15 @@ stops. It does not create durable context. The user bootstraps it with: `sce setup --bootstrap-context` -That command owns creation of the baseline context tree. The baseline contains: +That command is the dedicated context-only setup mode: it creates the baseline +context tree without prompting for an integration target or installing +integration assets. Normal successful `sce setup` paths also ensure the same +baseline exists before continuing. Bootstrap is additive and idempotent: +missing baseline files and directories are created with neutral placeholders, +while existing context documents, plans, decisions, handovers, and scratch +ignore content are never overwritten. + +The baseline contains: - `context/overview.md` - `context/architecture.md` diff --git a/context/sce/setup-repo-local-config-bootstrap.md b/context/sce/setup-repo-local-config-bootstrap.md index c6ff4150..95c64c55 100644 --- a/context/sce/setup-repo-local-config-bootstrap.md +++ b/context/sce/setup-repo-local-config-bootstrap.md @@ -2,7 +2,7 @@ ## Scope -Task `setup-repo-gate-and-local-config-bootstrap` T02 and `turso-local-db-sync` T04 define the local bootstrap behavior for `sce setup`. +Task `setup-repo-gate-and-local-config-bootstrap` T02, `turso-local-db-sync` T04, and `setup-bootstrap-context` T01 define the local bootstrap behavior for `sce setup`. ## Behavior @@ -11,7 +11,17 @@ Task `setup-repo-gate-and-local-config-bootstrap` T02 and `turso-local-db-sync` - If `.sce/config.json` already exists, the bootstrap step returns `Ok(())` immediately and leaves the file untouched — no merge, no reformat, no overwrite. - The parent `.sce/` directory is created via `fs::create_dir_all` if missing. - The setup flow also bootstraps the canonical local DB through `LocalDbLifecycle::setup` and the Agent Trace DB through `AgentTraceDbLifecycle::setup`; both use the shared `TursoDb` adapter. -- The bootstrap runs after the git-repo gate (`ensure_git_repository`) and before config/hooks dispatch, so it applies to all setup modes: config-only, hooks-only, combined, and interactive. +- Config/DB bootstrap runs after the git-repo gate (`ensure_git_repository`) and after context baseline bootstrap, and before config/hooks dispatch, so it applies to all normal setup modes: config-only, hooks-only, combined, and interactive. + +## Context baseline bootstrap + +- `sce setup --bootstrap-context` is a non-interactive context-only mode and must be used alone (no target, hooks, non-interactive, or `--repo` flags). +- Context-only setup ensures the Git-repository gate, then creates the baseline durable-context tree and exits without lifecycle providers, integration installs, or prompts. +- Every normal successful setup path also calls the same additive context bootstrap after the Git gate and before lifecycle/config install work. +- Baseline paths: `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, `context/context-map.md`, `context/plans/`, `context/handovers/`, `context/decisions/`, `context/tmp/`, and `context/tmp/.gitignore`. +- Create-if-missing only: existing files and directory contents are left untouched; missing individual paths are restored even when `context/` already exists. +- New Markdown files use neutral headings/placeholders; `context-map.md` links baseline entry points without inventing repository details; `context/tmp/.gitignore` ignores scratch content while retaining itself (`*\n!.gitignore\n`). +- Deterministic success messaging includes `Context baseline ensured.` ## Post-install integration target persistence @@ -27,15 +37,16 @@ After config asset installation succeeds for a non-interactive target (`--openco ## Implementation -- `cli/src/services/setup/mod.rs` exports `bootstrap_repo_local_config(repository_root: &Path) -> Result<()>` and `persist_integration_targets(repository_root: &Path, target: SetupTarget) -> Result<()>`. +- `cli/src/services/setup/mod.rs` exports `bootstrap_repo_local_config(repository_root: &Path) -> Result<()>`, `bootstrap_context_baseline(repository_root: &Path) -> Result`, and `persist_integration_targets(repository_root: &Path, target: SetupTarget) -> Result<()>`. - `cli/src/services/local_db/lifecycle.rs` implements `LocalDbLifecycle::setup()` for local DB initialization. - `cli/src/services/agent_trace_db/lifecycle.rs` implements `AgentTraceDbLifecycle::setup()` for Agent Trace DB initialization. -- The function uses `RepoPaths::sce_config_file()` and `RepoPaths::sce_dir()` from `default_paths` for path resolution. +- Repo-local config bootstrap uses `RepoPaths::sce_config_file()` and `RepoPaths::sce_dir()`; context baseline bootstrap uses the shared context accessors including `RepoPaths::context_tmp_gitignore_file()`. - The canonical payload constant is `REPO_LOCAL_CONFIG_BOOTSTRAP_PAYLOAD`. -- `cli/src/services/setup/command.rs` derives a repo-root-scoped `AppContext` after `ensure_git_repository`, then aggregates lifecycle providers in config → local_db → auth_db → agent_trace_db → hooks order; `ConfigLifecycle::setup()` calls `bootstrap_repo_local_config(...)`, `LocalDbLifecycle::setup()` initializes the local DB, `AuthDbLifecycle::setup()` initializes the auth DB, and `AgentTraceDbLifecycle::setup()` initializes the Agent Trace DB. +- `cli/src/services/setup/command.rs` runs `bootstrap_context_baseline` immediately after `ensure_git_repository`. Context-only requests return there. Normal modes then derive a repo-root-scoped `AppContext` and aggregate lifecycle providers in config → local_db → auth_db → agent_trace_db → hooks order; `ConfigLifecycle::setup()` calls `bootstrap_repo_local_config(...)`, `LocalDbLifecycle::setup()` initializes the local DB, `AuthDbLifecycle::setup()` initializes the auth DB, and `AgentTraceDbLifecycle::setup()` initializes the Agent Trace DB. ## Relationship to other setup contracts -- The git-repo gate (`ensure_git_repository`) was introduced in T01 of the same plan. -- Local bootstrap (repo config + local DB init) is independent of config install and hook install; it runs before both. +- The git-repo gate (`ensure_git_repository`) remains the precondition for every setup write path, including context-only bootstrap. +- Context baseline bootstrap is independent of config/DB/hooks install and runs before those steps on normal setup paths. +- Local bootstrap (repo config + local DB init) is independent of config install and hook install; it runs before both after context baseline bootstrap. - The bootstrap payload matches the `$schema` declaration accepted by startup config loading and the Pkl-authored JSON Schema embedded from Cargo `OUT_DIR`. From 9b37965768b9972664a748b3d0c404f36774cefe Mon Sep 17 00:00:00 2001 From: David Abram Date: Tue, 28 Jul 2026 14:51:15 +0200 Subject: [PATCH 12/21] claude: Implement Markdown workflow result packages Render structured Claude phase results as human-facing Markdown, then fold machine-facing contract details directly into each SKILL.md so package-local references remain presentation-only. Align command handoffs, parser behavior, metadata coverage, generated skills, and durable architecture guidance with the single-reference package model. Plan: claude-markdown-workflow-results (T01) Plan: skill-references-human-presentation-only (T01, T02) Co-authored-by: SCE --- .claude/commands/change-to-plan.md | 10 +- .claude/commands/commit.md | 6 +- .claude/commands/next-task.md | 20 +- .claude/commands/validate.md | 14 +- .claude/skills/sce-atomic-commit/SKILL.md | 143 ++- .../references/commit-contract.yaml | 205 ----- .claude/skills/sce-context-load/SKILL.md | 95 +- .../references/context-brief.yaml | 153 ---- .claude/skills/sce-plan-authoring/SKILL.md | 307 ++++++- .../references/authoring-contract.yaml | 256 ------ .../references/plan-template.md | 170 ---- .claude/skills/sce-plan-context-sync/SKILL.md | 8 + .claude/skills/sce-plan-review/SKILL.md | 122 ++- .../references/readiness-contract.yaml | 246 ------ .claude/skills/sce-task-context-sync/SKILL.md | 8 + .claude/skills/sce-task-execution/SKILL.md | 219 ++++- .../references/execution-contract.yaml | 306 ------- .../references/implementation-gate.md | 8 +- .claude/skills/sce-validation/SKILL.md | 203 ++++- .../references/validation-result.md | 186 ---- cli/src/services/parse/command_runtime.rs | 33 +- config/pkl/README.md | 4 +- config/pkl/renderers/claude-content.pkl | 146 +++- .../pkl/renderers/claude-workflow-results.pkl | 811 ++++++++++++++++++ .../pkl/renderers/metadata-coverage-check.pkl | 27 +- context/architecture.md | 17 +- context/context-map.md | 6 +- ...-07-27-workflow-oriented-pkl-generation.md | 11 +- context/glossary.md | 4 +- context/overview.md | 9 +- context/patterns.md | 9 +- .../plans/claude-markdown-workflow-results.md | 99 +++ ...kill-references-human-presentation-only.md | 108 +++ 33 files changed, 2329 insertions(+), 1640 deletions(-) delete mode 100644 .claude/skills/sce-atomic-commit/references/commit-contract.yaml delete mode 100644 .claude/skills/sce-context-load/references/context-brief.yaml delete mode 100644 .claude/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 .claude/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 .claude/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 .claude/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 .claude/skills/sce-validation/references/validation-result.md create mode 100644 config/pkl/renderers/claude-workflow-results.pkl create mode 100644 context/plans/claude-markdown-workflow-results.md create mode 100644 context/plans/skill-references-human-presentation-only.md diff --git a/.claude/commands/change-to-plan.md b/.claude/commands/change-to-plan.md index 556c578e..41fbe73d 100644 --- a/.claude/commands/change-to-plan.md +++ b/.claude/commands/change-to-plan.md @@ -21,6 +21,8 @@ Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is ## Workflow +Run every step in one turn. Stop only where a step says to wait for the user. + ### 1. Load durable context Invoke `sce-context-load` with the change request as the focus. @@ -46,7 +48,9 @@ Bootstrap it, then continue in this session: Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. -`loaded` -> Continue to the next step. +`loaded` -> The brief is internal workflow input, not workflow output. Do not print it, and do not end your turn. Invoke `sce-plan-authoring` in the same turn. + +This step ends the turn only on `bootstrap_required`. Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. @@ -100,7 +104,9 @@ Do not answer the questions. Do not assume answers. Do not write a plan. Stop an Stop. -`plan_ready` -> Continue to the next step. +`plan_ready` -> An authoring result is never presented to the user as workflow output. Do not print it, and do not end your turn. Continue to the next step in the same turn. + +This step ends the turn only on `needs_clarification` or `blocked`. ### 3. Determine the continuation diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md index 2975a132..60d20384 100644 --- a/.claude/commands/commit.md +++ b/.claude/commands/commit.md @@ -33,6 +33,8 @@ command never stages, unstages, or modifies files. ## Workflow +Run every step in one turn. Stop only where a step says to wait for the user. + Follow exactly one path. ### Bypass path (`oneshot` or `skip`) @@ -59,7 +61,9 @@ The skill must return a result matching its commit contract. Branch on `blocked` -> Present the issue and stop. Do not commit. -`bypass_message` -> Continue to the next step. +`bypass_message` -> The message is internal workflow input, not workflow output. Do not print it as the deliverable, and do not end your turn. The commit is this path's deliverable, so continue to the next step in the same turn. + +This step ends the turn only on `blocked` or a contract violation. The skill never returns `proposal` in bypass mode. Treat a `proposal` result as a contract violation: report it and stop without committing. diff --git a/.claude/commands/next-task.md b/.claude/commands/next-task.md index a52e26ff..c5846c65 100644 --- a/.claude/commands/next-task.md +++ b/.claude/commands/next-task.md @@ -26,6 +26,8 @@ Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is ## Workflow +Run every step in one turn. Stop only where a step says to wait for the user. + ### 1. Review the task Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. @@ -66,7 +68,11 @@ Run the final validation: Stop. -`ready` -> Pass the complete readiness result to `sce-task-execution`. +`ready` -> A readiness result is never presented to the user. Do not print it, and do not end your turn. Pass the complete readiness result to `sce-task-execution` in the same turn. + +The readiness result is a compact handoff: plan and task identity, relevant files, relevant context, and review assumptions. It deliberately omits the task's goal, scope, done checks, dependencies, and verification, which `sce-task-execution` reads from the plan and presents in its implementation gate. Do not reconstruct the omitted fields, and do not treat their absence as a stale handoff. + +This step ends the turn only on `blocked` or `plan_complete`. Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. @@ -111,13 +117,17 @@ Do not invoke context synchronization. Stop. Do not invoke context synchronization. Do not select another task. Stop. -`complete` -> continue to the next step. +`complete` -> Do not print the raw result, and do not end your turn. Invoke `sce-task-context-sync` in the same turn. + +This result stays full-size: `sce-task-context-sync` validates the changed files, implementation summary, verification evidence, done-check evidence, and context impact, and blocks when any is missing. Pass it through untouched rather than trimming it to match the compact readiness handoff. + +This step ends the turn only on `declined`, `blocked`, or `incomplete`. ### 3. Synchronize context Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. +Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, implementation summary, verification evidence, done-check evidence, and reported context impact out of it. Do not restate, summarize, or reconstruct any part of the execution result. @@ -135,7 +145,9 @@ State that durable context is now out of date, and that synchronization must be Do not select another task. Stop. -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. +`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned, then continue to the next step in the same turn. Do not end your turn before the continuation block. + +This step ends the turn only on `blocked`. ### 4. Determine the continuation diff --git a/.claude/commands/validate.md b/.claude/commands/validate.md index bbaeca4f..005c733f 100644 --- a/.claude/commands/validate.md +++ b/.claude/commands/validate.md @@ -27,6 +27,8 @@ candidate path), so every emitted command is directly runnable. ## Workflow +Run every step in one turn. Stop only where a step says to wait for the user. + ### 1. Validate the plan Invoke `sce-validation` with the plan name or path. @@ -59,8 +61,11 @@ Stop. Do not mark the plan finished. Do not continue to context synchronization. Do not start the repair work in this workflow unless the user explicitly asks to continue here; the default is that the handoff can leave this session. -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. +`validated` -> A validated result is never presented to the user as workflow +output. Do not print it, and do not end your turn. Pass the complete validated +Markdown result to `sce-plan-context-sync` in the same turn. + +This step ends the turn only on `blocked` or `failed`. Do not reconstruct, summarize, or reinterpret the validation result before passing it. @@ -99,7 +104,10 @@ so it is lost once this session ends. Stop. `synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. +`sce-plan-context-sync` returned, then continue to the next step in the same +turn. Do not end your turn before the completion block. + +This step ends the turn only on `blocked`. ### 3. Report completion diff --git a/.claude/skills/sce-atomic-commit/SKILL.md b/.claude/skills/sce-atomic-commit/SKILL.md index 0365ae94..ff7aec5c 100644 --- a/.claude/skills/sce-atomic-commit/SKILL.md +++ b/.claude/skills/sce-atomic-commit/SKILL.md @@ -3,7 +3,7 @@ name: sce-atomic-commit description: > Internal SCE workflow skill that analyzes the staged diff and returns atomic, repository-style commit messages: coherent-unit detection, split guidance, - scope and subject wording, and the plan-citation body rule. Returns one YAML + scope and subject wording, and the plan-citation body rule. Returns one Markdown result (proposal, bypass_message, or blocked). Use from /commit. Do not stage files, create commits, or ask the user to confirm staging. compatibility: claude @@ -22,7 +22,7 @@ This skill owns: - Choosing the scope and writing the subject and body of every message. - Applying the plan-citation body rule. - Classifying staged scope and applying context-file guidance gating. -- Returning one terminal YAML result. +- Returning one terminal Markdown result. Write messages matching: @@ -30,7 +30,7 @@ Write messages matching: Return a result matching: -`references/commit-contract.yaml` +the **Result contract** section in this file Committing is not this skill's job. The invoking `/commit` workflow decides whether a returned message is committed, and it is the only thing that runs @@ -131,15 +131,15 @@ Confirm before returning that: - No plan slug or task ID appears that the staged diff does not support. - The mode's own constraints hold. -### 9. Return YAML +### 9. Return Markdown -Return exactly one YAML document matching `references/commit-contract.yaml`: +Return exactly one Markdown document matching the **Result contract** section in this file: - `proposal` in `regular` mode, with one or more messages. - `bypass_message` in `bypass` mode, with exactly one message. - `blocked` when messages cannot be written faithfully. -Return only the YAML document. Do not add explanatory prose before or after it. +Return only the Markdown document. Do not add explanatory prose before or after it. ## Boundaries @@ -163,5 +163,134 @@ The skill is complete after: - The staged diff was read, or reading it failed and was reported. - Messages were written for every staged file, or a blocker prevented it. -- One valid terminal YAML result matching `references/commit-contract.yaml` was +- One valid terminal Markdown result matching the **Result contract** section in this file was returned. + +## Result contract + +# SCE Atomic Commit Result Contract + +Return exactly one Markdown document using one layout below. `Status` is the +branch value consumed by `/commit`. Use every required heading and label +exactly as written, omit optional sections that do not apply, and do not add +prose outside the selected layout. + +Report paths exactly as `git diff --cached --name-only` reports them. Every +staged file belongs to exactly one proposed commit. Keep each message's body +in the same fenced block as its subject, separated by one blank line. Never +report a commit hash or guidance forbidden by the mode. + +## Status: `proposal` + +Use only in regular mode. Nothing is committed. + +````markdown +# Atomic Commit Result + +Status: proposal +Mode: regular + +## Commits + +### {commit.id} + +#### Message + +```text +{subject} + +{body} +``` + +#### Files + +- {file} + +#### Cites plan + +{true|false} + +## Split rationale + +{split_rationale} + +## Scope classification + +{context_only|mixed} + +## Notes + +- {note} +```` + +`Commits` is required. Repeat the commit block as needed. Include `Split +rationale` only for multiple commits. `Scope classification` and `Notes` are +optional. + +## Status: `bypass_message` + +Use only in bypass mode. Exactly one message covers every staged file. + +````markdown +# Atomic Commit Result + +Status: bypass_message +Mode: bypass + +## Message + +```text +{subject} + +{body} +``` + +## Files + +- {file} + +## Cites plan + +{true|false} + +## Notes + +- {note} +```` + +`Message` and `Files` are required. `Cites plan` and `Notes` are optional. +Never include commits, split rationale, or scope classification. + +## Status: `blocked` + +````markdown +# Atomic Commit Result + +Status: blocked +Mode: {regular|bypass} + +## Files + +- {file} + +## Issues + +### {issue.id} + +- Category: {no_staged_changes|plan_citation_ambiguity|unreadable_diff|contradictory_context} +- Problem: {problem} +- Impact: {impact} +- Decision required: {decision_required} +```` + +`Issues` is required. Include `Mode` when supplied and `Files` when staged +files were read. Plan-citation ambiguity blocks only in regular mode; bypass +mode omits the citation instead. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-atomic-commit/references/commit-contract.yaml b/.claude/skills/sce-atomic-commit/references/commit-contract.yaml deleted file mode 100644 index 5ffdd9ff..00000000 --- a/.claude/skills/sce-atomic-commit/references/commit-contract.yaml +++ /dev/null @@ -1,205 +0,0 @@ -version: 1 -name: sce-atomic-commit-result - -description: > - Output contract for sce-atomic-commit. The skill returns exactly one YAML - document representing proposal, bypass_message, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be proposal, bypass_message, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. - - Return proposal only in regular mode, and bypass_message only in bypass - mode. blocked is valid in both. - - Every staged file must appear under exactly one commit's files. - - Report file paths exactly as `git diff --cached --name-only` reports them. - - Carry the message body inside message, separated from the subject by one - blank line. Do not split it into a separate field. - - Do not include a commit hash. This skill never commits. - - Do not report guidance the mode forbids. - -variants: - - proposal: - meaning: > - The staged changes were analyzed in regular mode and one or more atomic - commit messages were written. Proposal-only: nothing was committed. - - required_fields: - - status - - mode - - commits - - optional_fields: - - split_rationale - - scope_classification - - notes - - field_rules: - - Include split_rationale only when commits holds more than one entry. - - scope_classification reports the context-file guidance gate as - context_only or mixed. - - shape: - status: proposal - mode: regular - - commits: - - id: string - message: string - files: - - string - cites_plan: boolean - - split_rationale: string - scope_classification: context_only | mixed - - notes: - - string - - example: - status: proposal - mode: regular - - commits: - - id: C01 - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full - re-login. Adds the refresh handler and reuses the existing token - issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - - id: C02 - - message: | - build: Pin the formatter to the toolchain version - - The formatter floated across environments and produced diff noise - unrelated to any change. - - files: - - flake.nix - - cites_plan: false - - split_rationale: > - The refresh endpoint and the formatter pin pursue unrelated goals and - share no files. Committing them together would hide the build change - behind a feature subject. - - scope_classification: mixed - - bypass_message: - meaning: > - The staged changes were analyzed in bypass mode and exactly one commit - message covering all staged files was written. The invoking workflow - executes the commit. - - required_fields: - - status - - mode - - message - - files - - optional_fields: - - cites_plan - - notes - - field_rules: - - files lists every staged file, because one message covers all of them. - - Never include commits, split_rationale, or scope_classification. - - shape: - status: bypass_message - mode: bypass - - message: string - - files: - - string - - cites_plan: boolean - - notes: - - string - - example: - status: bypass_message - mode: bypass - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full re-login. - Adds the refresh handler and reuses the existing token issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - blocked: - meaning: > - Faithful commit messages cannot be written from the staged changes. - - required_fields: - - status - - issues - - optional_fields: - - mode - - files - - field_rules: - - Include mode whenever the workflow supplied one. - - Include files when staged files were read before blocking. - - Plan-citation ambiguity blocks in regular mode only. In bypass mode the - citation is omitted instead. - - shape: - status: blocked - mode: regular | bypass - - files: - - string - - issues: - - id: string - category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context - problem: string - impact: string - decision_required: string - - example: - status: blocked - mode: regular - - files: - - context/plans/authentication.md - - issues: - - id: B01 - category: plan_citation_ambiguity - - problem: > - The staged plan diff changes two task checkboxes and does not - expose which task this commit completes. - - impact: > - The commit body would cite a task ID the staged diff does not - support. - - decision_required: > - State the completed task ID, or stage only that task's plan edit. diff --git a/.claude/skills/sce-context-load/SKILL.md b/.claude/skills/sce-context-load/SKILL.md index 67e569b8..70db93f3 100644 --- a/.claude/skills/sce-context-load/SKILL.md +++ b/.claude/skills/sce-context-load/SKILL.md @@ -3,7 +3,7 @@ name: sce-context-load description: > Internal SCE workflow skill that loads the durable context in `context/` relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and + one Markdown result: loaded or bootstrap_required. Use from /change-to-plan and any workflow that needs durable context before acting. Do not modify context, repair drift, plan, or implement. compatibility: claude @@ -30,7 +30,7 @@ This skill owns: Return a result matching: -`references/context-brief.yaml` +the **Result contract** section in this file ## Input @@ -126,4 +126,93 @@ The skill is complete after: - The context root was confirmed, or `bootstrap_required` was returned. - The entry points were read, and the relevant domain context was selected and read. -- One valid result matching `references/context-brief.yaml` was returned. +- One valid result matching the **Result contract** section in this file was returned. + +## Result contract + +# SCE Context Load Result Contract + +Return exactly one Markdown document using one layout below. The first line +after the title is the status source consumed by the invoking command. Use +the headings and labels exactly as written, omit optional sections that do +not apply, and do not add prose outside the selected layout. + +List every file read and no file that was not read. Key facts are durable +statements, not planning or implementation recommendations. Empty required +lists must contain `- None.`. This skill never reports context edits. + +## Status: `loaded` + +Use when the context root exists and relevant context was read. + +```markdown +# Context Load Result + +Status: loaded + +## Context root + +{context_root} + +## Entry points + +### {path} + +- Read: {true|false} +- Reason: {reason; omit only when read is true and no reason is needed} + +## Domain context + +### {path} + +**Relevance:** {relevance} + +**Key facts:** + +- {key_fact} + +## Gaps + +### {area} + +{detail} + +## Drift + +### {path} + +- Context says: {context_says} +- Code says: {code_says} +- Repair needed: {repair_needed} +``` + +`Context root`, `Entry points`, `Domain context`, and `Gaps` are required. +Repeat the entry-point, domain-context, gap, and drift blocks as needed. +Include `Drift` only when recorded context contradicts code. Record gaps for +absent entry points and focus areas without durable context. + +## Status: `bootstrap_required` + +Use when the context root does not exist. Read and create nothing. + +```markdown +# Context Load Result + +Status: bootstrap_required + +## Context root + +{context_root} + +## Reason + +{reason} +``` + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-context-load/references/context-brief.yaml b/.claude/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/.claude/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/.claude/skills/sce-plan-authoring/SKILL.md b/.claude/skills/sce-plan-authoring/SKILL.md index 1b34665e..06f4a7f5 100644 --- a/.claude/skills/sce-plan-authoring/SKILL.md +++ b/.claude/skills/sce-plan-authoring/SKILL.md @@ -3,7 +3,7 @@ name: sce-plan-authoring description: > Internal SCE workflow skill that turns one change request into a scoped plan in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from + Markdown result: plan_ready, needs_clarification, or blocked. Use from /change-to-plan. Do not implement plan tasks, request implementation approval, synchronize context, or run final validation. compatibility: claude @@ -30,11 +30,11 @@ This skill owns: Use the document format defined in: -`references/plan-template.md` +the **Plan template** section in this file Return a result matching: -`references/authoring-contract.yaml` +the **Result contract** section in this file The invoking workflow renders that result as the summary defined in: @@ -191,7 +191,7 @@ place a plan says how it is validated. ### 6. Author the task stack Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. +atomic slicing contract in the **Plan template** section in this file. Every executable task must be completable and landable as one coherent commit. Split any task that would require multiple independent commits. Convert broad @@ -215,7 +215,7 @@ or already covered by completed tasks, return `blocked` with category ### 7. Write the plan -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. +Write `context/plans/{plan_name}.md` using the **Plan template** section in this file. When updating an existing plan, keep completed tasks and their evidence intact, and append or renumber new tasks without disturbing recorded history. @@ -287,4 +287,299 @@ The skill is complete after: - One plan target was resolved, or resolution failed and was reported. - The plan file was written, or no file was written because the result is `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. +- One valid result matching the **Result contract** section in this file was returned. + +## Result contract + +# SCE Plan Authoring Result Contract + +Return exactly one Markdown document using one layout below. `Status` is the +branch value consumed by the invoking command. Use every required heading and +label exactly as written, omit optional sections that do not apply, and do +not add prose outside the selected layout. Empty required lists must contain +`- None.`. + +Report plan names without extensions and paths exactly as written so emitted +commands are runnable. Only `plan_ready` writes a plan. Do not include +implementation, synchronization, or final-validation results. + +## Status: `plan_ready` + +Use after creating or updating a plan with at least one incomplete task. + +```markdown +# Plan Authoring Result + +Status: plan_ready + +## Plan + +- Path: {plan.path} +- Name: {plan.name} +- Action: {created|updated} +- Completed tasks: {plan.completed_tasks} +- Total tasks: {plan.total_tasks} + +## Summary + +{summary} + +## Tasks + +- {task.id} — {task.title} — {todo|done} + +## Next task + +- ID: {next_task.id} +- Title: {next_task.title} + +## Assumptions + +- {assumption} + +## Open questions + +- {open_question} +``` + +`Plan`, `Summary`, `Tasks`, `Next task`, and `Assumptions` are required. +List tasks in plan order, including completed tasks. `Next task` is the first +unchecked task. Include `Open questions` only for genuine non-blocking +questions. Summary describes resulting behavior rather than repeating tasks. + +## Status: `needs_clarification` + +Use when one to three critical questions block writing the plan. + +```markdown +# Plan Authoring Result + +Status: needs_clarification + +## Plan target + +- Name: {plan_target.name} +- Action: {created|updated} +- Path: {existing plan_target.path; omit this label when no plan exists} + +## Questions + +### {question.id} + +- Category: {scope|success_criteria|constraints|dependency|domain|architecture|sequencing} +- Question: {question} +- Why blocking: {why_blocking} +``` + +`Questions` is required. `Plan target` is optional and appears only when the +request resolved to one target before authoring stopped. Never report a path +for a plan that does not exist. + +## Status: `blocked` + +Use when the target cannot be resolved or the request cannot be safely +planned. Nothing is written. + +```markdown +# Plan Authoring Result + +Status: blocked + +## Candidates + +- {candidate_path} + +## Issues + +### {issue.id} + +- Category: {ambiguous_plan_target|missing_request|conflicting_request|no_actionable_work|other} +- Problem: {problem} +- Impact: {impact} +- Decision required: {decision_required} +``` + +`Issues` is required. Include `Candidates` only for an ambiguous existing-plan +match. Use `needs_clarification` when an answer would make the request +plannable; use `no_actionable_work` when no incomplete task would result. + +## Plan template + +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +`sce-task-execution` appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml b/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/.claude/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/.claude/skills/sce-plan-authoring/references/plan-template.md b/.claude/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/.claude/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/.claude/skills/sce-plan-context-sync/SKILL.md b/.claude/skills/sce-plan-context-sync/SKILL.md index 96127523..ca14c2ee 100644 --- a/.claude/skills/sce-plan-context-sync/SKILL.md +++ b/.claude/skills/sce-plan-context-sync/SKILL.md @@ -307,3 +307,11 @@ The skill is complete after: - Applicable durable context was synchronized and verified, no context change was warranted, or a synchronization blocker was reported. - One Markdown report matching `references/sync-report.md` was returned. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-plan-review/SKILL.md b/.claude/skills/sce-plan-review/SKILL.md index a55fee1d..0f29e07b 100644 --- a/.claude/skills/sce-plan-review/SKILL.md +++ b/.claude/skills/sce-plan-review/SKILL.md @@ -27,7 +27,7 @@ This skill owns: Return a result matching: -`references/readiness-contract.yaml` +the **Result contract** section in this file ## Input @@ -145,5 +145,123 @@ The skill is complete after: - One plan was resolved. - At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was +- One valid readiness result matching the **Result contract** section in this file was returned. + +## Result contract + +# SCE Plan Review Result Contract + +Return exactly one Markdown document using one layout below. `Status` is the +branch value consumed by `/next-task`. Use every required heading and label +exactly as written, omit optional sections that do not apply, and do not add +prose outside the selected layout. Empty required lists must contain +`- None.`. + +Report task counts as they stand and the plan path exactly as resolved. Do +not request implementation confirmation or include implementation, +synchronization, or final-validation results. + +## Status: `ready` + +```markdown +# Plan Review Result + +Status: ready + +## Plan + +- Path: {plan.path} +- Name: {plan.name} +- Completed tasks: {plan.completed_tasks} +- Total tasks: {plan.total_tasks} + +## Task + +- ID: {task.id} +- Title: {task.title} + +## Relevant files + +- {relevant_file} + +## Relevant context + +- {relevant_context} + +## Assumptions + +- {assumption} +``` + +Every section is required. `Name` is the plan basename without its extension. +Repeat list items as needed. + +This layout is a compact handoff, not a task presentation. It carries only +what review discovered and the next phase cannot recover on its own. The +task's goal, scope boundaries, done checks, dependencies, and verification +stay in the plan file, where `sce-task-execution` reads them. Do not restate +them here. + +## Status: `blocked` + +```markdown +# Plan Review Result + +Status: blocked + +## Plan + +- Path: {plan.path} +- Completed tasks: {plan.completed_tasks} +- Total tasks: {plan.total_tasks} + +## Task + +- ID: {task.id} +- Title: {task.title} + +## Candidates + +- {candidate_path} + +## Issues + +### {issue.id} + +- Category: {missing_decision|ambiguity|missing_acceptance_criteria|dependency|scope} +- Problem: {problem} +- Impact: {impact} +- Decision required: {decision_required} + +## Executable tasks remaining + +{true|false} +``` + +`Issues` is required. Include `Plan` whenever exactly one plan resolved, +`Task` when one was selected, and `Candidates` only when plan resolution +failed or was ambiguous. Include `Executable tasks remaining` when a plan +resolved. + +## Status: `plan_complete` + +```markdown +# Plan Review Result + +Status: plan_complete + +## Plan + +- Path: {plan.path} +- Completed tasks: {plan.completed_tasks} +- Total tasks: {plan.total_tasks} +``` + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-plan-review/references/readiness-contract.yaml b/.claude/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/.claude/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/.claude/skills/sce-task-context-sync/SKILL.md b/.claude/skills/sce-task-context-sync/SKILL.md index 437585c2..fa3eafa6 100644 --- a/.claude/skills/sce-task-context-sync/SKILL.md +++ b/.claude/skills/sce-task-context-sync/SKILL.md @@ -309,3 +309,11 @@ The skill is complete after: - Applicable durable context was synchronized and verified, no context change was warranted, or a synchronization blocker was reported. - One Markdown report matching `references/sync-report.md` was returned. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-task-execution/SKILL.md b/.claude/skills/sce-task-execution/SKILL.md index da53bb98..3d484c76 100644 --- a/.claude/skills/sce-task-execution/SKILL.md +++ b/.claude/skills/sce-task-execution/SKILL.md @@ -3,7 +3,7 @@ name: sce-task-execution description: > Internal SCE workflow skill that always presents one reviewed task to the user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, + task, records evidence in the plan, and returns one Markdown result: declined, blocked, incomplete, or complete. Accepts a ready result from sce-plan-review. Do not select or execute another task, synchronize durable context, run final plan validation, create commits, or @@ -25,7 +25,7 @@ This skill owns: - Implementing one approved task. - Running task-level verification. - Updating that task and its evidence in the plan. -- Returning one terminal YAML result. +- Returning one terminal Markdown result. Use the gate defined in: @@ -33,7 +33,7 @@ Use the gate defined in: Return a final result matching: -`references/execution-contract.yaml` +the **Result contract** section in this file ## Input @@ -51,12 +51,15 @@ The readiness result must identify: - One resolved plan. - Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. - Relevant files and context. - Review assumptions. +The readiness result is a compact handoff carrying only what review +discovered. Read the task's goal, scope boundaries, done checks, +dependencies, and verification from that task's entry in the plan file. +The handoff does not repeat them, and their absence from it is not a +handoff problem. + If required handoff information is absent or stale, still show the gate using what is known, clearly identify the handoff problem, and do not edit files. After the user responds, return `blocked`. @@ -71,7 +74,7 @@ Confirm that: - Exactly one task is present. - The plan file exists. - The selected task is still incomplete. -- The task has not materially changed since review. +- The task entry in the plan still matches the reviewed task ID and title. - Declared dependencies remain complete. Do not reconstruct missing material requirements. @@ -79,7 +82,8 @@ Do not reconstruct missing material requirements. ### 2. Always show the implementation gate At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. +`references/implementation-gate.md`. Read that task's entry in the plan file for +the gate's goal, scope, done-check, and verification fields. The gate must be shown even when: @@ -93,7 +97,7 @@ question: `Continue with implementation now? (yes/no)` -Stop and wait for the user's answer. Do not return YAML, and make no file +Stop and wait for the user's answer. Do not return Markdown, and make no file modifications, until the user has answered. When the `approve` flag is supplied, show the gate as a summary, omit the @@ -152,8 +156,8 @@ the repository unsafe or invalid. Run the narrowest authoritative checks that demonstrate the done checks. -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. +Start with the verification declared by that task's entry in the plan. Add +nearby or directly relevant checks only when needed. Verification may include: @@ -206,17 +210,17 @@ Return `blocked` for every other non-successful outcome, including: - Material blocker. - A verification failure that cannot be resolved in scope. -Use a blocker category defined by `references/execution-contract.yaml`. +Use a blocker category defined by the **Result contract** section in this file. Do not determine whether the plan is complete. The invoking `/next-task` workflow owns that decision after context synchronization. -### 9. Return YAML +### 9. Return Markdown -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. +After the skill reaches a terminal state, return exactly one Markdown document +matching the **Result contract** section in this file. -Return only the YAML document. Do not add explanatory prose before or after it. +Return only the Markdown document. Do not add explanatory prose before or after it. ## Boundaries @@ -243,5 +247,186 @@ The skill is complete after: - The implementation gate was shown. - The user approved or rejected the task, or approval was pre-supplied. - At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` +- One valid terminal Markdown result matching the **Result contract** section in this file was returned. + +## Result contract + +# SCE Task Execution Result Contract + +Return exactly one Markdown document using one layout below after the +implementation gate reaches a terminal state. `Status` is the branch value +consumed by `/next-task`. Use every required heading and label exactly as +written, omit optional sections that do not apply, and do not add prose +outside the selected layout. Empty required lists must contain `- None.`. + +Report task counts as they stand. Never serialize the implementation gate, +select the next task, or include synchronization or final-validation results. + +## Shared Plan and Task layout + +Every status includes these sections: + +```markdown +## Plan + +- Path: {plan.path} +- Completed tasks: {plan.completed_tasks} +- Total tasks: {plan.total_tasks} + +## Task + +- ID: {task.id} +- Title: {task.title} +``` + +## Status: `declined` + +```markdown +# Task Execution Result + +Status: declined + +{Shared Plan and Task layout} +``` + +Use only when the user declines and no implementation changes were made. + +## Status: `blocked` + +```markdown +# Task Execution Result + +Status: blocked + +{Shared Plan and Task layout} + +## Blocker + +- Category: {stale_review|scope|dependency|architecture|security|data|destructive_operation|other} +- Problem: {problem} +- Impact: {impact} +- Decision required: {decision_required} + +## Changes + +### Files changed + +- {file} + +## Verification + +### {command} + +- Outcome: {passed|failed|not_run} +- Summary: {summary} + +## Work preserved + +{true|false} +``` + +`Blocker` and `Work preserved` are required. `Changes` and `Verification` are +optional and appear only when work or checks occurred. + +## Status: `incomplete` + +```markdown +# Task Execution Result + +Status: incomplete + +{Shared Plan and Task layout} + +## Changes + +### Files changed + +- {file} + +### Summary + +- {change_summary} + +## Verification + +### {command} + +- Outcome: {passed|failed|not_run} +- Summary: {summary} + +## Satisfied done checks + +- {check} + +## Unsatisfied done checks + +- {check} + +## Remaining work + +- {remaining_work} + +## Reason + +{reason} +``` + +`Changes`, `Verification`, and `Remaining work` are required. The done-check +sections and `Reason` are optional. + +## Status: `complete` + +```markdown +# Task Execution Result + +Status: complete + +{Shared Plan and Task layout} + +## Changes + +### Files changed + +- {file} + +### Summary + +- {change_summary} + +## Verification + +### {command} + +- Outcome: passed +- Summary: {summary} + +## Done checks + +### {check} + +{evidence} + +## Context impact + +- Classification: {none|local|domain|root} +- Affected areas: {comma-separated areas, or none} +- Reason: {reason} +``` + +Every shown section is required. Repeat verification and done-check blocks as +needed. This layout is the authoritative handoff to context synchronization. + +Keep it at exactly these sections. `sce-task-context-sync` validates the +changed files, implementation summary, verification evidence, done-check +evidence, and context impact, and blocks when any is missing, so none of them +may be dropped. `Status: complete` already asserts the task was marked +complete in the plan with evidence recorded; do not restate that as a section. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-task-execution/references/execution-contract.yaml b/.claude/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/.claude/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.claude/skills/sce-task-execution/references/implementation-gate.md b/.claude/skills/sce-task-execution/references/implementation-gate.md index d4ad836c..76f1446e 100644 --- a/.claude/skills/sce-task-execution/references/implementation-gate.md +++ b/.claude/skills/sce-task-execution/references/implementation-gate.md @@ -3,9 +3,13 @@ Always show this gate at the start of `sce-task-execution`, before editing any file. -The gate is user-facing prose. It is never serialized into a YAML result. This +The gate is user-facing prose. It is never serialized into a Markdown result. This file is the only authority for the gate's content and order. +Every `{task.*}` field below comes from that task's entry in the plan file. +The readiness result supplies only the plan and task identity, relevant files +and context, and review assumptions. + ## Format # `{task.id} - {task.title} - {plan.name}` @@ -63,7 +67,7 @@ When the `approve` flag is supplied, omit the question and end after - Do not add requirements absent from the reviewed task. - Do not present multiple competing approaches unless a material decision is required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and +- Do not emit Markdown while waiting for the user's answer. Stop after the gate and wait. - If the handoff is stale or incomplete, show the known task information and identify the problem under **Risks or trade-offs**. diff --git a/.claude/skills/sce-validation/SKILL.md b/.claude/skills/sce-validation/SKILL.md index ddb04f99..1898cb10 100644 --- a/.claude/skills/sce-validation/SKILL.md +++ b/.claude/skills/sce-validation/SKILL.md @@ -33,7 +33,7 @@ This skill owns: Return a result matching: -`references/validation-result.md` +the **Result contract** section in this file Write plan-file evidence matching: @@ -154,7 +154,7 @@ Return exactly one Markdown result: passed, and the Validation Report was written. - `failed` when evidence was captured but required checks or criteria remain unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with + the **Result contract** section in this file, ending recommended work with `/validate {plan path}`. - `blocked` when validation cannot proceed safely. @@ -186,5 +186,202 @@ The skill is complete after: - One plan was resolved, or resolution failed and was reported. - Implementation completeness was checked. - Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was +- One valid Markdown result matching the **Result contract** section in this file was returned. + +## Result contract + +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not invoked for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs `sce-plan-context-sync` only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. + +## Control flow + +This skill is one phase of a workflow, not a turn. Return the result to the +invoking command and let it continue in the same turn. Do not present the +result to the user as workflow output, and do not end your turn after +returning it — the invoking command decides what the user sees and when the +workflow stops. diff --git a/.claude/skills/sce-validation/references/validation-result.md b/.claude/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/.claude/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. diff --git a/cli/src/services/parse/command_runtime.rs b/cli/src/services/parse/command_runtime.rs index 2bceb22c..0aa0cc52 100644 --- a/cli/src/services/parse/command_runtime.rs +++ b/cli/src/services/parse/command_runtime.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use crate::{cli_schema, command_surface, services}; use services::command_registry::{CommandRegistry, RuntimeCommand}; use services::error::{ClassifiedError, FailureClass}; @@ -223,16 +221,17 @@ fn convert_clap_command(command: cli_schema::Commands) -> Result convert_setup_command( + } => convert_setup_command(services::setup::SetupCliOptions { + help: false, + non_interactive, opencode, claude, pi, all, - non_interactive, hooks, - repo, + repo_path: repo, bootstrap_context, - ), + }), cli_schema::Commands::Doctor { fix, format } => Ok(convert_doctor_command(fix, format)), cli_schema::Commands::Hooks { subcommand } => convert_hooks_subcommand(subcommand), cli_schema::Commands::Policy { subcommand } => Ok(convert_policy_subcommand(&subcommand)), @@ -402,29 +401,9 @@ fn convert_config_subcommand( } } -#[allow(clippy::fn_params_excessive_bools)] fn convert_setup_command( - opencode: bool, - claude: bool, - pi: bool, - all: bool, - non_interactive: bool, - hooks: bool, - repo: Option, - bootstrap_context: bool, + options: services::setup::SetupCliOptions, ) -> Result { - let options = services::setup::SetupCliOptions { - help: false, - non_interactive, - opencode, - claude, - pi, - all, - hooks, - repo_path: repo, - bootstrap_context, - }; - let request = services::setup::resolve_setup_request(options) .map_err(|error| ClassifiedError::validation(error.to_string()))?; diff --git a/config/pkl/README.md b/config/pkl/README.md index ae3a7387..60d900a3 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -26,6 +26,8 @@ Apply target-specific rendering and supported metadata under `config/pkl/rendere Each skill package includes its package-local `SKILL.md` and any nested `references/` documents. Generated skill trees must remain self-contained; a generated skill must not depend on a sibling skill package. +Pi and OpenCode consume the canonical multi-file packages, including YAML phase-result contracts under `references/`. Claude receives the same skills with two Claude-only transforms: Markdown phase-result contracts for `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`, and a reduced package shape where machine contracts and plan templates are folded into `SKILL.md` so each Claude package keeps at most one human-presentation file under `references/` (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, or `commit-message-style.md`). Validation and context-synchronization reports remain Markdown for every target; on Claude, `validation-result` lives in `SKILL.md` while `validation-report` / `sync-report` stay as the single human-facing reference when present. + The automated OpenCode profile, the generated `/handover` command, legacy bootstrap/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. Not generated by this pipeline: dependency artifacts such as `node_modules`, lockfiles, install outputs, and manifests outside the paths above. @@ -69,7 +71,7 @@ nix run .#pkl-check-generated The check: - rejects committed `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, and `cli/assets/generated` outputs; -- evaluates `metadata-coverage-check.pkl` for the exact four-command, eight-skill-package, nested-reference, and two-agent OpenCode inventory; +- evaluates `metadata-coverage-check.pkl` for exact per-target four-command, eight-skill-package, and nested-reference inventories, including Claude's reduced single human-presentation reference inventory (machine contracts inlined in `SKILL.md`), plus the two-agent OpenCode inventory; - generates twice into temporary directories and compares sorted SHA-256 inventories; - requires all generated target roots and the SCE config schema while rejecting removed surfaces such as `config/automated/.opencode` and `config/.claude/agents`; - prints the stable inventory count and digest without preserving generated files. diff --git a/config/pkl/renderers/claude-content.pkl b/config/pkl/renderers/claude-content.pkl index f5725717..f85ea5b9 100644 --- a/config/pkl/renderers/claude-content.pkl +++ b/config/pkl/renderers/claude-content.pkl @@ -5,6 +5,7 @@ import "../base/workflow-commit.pkl" as commit import "../base/workflow-content.pkl" as model import "common.pkl" as common import "claude-metadata.pkl" as metadata +import "claude-workflow-results.pkl" as workflowResults local missingSceInstallMessage = "sce CLI not found. Install it from https://sce.crocoder.dev/docs/getting-started#install-cli" @@ -19,21 +20,138 @@ local workflows = new Listing { commit.workflow } +/// Claude reads a phase result as a finished deliverable and ends the turn +/// unless the continuation branch is at least as vivid as the stop branch. The +/// canonical bodies specify stopping in detail and continuing in four words, so +/// Claude-only command bodies name the next skill and rule out ending the turn. +local turnBoundaryRule = "Run every step in one turn. Stop only where a step says to wait for the user." + +local withTurnBoundaryRule = (text: String) -> + text.replaceFirst("## Workflow\n\n", "## Workflow\n\n\(turnBoundaryRule)\n\n") + +local changeToPlanContinuations = (text: String) -> + text + .replaceFirst( + "`loaded` -> Continue to the next step.", + """ + `loaded` -> The brief is internal workflow input, not workflow output. Do not print it, and do not end your turn. Invoke `sce-plan-authoring` in the same turn. + + This step ends the turn only on `bootstrap_required`. + """ + ) + .replaceFirst( + "`plan_ready` -> Continue to the next step.", + """ + `plan_ready` -> An authoring result is never presented to the user as workflow output. Do not print it, and do not end your turn. Continue to the next step in the same turn. + + This step ends the turn only on `needs_clarification` or `blocked`. + """ + ) + +local nextTaskContinuations = (text: String) -> + text + .replaceFirst( + "`ready` -> Pass the complete readiness result to `sce-task-execution`.", + """ + `ready` -> A readiness result is never presented to the user. Do not print it, and do not end your turn. Pass the complete readiness result to `sce-task-execution` in the same turn. + + The readiness result is a compact handoff: plan and task identity, relevant files, relevant context, and review assumptions. It deliberately omits the task's goal, scope, done checks, dependencies, and verification, which `sce-task-execution` reads from the plan and presents in its implementation gate. Do not reconstruct the omitted fields, and do not treat their absence as a stale handoff. + + This step ends the turn only on `blocked` or `plan_complete`. + """ + ) + .replaceFirst( + "`complete` -> continue to the next step.", + """ + `complete` -> Do not print the raw result, and do not end your turn. Invoke `sce-task-context-sync` in the same turn. + + This result stays full-size: `sce-task-context-sync` validates the changed files, implementation summary, verification evidence, done-check evidence, and context impact, and blocks when any is missing. Pass it through untouched rather than trimming it to match the compact readiness handoff. + + This step ends the turn only on `declined`, `blocked`, or `incomplete`. + """ + ) + .replaceFirst( + "`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step.", + """ + `synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned, then continue to the next step in the same turn. Do not end your turn before the continuation block. + + This step ends the turn only on `blocked`. + """ + ) + +local validateContinuations = (text: String) -> + text + .replaceFirst( + """ + `validated` -> Pass the complete validated Markdown result to + `sce-plan-context-sync`. + """, + """ + `validated` -> A validated result is never presented to the user as workflow + output. Do not print it, and do not end your turn. Pass the complete validated + Markdown result to `sce-plan-context-sync` in the same turn. + + This step ends the turn only on `blocked` or `failed`. + """ + ) + .replaceFirst( + """ + `synced` | `no_context_change` -> Print out the report + `sce-plan-context-sync` returned. Continue to the next step. + """, + """ + `synced` | `no_context_change` -> Print out the report + `sce-plan-context-sync` returned, then continue to the next step in the same + turn. Do not end your turn before the completion block. + + This step ends the turn only on `blocked`. + """ + ) + +local nextTaskHandoffProse = (text: String) -> + text.replaceFirst( + "`sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it.", + "`sce-task-context-sync` owns reading the plan, task, changed files, implementation summary, verification evidence, done-check evidence, and reported context impact out of it." + ) + +local commitContinuations = (text: String) -> + text.replaceFirst( + "`bypass_message` -> Continue to the next step.", + """ + `bypass_message` -> The message is internal workflow input, not workflow output. Do not print it as the deliverable, and do not end your turn. The commit is this path's deliverable, so continue to the next step in the same turn. + + This step ends the turn only on `blocked` or a contract violation. + """ + ) + +local renderCommandBody = (slug: String, text: String) -> + if (slug == "change-to-plan") changeToPlanContinuations.apply(withTurnBoundaryRule.apply(text)) + else if (slug == "next-task") nextTaskHandoffProse.apply(nextTaskContinuations.apply(withTurnBoundaryRule.apply(text))) + else if (slug == "validate") validateContinuations.apply(withTurnBoundaryRule.apply(text)) + else if (slug == "commit") commitContinuations.apply(withTurnBoundaryRule.apply(text)) + else text + local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { path = command.document.path - text = command.document.text.replaceFirst( - "\n---\n", - "\nallowed-tools: \(metadata.commandAllowedTools[command.slug])\n---\n" + text = renderCommandBody.apply( + command.slug, + command.document.text.replaceFirst( + "\n---\n", + "\nallowed-tools: \(metadata.commandAllowedTools[command.slug])\n---\n" + ) ) } -local renderSkillDocument = (document: model.WorkflowDocument) -> new model.WorkflowDocument { - path = document.path - text = if (document.path == "SKILL.md") document.text.replaceFirst( - "\n---\n", - "\ncompatibility: \(metadata.skillCompatibility)\n---\n" - ) else document.text -} +local withClaudeEntrypointMetadata = (document: model.WorkflowDocument) -> + if (document.path == "SKILL.md") + new model.WorkflowDocument { + path = document.path + text = document.text.replaceFirst( + "\n---\n", + "\ncompatibility: \(metadata.skillCompatibility)\n---\n" + ) + } + else document settings = new common.RenderedTextFile { slug = "settings" @@ -119,12 +237,14 @@ commands { /// Flatten package-relative document paths while retaining each skill's /// self-contained directory layout and adding only Claude-supported metadata -/// to the package entrypoint. +/// to the package entrypoint. Machine contracts are folded into SKILL.md by +/// the Claude workflow-results renderer so each package keeps at most one +/// human-presentation `references/` file. skillDocuments { for (workflow in workflows) { for (skillSlug, skillPackage in workflow.skills) { - for (documentPath, document in skillPackage.documents) { - ["\(skillSlug)/\(documentPath)"] = renderSkillDocument.apply(document) + for (documentPath, document in workflowResults.renderSkillPackage.apply(skillSlug, skillPackage)) { + ["\(skillSlug)/\(documentPath)"] = withClaudeEntrypointMetadata.apply(document) } } } diff --git a/config/pkl/renderers/claude-workflow-results.pkl b/config/pkl/renderers/claude-workflow-results.pkl new file mode 100644 index 00000000..b77eabc7 --- /dev/null +++ b/config/pkl/renderers/claude-workflow-results.pkl @@ -0,0 +1,811 @@ +import "../base/workflow-content.pkl" as model + +/// Claude cannot reliably transport YAML-only phase handoffs between workflow +/// skills and commands. Keep the canonical Pi/OpenCode documents unchanged and +/// replace only Claude's five structured phase-result contracts with Markdown. +/// +/// Claude also collapses multi-file skill `references/` so each package emits at +/// most one human-facing presentation layout. Machine contracts and plan +/// templates are folded into that package's `SKILL.md`. + +local markdownContractPathBySkill = new Mapping { + ["sce-context-load"] = "references/context-brief.md" + ["sce-plan-authoring"] = "references/authoring-contract.md" + ["sce-plan-review"] = "references/readiness-contract.md" + ["sce-task-execution"] = "references/execution-contract.md" + ["sce-atomic-commit"] = "references/commit-contract.md" +} + +local markdownContractBySkill = new Mapping { + ["sce-context-load"] = CONTEXT_BRIEF + ["sce-plan-authoring"] = AUTHORING_CONTRACT + ["sce-plan-review"] = READINESS_CONTRACT + ["sce-task-execution"] = EXECUTION_CONTRACT + ["sce-atomic-commit"] = COMMIT_CONTRACT +} + +/// Presentation layouts shown to a human reviewer. All other `references/` +/// documents are machine contracts and fold into Claude's `SKILL.md`. +local humanPresentationPaths = Set( + "references/plan-summary.md", + "references/implementation-gate.md", + "references/validation-report.md", + "references/sync-report.md", + "references/commit-message-style.md" +) + +local planTemplatePath = "references/plan-template.md" +local validationResultPath = "references/validation-result.md" + +local rewriteMachineReferencePaths = (text: String) -> + text + .replaceAll("`references/context-brief.md`", "the **Result contract** section in this file") + .replaceAll("`references/authoring-contract.md`", "the **Result contract** section in this file") + .replaceAll("`references/readiness-contract.md`", "the **Result contract** section in this file") + .replaceAll("`references/execution-contract.md`", "the **Result contract** section in this file") + .replaceAll("`references/commit-contract.md`", "the **Result contract** section in this file") + .replaceAll("`references/validation-result.md`", "the **Result contract** section in this file") + .replaceAll("`references/plan-template.md`", "the **Plan template** section in this file") + +/// Per-document Claude transform: Markdown phase contracts and YAML→Markdown +/// wording for the five structured skills. Package-level folding happens in +/// `renderSkillPackage`. +renderSkillDocument = (skillSlug: String, document: model.WorkflowDocument) -> + if (document.path == "SKILL.md" && markdownContractPathBySkill.containsKey(skillSlug)) + new model.WorkflowDocument { + path = document.path + text = document.text + .replaceAll("YAML", "Markdown") + .replaceAll(".yaml", ".md") + } + else if (markdownContractPathBySkill.containsKey(skillSlug) && document.path.endsWith(".yaml")) + new model.WorkflowDocument { + path = markdownContractPathBySkill[skillSlug] + text = markdownContractBySkill[skillSlug] + } + else if (markdownContractPathBySkill.containsKey(skillSlug)) + new model.WorkflowDocument { + path = document.path + text = document.text + .replaceAll("YAML", "Markdown") + .replaceAll(".yaml", ".md") + } + else document + +/// Claude's readiness handoff carries only what plan review discovered, because +/// a skill "returning" a result and printing it to the user are the same act. +/// Point `sce-task-execution` at the plan file for the fields the compact +/// handoff no longer repeats. +local rewriteTaskExecutionSourcing = (path: String, text: String) -> + if (path == "SKILL.md") + text + .replaceFirst( + """ + - One resolved plan. + - Exactly one incomplete task. + - The task goal and scope boundaries. + - Done checks. + - Verification expectations. + - Relevant files and context. + - Review assumptions. + """, + """ + - One resolved plan. + - Exactly one incomplete task. + - Relevant files and context. + - Review assumptions. + + The readiness result is a compact handoff carrying only what review + discovered. Read the task's goal, scope boundaries, done checks, + dependencies, and verification from that task's entry in the plan file. + The handoff does not repeat them, and their absence from it is not a + handoff problem. + """ + ) + .replaceFirst( + "- The task has not materially changed since review.", + "- The task entry in the plan still matches the reviewed task ID and title." + ) + .replaceFirst( + """ + At the start of the skill, before any file modification, present the task using + `references/implementation-gate.md`. + """, + """ + At the start of the skill, before any file modification, present the task using + `references/implementation-gate.md`. Read that task's entry in the plan file for + the gate's goal, scope, done-check, and verification fields. + """ + ) + .replaceFirst( + """ + Start with verification supplied by the readiness result. Add nearby or directly + relevant checks only when needed. + """, + """ + Start with the verification declared by that task's entry in the plan. Add + nearby or directly relevant checks only when needed. + """ + ) + else if (path == "references/implementation-gate.md") + text.replaceFirst( + "file is the only authority for the gate's content and order.", + """ + file is the only authority for the gate's content and order. + + Every `{task.*}` field below comes from that task's entry in the plan file. + The readiness result supplies only the plan and task identity, relevant files + and context, and review assumptions. + """ + ) + else text + +local rewriteHandoffSourcing = (skillSlug: String, document: model.WorkflowDocument) -> + if (skillSlug == "sce-task-execution") + new model.WorkflowDocument { + path = document.path + text = rewriteTaskExecutionSourcing.apply(document.path, document.text) + } + else document + +local renderPackageDocuments = (skillSlug: String, skillPackage: model.SkillPackage) -> new Mapping { + for (_, document in skillPackage.documents) { + [renderSkillDocument.apply(skillSlug, document).path] = + rewriteHandoffSourcing.apply(skillSlug, renderSkillDocument.apply(skillSlug, document)) + } +} + +local foldResultContract = (skillSlug: String, skillText: String, renderedByPath: Mapping) -> + if (markdownContractBySkill.containsKey(skillSlug)) + skillText + "\n\n## Result contract\n\n" + markdownContractBySkill[skillSlug] + else if (renderedByPath.containsKey(validationResultPath)) + skillText + "\n\n## Result contract\n\n" + renderedByPath[validationResultPath].text + else skillText + +local foldPlanTemplate = (skillText: String, renderedByPath: Mapping) -> + if (renderedByPath.containsKey(planTemplatePath)) + skillText + "\n\n## Plan template\n\n" + renderedByPath[planTemplatePath].text + else skillText + +/// Claude treats the most recently injected instruction block as the strongest +/// one, so a phase skill that ends on "return only the result" reads as the end +/// of the turn and the invoking command never resumes. State the turn boundary +/// explicitly at the end of every Claude `SKILL.md`. +local appendControlFlow = (skillText: String) -> skillText + "\n\n" + CONTROL_FLOW + +local buildClaudeSkillText = (skillSlug: String, renderedByPath: Mapping) -> + appendControlFlow.apply( + foldPlanTemplate.apply( + foldResultContract.apply( + skillSlug, + rewriteMachineReferencePaths.apply(renderedByPath["SKILL.md"].text), + renderedByPath + ), + renderedByPath + ) + ) + +/// Emit Claude skill documents with machine contracts folded into `SKILL.md` +/// and at most one human-presentation file under `references/`. +renderSkillPackage = (skillSlug: String, skillPackage: model.SkillPackage) -> + let (renderedByPath = renderPackageDocuments.apply(skillSlug, skillPackage)) + new Mapping { + ["SKILL.md"] = new model.WorkflowDocument { + path = "SKILL.md" + text = buildClaudeSkillText.apply(skillSlug, renderedByPath) + } + for (path, document in renderedByPath) { + when (humanPresentationPaths.contains(path)) { + [path] = document + } + } + } + +local CONTROL_FLOW = """ + ## Control flow + + This skill is one phase of a workflow, not a turn. Return the result to the + invoking command and let it continue in the same turn. Do not present the + result to the user as workflow output, and do not end your turn after + returning it — the invoking command decides what the user sees and when the + workflow stops. + """ + +local CONTEXT_BRIEF = """ + # SCE Context Load Result Contract + + Return exactly one Markdown document using one layout below. The first line + after the title is the status source consumed by the invoking command. Use + the headings and labels exactly as written, omit optional sections that do + not apply, and do not add prose outside the selected layout. + + List every file read and no file that was not read. Key facts are durable + statements, not planning or implementation recommendations. Empty required + lists must contain `- None.`. This skill never reports context edits. + + ## Status: `loaded` + + Use when the context root exists and relevant context was read. + + ```markdown + # Context Load Result + + Status: loaded + + ## Context root + + {context_root} + + ## Entry points + + ### {path} + + - Read: {true|false} + - Reason: {reason; omit only when read is true and no reason is needed} + + ## Domain context + + ### {path} + + **Relevance:** {relevance} + + **Key facts:** + + - {key_fact} + + ## Gaps + + ### {area} + + {detail} + + ## Drift + + ### {path} + + - Context says: {context_says} + - Code says: {code_says} + - Repair needed: {repair_needed} + ``` + + `Context root`, `Entry points`, `Domain context`, and `Gaps` are required. + Repeat the entry-point, domain-context, gap, and drift blocks as needed. + Include `Drift` only when recorded context contradicts code. Record gaps for + absent entry points and focus areas without durable context. + + ## Status: `bootstrap_required` + + Use when the context root does not exist. Read and create nothing. + + ```markdown + # Context Load Result + + Status: bootstrap_required + + ## Context root + + {context_root} + + ## Reason + + {reason} + ``` + """ + +local AUTHORING_CONTRACT = """ + # SCE Plan Authoring Result Contract + + Return exactly one Markdown document using one layout below. `Status` is the + branch value consumed by the invoking command. Use every required heading and + label exactly as written, omit optional sections that do not apply, and do + not add prose outside the selected layout. Empty required lists must contain + `- None.`. + + Report plan names without extensions and paths exactly as written so emitted + commands are runnable. Only `plan_ready` writes a plan. Do not include + implementation, synchronization, or final-validation results. + + ## Status: `plan_ready` + + Use after creating or updating a plan with at least one incomplete task. + + ```markdown + # Plan Authoring Result + + Status: plan_ready + + ## Plan + + - Path: {plan.path} + - Name: {plan.name} + - Action: {created|updated} + - Completed tasks: {plan.completed_tasks} + - Total tasks: {plan.total_tasks} + + ## Summary + + {summary} + + ## Tasks + + - {task.id} — {task.title} — {todo|done} + + ## Next task + + - ID: {next_task.id} + - Title: {next_task.title} + + ## Assumptions + + - {assumption} + + ## Open questions + + - {open_question} + ``` + + `Plan`, `Summary`, `Tasks`, `Next task`, and `Assumptions` are required. + List tasks in plan order, including completed tasks. `Next task` is the first + unchecked task. Include `Open questions` only for genuine non-blocking + questions. Summary describes resulting behavior rather than repeating tasks. + + ## Status: `needs_clarification` + + Use when one to three critical questions block writing the plan. + + ```markdown + # Plan Authoring Result + + Status: needs_clarification + + ## Plan target + + - Name: {plan_target.name} + - Action: {created|updated} + - Path: {existing plan_target.path; omit this label when no plan exists} + + ## Questions + + ### {question.id} + + - Category: {scope|success_criteria|constraints|dependency|domain|architecture|sequencing} + - Question: {question} + - Why blocking: {why_blocking} + ``` + + `Questions` is required. `Plan target` is optional and appears only when the + request resolved to one target before authoring stopped. Never report a path + for a plan that does not exist. + + ## Status: `blocked` + + Use when the target cannot be resolved or the request cannot be safely + planned. Nothing is written. + + ```markdown + # Plan Authoring Result + + Status: blocked + + ## Candidates + + - {candidate_path} + + ## Issues + + ### {issue.id} + + - Category: {ambiguous_plan_target|missing_request|conflicting_request|no_actionable_work|other} + - Problem: {problem} + - Impact: {impact} + - Decision required: {decision_required} + ``` + + `Issues` is required. Include `Candidates` only for an ambiguous existing-plan + match. Use `needs_clarification` when an answer would make the request + plannable; use `no_actionable_work` when no incomplete task would result. + """ + +local READINESS_CONTRACT = """ + # SCE Plan Review Result Contract + + Return exactly one Markdown document using one layout below. `Status` is the + branch value consumed by `/next-task`. Use every required heading and label + exactly as written, omit optional sections that do not apply, and do not add + prose outside the selected layout. Empty required lists must contain + `- None.`. + + Report task counts as they stand and the plan path exactly as resolved. Do + not request implementation confirmation or include implementation, + synchronization, or final-validation results. + + ## Status: `ready` + + ```markdown + # Plan Review Result + + Status: ready + + ## Plan + + - Path: {plan.path} + - Name: {plan.name} + - Completed tasks: {plan.completed_tasks} + - Total tasks: {plan.total_tasks} + + ## Task + + - ID: {task.id} + - Title: {task.title} + + ## Relevant files + + - {relevant_file} + + ## Relevant context + + - {relevant_context} + + ## Assumptions + + - {assumption} + ``` + + Every section is required. `Name` is the plan basename without its extension. + Repeat list items as needed. + + This layout is a compact handoff, not a task presentation. It carries only + what review discovered and the next phase cannot recover on its own. The + task's goal, scope boundaries, done checks, dependencies, and verification + stay in the plan file, where `sce-task-execution` reads them. Do not restate + them here. + + ## Status: `blocked` + + ```markdown + # Plan Review Result + + Status: blocked + + ## Plan + + - Path: {plan.path} + - Completed tasks: {plan.completed_tasks} + - Total tasks: {plan.total_tasks} + + ## Task + + - ID: {task.id} + - Title: {task.title} + + ## Candidates + + - {candidate_path} + + ## Issues + + ### {issue.id} + + - Category: {missing_decision|ambiguity|missing_acceptance_criteria|dependency|scope} + - Problem: {problem} + - Impact: {impact} + - Decision required: {decision_required} + + ## Executable tasks remaining + + {true|false} + ``` + + `Issues` is required. Include `Plan` whenever exactly one plan resolved, + `Task` when one was selected, and `Candidates` only when plan resolution + failed or was ambiguous. Include `Executable tasks remaining` when a plan + resolved. + + ## Status: `plan_complete` + + ```markdown + # Plan Review Result + + Status: plan_complete + + ## Plan + + - Path: {plan.path} + - Completed tasks: {plan.completed_tasks} + - Total tasks: {plan.total_tasks} + ``` + """ + +local EXECUTION_CONTRACT = """ + # SCE Task Execution Result Contract + + Return exactly one Markdown document using one layout below after the + implementation gate reaches a terminal state. `Status` is the branch value + consumed by `/next-task`. Use every required heading and label exactly as + written, omit optional sections that do not apply, and do not add prose + outside the selected layout. Empty required lists must contain `- None.`. + + Report task counts as they stand. Never serialize the implementation gate, + select the next task, or include synchronization or final-validation results. + + ## Shared Plan and Task layout + + Every status includes these sections: + + ```markdown + ## Plan + + - Path: {plan.path} + - Completed tasks: {plan.completed_tasks} + - Total tasks: {plan.total_tasks} + + ## Task + + - ID: {task.id} + - Title: {task.title} + ``` + + ## Status: `declined` + + ```markdown + # Task Execution Result + + Status: declined + + {Shared Plan and Task layout} + ``` + + Use only when the user declines and no implementation changes were made. + + ## Status: `blocked` + + ```markdown + # Task Execution Result + + Status: blocked + + {Shared Plan and Task layout} + + ## Blocker + + - Category: {stale_review|scope|dependency|architecture|security|data|destructive_operation|other} + - Problem: {problem} + - Impact: {impact} + - Decision required: {decision_required} + + ## Changes + + ### Files changed + + - {file} + + ## Verification + + ### {command} + + - Outcome: {passed|failed|not_run} + - Summary: {summary} + + ## Work preserved + + {true|false} + ``` + + `Blocker` and `Work preserved` are required. `Changes` and `Verification` are + optional and appear only when work or checks occurred. + + ## Status: `incomplete` + + ```markdown + # Task Execution Result + + Status: incomplete + + {Shared Plan and Task layout} + + ## Changes + + ### Files changed + + - {file} + + ### Summary + + - {change_summary} + + ## Verification + + ### {command} + + - Outcome: {passed|failed|not_run} + - Summary: {summary} + + ## Satisfied done checks + + - {check} + + ## Unsatisfied done checks + + - {check} + + ## Remaining work + + - {remaining_work} + + ## Reason + + {reason} + ``` + + `Changes`, `Verification`, and `Remaining work` are required. The done-check + sections and `Reason` are optional. + + ## Status: `complete` + + ```markdown + # Task Execution Result + + Status: complete + + {Shared Plan and Task layout} + + ## Changes + + ### Files changed + + - {file} + + ### Summary + + - {change_summary} + + ## Verification + + ### {command} + + - Outcome: passed + - Summary: {summary} + + ## Done checks + + ### {check} + + {evidence} + + ## Context impact + + - Classification: {none|local|domain|root} + - Affected areas: {comma-separated areas, or none} + - Reason: {reason} + ``` + + Every shown section is required. Repeat verification and done-check blocks as + needed. This layout is the authoritative handoff to context synchronization. + + Keep it at exactly these sections. `sce-task-context-sync` validates the + changed files, implementation summary, verification evidence, done-check + evidence, and context impact, and blocks when any is missing, so none of them + may be dropped. `Status: complete` already asserts the task was marked + complete in the plan with evidence recorded; do not restate that as a section. + """ + +local COMMIT_CONTRACT = """ + # SCE Atomic Commit Result Contract + + Return exactly one Markdown document using one layout below. `Status` is the + branch value consumed by `/commit`. Use every required heading and label + exactly as written, omit optional sections that do not apply, and do not add + prose outside the selected layout. + + Report paths exactly as `git diff --cached --name-only` reports them. Every + staged file belongs to exactly one proposed commit. Keep each message's body + in the same fenced block as its subject, separated by one blank line. Never + report a commit hash or guidance forbidden by the mode. + + ## Status: `proposal` + + Use only in regular mode. Nothing is committed. + + ````markdown + # Atomic Commit Result + + Status: proposal + Mode: regular + + ## Commits + + ### {commit.id} + + #### Message + + ```text + {subject} + + {body} + ``` + + #### Files + + - {file} + + #### Cites plan + + {true|false} + + ## Split rationale + + {split_rationale} + + ## Scope classification + + {context_only|mixed} + + ## Notes + + - {note} + ```` + + `Commits` is required. Repeat the commit block as needed. Include `Split + rationale` only for multiple commits. `Scope classification` and `Notes` are + optional. + + ## Status: `bypass_message` + + Use only in bypass mode. Exactly one message covers every staged file. + + ````markdown + # Atomic Commit Result + + Status: bypass_message + Mode: bypass + + ## Message + + ```text + {subject} + + {body} + ``` + + ## Files + + - {file} + + ## Cites plan + + {true|false} + + ## Notes + + - {note} + ```` + + `Message` and `Files` are required. `Cites plan` and `Notes` are optional. + Never include commits, split rationale, or scope classification. + + ## Status: `blocked` + + ````markdown + # Atomic Commit Result + + Status: blocked + Mode: {regular|bypass} + + ## Files + + - {file} + + ## Issues + + ### {issue.id} + + - Category: {no_staged_changes|plan_citation_ambiguity|unreadable_diff|contradictory_context} + - Problem: {problem} + - Impact: {impact} + - Decision required: {decision_required} + ```` + + `Issues` is required. Include `Mode` when supplied and `Files` when staged + files were read. Plan-citation ambiguity blocks only in regular mode; bypass + mode omits the citation instead. + """ diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index 5e365e93..8351f5cb 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -14,7 +14,7 @@ local expectedAgentSlugs = Set( "shared-context-code" ) -local expectedSkillDocumentPaths = Set( +local expectedCanonicalSkillDocumentPaths = Set( "sce-atomic-commit/SKILL.md", "sce-atomic-commit/references/commit-contract.yaml", "sce-atomic-commit/references/commit-message-style.md", @@ -38,6 +38,25 @@ local expectedSkillDocumentPaths = Set( "sce-validation/references/validation-result.md" ) +/// Claude folds machine contracts and plan templates into SKILL.md, so each +/// package keeps at most one human-presentation `references/` file. +local expectedClaudeSkillDocumentPaths = Set( + "sce-atomic-commit/SKILL.md", + "sce-atomic-commit/references/commit-message-style.md", + "sce-context-load/SKILL.md", + "sce-plan-authoring/SKILL.md", + "sce-plan-authoring/references/plan-summary.md", + "sce-plan-context-sync/SKILL.md", + "sce-plan-context-sync/references/sync-report.md", + "sce-plan-review/SKILL.md", + "sce-task-context-sync/SKILL.md", + "sce-task-context-sync/references/sync-report.md", + "sce-task-execution/SKILL.md", + "sce-task-execution/references/implementation-gate.md", + "sce-validation/SKILL.md", + "sce-validation/references/validation-report.md" +) + local opencodeAgents = new Mapping { for (slug, document in opencode.agents) { [slug] = document @@ -84,11 +103,11 @@ local assertExactKeys = (actual: Mapping, expected: Set, label: String) inventoryChecks { ["opencode-agents"] = assertExactKeys.apply(opencodeAgents, expectedAgentSlugs, "OpenCode agent") ["opencode-commands"] = assertExactKeys.apply(opencodeCommands, expectedCommandSlugs, "OpenCode command") - ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedSkillDocumentPaths, "OpenCode skill document") + ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedCanonicalSkillDocumentPaths, "OpenCode skill document") ["claude-commands"] = assertExactKeys.apply(claudeCommands, expectedCommandSlugs, "Claude command") - ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedSkillDocumentPaths, "Claude skill document") + ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedClaudeSkillDocumentPaths, "Claude skill document") ["pi-commands"] = assertExactKeys.apply(piCommands, expectedCommandSlugs, "Pi command") - ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedSkillDocumentPaths, "Pi skill document") + ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedCanonicalSkillDocumentPaths, "Pi skill document") } /// Force rendering after exact inventory checks so target-specific metadata diff --git a/context/architecture.md b/context/architecture.md index 411c5c52..b5b3f36d 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -12,6 +12,7 @@ Current location for canonical workflow content primitives: - `config/pkl/base/workflow-change-to-plan.pkl` (canonical `/change-to-plan` package with the command plus self-contained `sce-context-load` and `sce-plan-authoring` skill/reference documents mirrored from the project-root `.pi/` baseline) - `config/pkl/base/workflow-next-task.pkl` (canonical `/next-task` package with self-contained `sce-plan-review` and `sce-task-execution` documents plus the task instance from the shared context-sync skeleton) - `config/pkl/base/workflow-validate.pkl` (canonical `/validate` package with the self-contained `sce-validation` documents plus the plan instance from the shared context-sync skeleton) +- `config/pkl/base/workflow-commit.pkl` (canonical `/commit` package with the self-contained `sce-atomic-commit` skill and references) - `config/pkl/base/workflow-context-sync.pkl` (one role-parameterized shared-fragment skeleton that emits exact, self-contained task and plan context-sync packages) - `config/pkl/base/opencode.pkl` - `config/pkl/base/sce-config-schema.pkl` @@ -20,6 +21,7 @@ Current target renderer helper modules: - `config/pkl/renderers/opencode-content.pkl` - `config/pkl/renderers/claude-content.pkl` +- `config/pkl/renderers/claude-workflow-results.pkl` (Claude-only Markdown phase-result contracts and package-local path overrides) - `config/pkl/renderers/pi-content.pkl` - `config/pkl/renderers/common.pkl` - `config/pkl/renderers/opencode-metadata.pkl` @@ -34,15 +36,15 @@ The scaffold provides stable canonical content-unit identifiers and reusable tar Renderer modules apply target-specific metadata/frontmatter rules while reusing canonical content bodies: -- The manual OpenCode renderer consumes the three canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. -- Claude renderer consumes the three canonical workflow packages directly, extends command and skill entrypoint frontmatter with `allowed-tools` and `compatibility: claude`, flattens nested package documents, and emits exactly three commands plus seven self-contained skill packages without generated agents. Claude settings and the hook helper remain separate retained outputs. -- Pi renderer consumes the three canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly three prompts to `config/.pi/prompts/{slug}.md` and seven self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). +- The manual OpenCode renderer consumes the four canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. +- Claude renderer consumes the four canonical workflow packages, extends command and skill entrypoint frontmatter with `allowed-tools` and `compatibility: claude`, and emits exactly four commands plus eight self-contained skill packages without generated agents. `claude-workflow-results.pkl` replaces the five canonical YAML-returning skill contracts with Markdown layouts, folds those contracts (plus plan-template and validation-result) into each package's `SKILL.md`, and keeps at most one human-presentation file under `references/` per Claude package. Validation and context-sync human reports remain package-local `references/` documents when present. Claude settings and the hook helper remain separate retained outputs. +- Pi renderer consumes the four canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly four prompts to `config/.pi/prompts/{slug}.md` and eight self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). - Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tool and compatibility fields. Pi workflow documents own their supported frontmatter directly. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts the exact current inventory—three commands, all 18 documents in seven self-contained skill packages, and two OpenCode agents—then forces every rendered document and target metadata lookup to evaluate across OpenCode, Claude, and Pi. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode/Pi's 21 multi-file skill documents, Claude's reduced single human-presentation skill inventory (machine contracts inlined in `SKILL.md`), and two OpenCode agents—then forces every rendered document and target metadata lookup to evaluate. - OpenCode, Claude, and Pi renderers expose canonical command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`. -- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's three workflow commands, seven complete skill packages with nested references, and two thin routing agents; Claude's three workflow commands and seven complete skill packages with nested references but no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (three workflow prompts, seven complete skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. +- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete skill packages with nested references, and two thin routing agents; Claude's four workflow commands and eight complete skill packages with nested references but no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four workflow prompts, eight complete skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. - `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. @@ -182,8 +184,9 @@ Shared Context Plan and Shared Context Code remain separate architectural roles. - Shared Context Code owns exactly one approved task execution, validation, and mandatory `context/` synchronization. - `/change-to-plan` and `/next-task` remain separate command entrypoints aligned to those roles. - Reuse is handled through shared canonical guidance blocks and skill-owned phase contracts, not by collapsing both roles into one agent. -- OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task` and `/validate`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole Markdown behavior owners. +- OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole behavior owners. - `/change-to-plan` sequences `sce-context-load` and `sce-plan-authoring`, preserving context loading, clarification, plan output, and `/next-task` handoff ownership. - `/next-task` owns one-task sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, including its implementation gate and continuation contract. - `/validate` owns final sequencing across `sce-validation` and validated-only `sce-plan-context-sync`. -- OpenCode, Claude, and Pi expose no generated `/commit` or `/handover` command, and the automated OpenCode profile is removed. +- `/commit` owns regular proposal-only and bypass sequencing around `sce-atomic-commit`. +- OpenCode, Claude, and Pi expose the generated `/commit` workflow but no generated `/handover` command; the automated OpenCode profile is removed. diff --git a/context/context-map.md b/context/context-map.md index 07ab554a..69dccee2 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -25,9 +25,9 @@ Feature/domain context: - `context/sce/shared-context-code-workflow.md` - `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, and one-task/one-atomic-commit task-slicing policy) - [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) -- `context/sce/plan-code-overlap-map.md` (current overlap matrix for thin OpenCode Plan/Code routing agents, the three workflow commands, and their phase-skill ownership boundaries) -- `context/sce/dedup-ownership-table.md` (current canonical owner-vs-consumer matrix for the three workflow packages, seven phase skills, shared sync skeleton, and thin OpenCode agents) -- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, command-vs-`sce-atomic-commit` ownership boundary, staged-truth rule, plan-citation rule, and result contract; currently a project-root `.pi/` baseline only, not yet canonical Pkl or generated) +- `context/sce/plan-code-overlap-map.md` (overlap matrix for thin OpenCode Plan/Code routing agents and workflow phase ownership; its original three-workflow inventory predates the generated `/commit` package) +- `context/sce/dedup-ownership-table.md` (canonical owner-vs-consumer boundaries for workflow packages, phase skills, the shared sync skeleton, and thin OpenCode agents; its original three-workflow/seven-skill inventory predates generated `/commit` and `sce-atomic-commit`) +- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, command-vs-`sce-atomic-commit` ownership boundary, staged-truth rule, plan-citation rule, and result contract; now canonical Pkl and generated for OpenCode, Claude, and Pi) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) diff --git a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md index c31909a6..223dd088 100644 --- a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md +++ b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md @@ -6,11 +6,12 @@ Plan: `context/plans/rebuild-pkl-workflow-markdown.md` ## Decision -- Model generated SCE Markdown as three canonical workflow packages: `/change-to-plan`, `/next-task`, and `/validate`. +- Model generated SCE Markdown as four canonical workflow packages: `/change-to-plan`, `/next-task`, `/validate`, and `/commit`. - Use the project-root `.pi/` prompts, skills, and package-local references as the behavioral baseline. -- Generate the same seven self-contained skill packages for Pi, OpenCode, and Claude. A generated skill may share Pkl source with another skill, but it must not depend on a sibling generated package. +- Generate the same eight self-contained skill packages for Pi, OpenCode, and Claude. A generated skill may share Pkl source with another skill, but it must not depend on a sibling generated package. +- Preserve canonical YAML phase-result contracts for Pi and OpenCode, while Claude renders target-specific Markdown contracts for the five structured phase skills; fixed statuses and labeled sections preserve command handoff semantics. - Instantiate `sce-task-context-sync` and `sce-plan-context-sync` from one role-parameterized Pkl skeleton while preserving their distinct handoff gates, lifecycle boundaries, and reports. -- Keep only two generated agents, both for OpenCode and both routing-only: Plan routes to `/change-to-plan`; Code routes to `/next-task` and `/validate`. Claude and Pi receive no generated agents. +- Keep only two generated agents, both for OpenCode and both routing-only: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi receive no generated agents. - Remove the automated OpenCode profile and obsolete generated commit, handover, bootstrap, atomic-commit, and legacy context-sync Markdown surfaces. - Preserve retained non-Markdown generation for OpenCode plugins/config, Claude settings/hooks, the Pi extension, and the SCE config schema. @@ -22,8 +23,8 @@ The automated profile and obsolete Markdown catalog represented a second behavio ## Consequences -- Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`. -- Generated inventory is three commands and seven skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. +- Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`; Claude phase-result overrides live in `config/pkl/renderers/claude-workflow-results.pkl`. +- Generated inventory is four commands and eight skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. - `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/check-generated.sh`, and the root flake parity check enforce exact inventories, nested package references, and forbidden removed trees. - `config/automated/.opencode` and `config/.claude/agents` are forbidden outputs rather than compatibility surfaces. diff --git a/context/glossary.md b/context/glossary.md index 67ea09cb..6ed9508b 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -8,7 +8,9 @@ - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. -- `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, and `/validate` this way and has no generated agent-role prompts. +- `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. +- `Claude Markdown phase-result contract`: Claude-only transport form for the structured results returned by `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`. Fixed `Status` lines, headings, and labels preserve the canonical status variants and command-readable values while Pi and OpenCode retain package-local YAML contracts under `references/`. On Claude these contracts (and plan-template / validation-result) are inlined into `SKILL.md` so each package keeps at most one human-presentation `references/` file; validation and context-sync human reports remain Markdown for every target. +- `Claude human-presentation reference`: Optional single file under a Claude skill package's `references/` used only for human-facing layouts (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, `commit-message-style.md`). Machine contracts stay multi-file under `references/` for OpenCode and Pi. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. diff --git a/context/overview.md b/context/overview.md index 496addca..49345b38 100644 --- a/context/overview.md +++ b/context/overview.md @@ -54,8 +54,9 @@ The current supported automated release target matrix is `x86_64-unknown-linux-m The downstream publish-stage implementation is now complete for both registries: `.github/workflows/publish-crates.yml` publishes the checked-in crate version after `.version`/tag/Cargo parity checks, and `.github/workflows/publish-npm.yml` publishes the checked-in npm package after `.version`/tag/npm parity checks plus verification of the canonical `sce-v-npm.tgz` GitHub release asset. The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. -Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes only to `/next-task` and `/validate`. Workflow behavior lives in the canonical commands and seven self-contained skill packages rather than in agent bodies. -The `/change-to-plan` command sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. +Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four canonical commands and eight self-contained skill packages rather than in agent bodies. +The `/change-to-plan` command sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. +Claude preserves these shared workflow semantics but uses target-specific Markdown result contracts for the five phase skills whose canonical Pi/OpenCode handoffs are YAML (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`). Fixed status lines, headings, and labels carry the same command-readable values without exposing raw phase reports as user-facing workflow output. Claude alone also folds those machine contracts and plan templates into each skill's `SKILL.md` so generated Claude packages keep at most one human-presentation `references/` file. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. The prior no-git-wrapper Agent Trace design artifacts under `context/sce/agent-trace-*.md` are retained only as historical reference; the current CLI runtime no longer wires the removed Agent Trace schema adaptation, payload building, retry replay, or rewrite handling paths into local hook execution. @@ -69,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the three SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi, OpenCode, and Claude consume this model directly. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi and OpenCode consume the canonical result contracts directly, while Claude applies its phase-result transport override in the renderer layer. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. @@ -101,7 +102,7 @@ Lightweight post-task verification baseline (required after each completed task) ## Cross-target parity -- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly three rebuilt prompts and seven self-contained skill packages with no agent-role prompts. Manual OpenCode consumes the same workflow packages as exactly three commands, seven self-contained skill packages, and two thin routing agents. Claude consumes exactly three commands and seven self-contained skill packages with no generated agents, while retaining its generated settings and hook helper. +- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four prompts and eight self-contained skill packages with no agent-role prompts. Manual OpenCode consumes the same workflow packages as exactly four commands, eight self-contained skill packages, and two thin routing agents. Claude consumes exactly four commands and eight self-contained skill packages with no generated agents, while retaining its generated settings and hook helper. - When capabilities differ, parity is implemented by supported target-specific behavior rather than forcing unsupported fields. ## Context navigation diff --git a/context/patterns.md b/context/patterns.md index e87eeffb..1bc51898 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -49,17 +49,19 @@ ## Pkl renderer layering -- Keep the three target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`, with package primitives in `workflow-content.pkl` and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. +- Keep the four target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with package primitives in `workflow-content.pkl` and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. - Keep cross-target generated-config primitives in focused base modules under `config/pkl/base/` and re-export them through `config/pkl/renderers/common.pkl` when multiple renderers need the same contract. - Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. -- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`. +- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`. Keep canonical Pi/OpenCode YAML phase-result contracts and multi-file `references/` inventories unchanged. For Claude only: render the five structured phase results as package-local Markdown contracts with fixed `Status` lines, headings, and labels, and fold machine contracts plus plan templates into each package's `SKILL.md` so Claude packages keep at most one human-presentation `references/` file when present (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, or `commit-message-style.md`). - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi-compatible metadata remains in canonical workflow documents. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. - Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path; run it whenever workflow documents or target metadata change. -- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve the workflow body, and append only the required final newline at the output mapping. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve the workflow body, and append only the required final newline at the output mapping. Claude is the single exception: it may also apply target-specific body transforms for harness behavior that other targets do not need, currently the phase-contract folding above and the turn-boundary rules below. +- Claude runs a skill inside the assistant's turn, so returning a phase result and printing it to the user are the same act and "do not print the result" is unenforceable. Keep Claude inter-phase handoffs shrunk to what the next phase cannot recover on its own: `sce-plan-review` `ready` carries plan and task identity, relevant files, relevant context, and assumptions, while goal, scope, done checks, dependencies, and verification stay in the plan file where `sce-task-execution` reads them for its implementation gate. `sce-task-execution` `complete` stays full-size because `sce-task-context-sync` validates changed files, implementation summary, verification evidence, done-check evidence, and context impact and blocks when any is missing. Check the consuming skill before shrinking any handoff field; user-facing layouts (`blocked`, `plan_complete`, `declined`, `incomplete`) are presentations, not handoffs, and stay whole. +- Claude ends a turn after a phase skill unless the rendered text says otherwise, so `config/pkl/renderers/` owns Claude-only turn-boundary text: append a `## Control flow` section to every Claude `SKILL.md` declaring the skill one phase of a workflow rather than a turn, and rewrite command continuation branches so that every step branching on a skill status carries exactly one `This step ends the turn only on {statuses}.` line, names the next skill or step, and states that the result is not workflow output. All four commands satisfy this invariant; a step whose only terminal branches are stop branches is the gap to look for. Keep this in the renderers; `config/pkl/base/workflow-*.pkl` stays target-agnostic and OpenCode and Pi output stays byte-identical. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. - Validate each renderer module directly with `nix develop -c pkl eval ` before wiring output emission. @@ -69,6 +71,7 @@ - For `/change-to-plan`, sequence `sce-context-load` before `sce-plan-authoring`; keep context loading, clarification, plan output, and `/next-task` handoff in their declared owners. - For `/next-task`, retain one-task sequencing and confirmation gates while delegating phase details to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. - For `/validate`, run `sce-validation` first and invoke `sce-plan-context-sync` only for a validated result. +- For `/commit`, delegate staged-diff analysis and commit-message construction to `sce-atomic-commit`, preserving regular proposal-only and explicit bypass behavior. - Preserve mandatory gates and authoritative handoffs while removing duplicated phase instructions from agents or sibling skills. ## Multi-file generation entrypoint diff --git a/context/plans/claude-markdown-workflow-results.md b/context/plans/claude-markdown-workflow-results.md new file mode 100644 index 00000000..da940867 --- /dev/null +++ b/context/plans/claude-markdown-workflow-results.md @@ -0,0 +1,99 @@ +# Plan: claude-markdown-workflow-results + +## Change summary + +Replace YAML-only phase result handoffs in the generated Claude workflow skill packages with Markdown contracts that preserve the same status variants and command-to-skill data. OpenCode and Pi keep their current YAML contracts, while Claude commands continue rendering the internal phase results into the existing user-facing workflow responses instead of exposing raw handoffs. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: Every generated Claude skill that currently returns a YAML result (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`) instead returns one Markdown result with the same status variants and all fields required by its invoking command. + - Validate: generate a temporary payload with `nix run .#pkl-generate -- "$(mktemp -d)"`; inspect the five Claude skill entrypoints and their result-contract references for Markdown-only return instructions, complete status layouts, and command-readable labels. +- [x] AC2: Generated Claude workflow commands consume the Markdown phase handoffs and still render only their established user-facing clarification, readiness, execution, commit, and continuation responses; raw internal phase reports are not presented as the final workflow response. + - Validate: inspect the four generated Claude commands together with the five converted skill contracts and confirm every status branch and referenced value has an unambiguous Markdown source and an existing user-facing rendering branch. +- [x] AC3: OpenCode and Pi retain their current YAML result contracts and workflow behavior byte-for-byte while only Claude receives the target-specific Markdown variants. + - Validate: generate before/after payloads from the implementation base and working tree, then run `diff -rq` over `config/.opencode` and `config/.pi`; only `config/.claude` workflow Markdown may differ. +- [x] AC4: Exact metadata coverage accepts the target-specific Claude contract paths, rejects missing or extra workflow documents per target, and deterministic ephemeral generation passes. + - Validate: `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` to describe Claude's target-specific Markdown phase-result contract while preserving the canonical shared workflow semantics. +- Reconcile the stale three-workflow/seven-skill inventory claims in `context/context-map.md`, `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, and `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` with the implemented four-workflow/eight-skill generator inventory. + +## Constraints and non-goals + +- **In scope:** Canonical Pkl workflow/result-contract modeling, Claude renderer overrides, Claude workflow skill references and instructions, exact target inventory coverage, and focused generation documentation. +- **Out of scope:** Changes to workflow status semantics, command sequencing, implementation gates, user-facing continuation layouts, Rust CLI behavior, Claude hooks/settings, or generated repository target trees. +- **Constraints:** Keep self-contained skill packages and deterministic package-local references; preserve the project-root `.pi/` baseline and OpenCode output; author changes in canonical Pkl and renderers rather than generated payloads; retain every field the invoking command needs to branch or render its response. +- **Non-goal:** Replace YAML contracts for OpenCode or Pi, or convert validation/context-sync reports that already use Markdown. + +## Assumptions + +- “Claude workflow” covers all five YAML-returning skills currently generated for Claude across `/change-to-plan`, `/next-task`, and `/commit`, not only the phase that exposed the reported result. +- Markdown contracts remain structured through fixed headings, status labels, and repeated labeled sections so invoking commands can consume them without YAML. +- `/validate`, `sce-validation`, `sce-task-context-sync`, and `sce-plan-context-sync` need no result-format conversion because their current handoffs are already Markdown. + +## Task stack + +- [x] T01: `Render Claude phase results as Markdown` (status:done) + - Task ID: T01 + - Goal: Give every YAML-returning Claude workflow skill a complete target-specific Markdown result contract while preserving shared workflow semantics and all non-Claude outputs. + - Boundaries (in/out of scope): In — target-specific result-contract modeling for the five affected skills, Claude skill entrypoint/reference rendering, command compatibility, exact per-target inventory checks, and focused Pkl generation documentation. Out — status/field redesign, OpenCode or Pi behavior changes, validation/context-sync report changes, generated target-tree edits, and runtime code. + - Dependencies: none + - Done when: A temporary generated Claude payload contains Markdown-only result instructions and `.md` contracts for all five affected skills; every command branch can source its required values; exact coverage passes with target-specific inventories; before/after comparison shows no OpenCode or Pi changes; focused generation checks pass. + - Verification notes (commands or checks): `nix develop -c pkl eval config/pkl/renderers/{claude-content,opencode-content,pi-content,metadata-coverage-check}.pkl`; generate temporary before/after payloads and inspect/diff the three target workflow trees; `nix run .#pkl-check-generated`; `git diff --check -- config/pkl`. + - Completed: 2026-07-28 + - Files changed: `config/pkl/renderers/claude-workflow-results.pkl`, `config/pkl/renderers/claude-content.pkl`, `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/README.md`, `context/plans/claude-markdown-workflow-results.md` + - Evidence: focused evaluation of `claude-content.pkl`, `opencode-content.pkl`, `pi-content.pkl`, and `metadata-coverage-check.pkl` passed; temporary HEAD/current payload comparison showed byte-identical OpenCode and Pi trees and only the five intended Claude skill packages changed; generated Claude packages contained all five `.md` contracts and no YAML instructions or YAML contract references; `nix run .#pkl-check-generated` passed with 85 files and inventory SHA-256 `f465ad7139a66f8530581186b8db77405afa7203be9a6ce9e6de9624e238cd0b`; `git diff --check -- config/pkl` passed. + - Notes: Canonical Pi/OpenCode YAML contracts remain unchanged; Claude performs package-local path and content overrides in its renderer. + +## Open questions + +None. The reported failure identifies YAML as a Claude-specific transport problem, and the existing Markdown validation/synchronization reports establish a repository-local alternative without changing workflow semantics for other targets. + +## Validation Report + +**Status:** failed +**Date:** 2026-07-28 + +### Commands run + +- `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` -> exit 0 (exact target-specific metadata coverage passed) +- `nix run .#pkl-check-generated` -> exit 0 (85-file deterministic inventory passed with SHA-256 `f465ad7139a66f8530581186b8db77405afa7203be9a6ce9e6de9624e238cd0b`) +- `nix flake check` -> exit 1 (`sce-cli-generated-input` could not find the untracked imported module `config/pkl/renderers/claude-workflow-results.pkl` in the Git-backed flake source) +- `nix run .#pkl-generate -- "$(mktemp -d)"` with generated Claude path inspection -> exit 0 (all four workflow commands and all five converted skill packages were generated) +- temporary HEAD/current `pkl eval` generation, non-Claude `diff -rq`, and shell-only Claude contract/command inspection -> exit 0 (OpenCode and Pi were byte-identical; all five Markdown contracts exposed the required statuses; Claude commands exposed every converted handoff branch) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: Every affected generated Claude skill returns a Markdown result with preserved statuses and command-readable fields -> generated-payload inspection confirmed Markdown-only entrypoints, `.md` contracts, and every required status for all five skills. +- [x] AC2: Claude commands consume Markdown handoffs while retaining user-facing rendering -> generated command inspection confirmed branches for every converted phase status and retained response-rendering instructions. +- [x] AC3: OpenCode and Pi remain byte-for-byte unchanged -> HEAD/current ephemeral generation followed by `diff -rq` passed for both target trees. +- [x] AC4: Exact metadata coverage and deterministic ephemeral generation pass -> metadata evaluation and `nix run .#pkl-check-generated` both passed. + +### Failed checks and follow-ups + +- `nix flake check`: the Git-backed flake source omitted the new untracked renderer, so `sce-cli-generated-input` failed with `Cannot find module .../config/pkl/renderers/claude-workflow-results.pkl`; required: add `config/pkl/renderers/claude-workflow-results.pkl` to the Git index (or otherwise make it part of the Git-backed flake source), then rerun final validation. + +### Residual risks + +- Repository-wide flake checks have not passed with the new renderer visible to the Git-backed Nix source. + +### Retry + +After repairs, rerun: + +`/validate context/plans/claude-markdown-workflow-results.md` diff --git a/context/plans/skill-references-human-presentation-only.md b/context/plans/skill-references-human-presentation-only.md new file mode 100644 index 00000000..c8bc3d59 --- /dev/null +++ b/context/plans/skill-references-human-presentation-only.md @@ -0,0 +1,108 @@ +# Plan: skill-references-human-presentation-only + +## Change summary + +Claude still confuses multi-file skill `references/` packages after the Markdown result-contract conversion: result contracts, plan templates, style guides, and human-facing presentation layouts all live side by side under `references/`, so the agent mixes handoff shapes with chat presentation. + +Apply a **Claude-only** package shape: for generated Claude skill packages, `references/` holds **at most one file**, and that file is **only** the layout used to present work to a human reviewer. Machine-facing material—phase result contracts, plan templates, and similar agent contracts—is folded into each Claude package’s `SKILL.md` in the Claude renderer. Canonical Pkl packages, OpenCode, and Pi keep their existing multi-file inventories and YAML contracts unchanged. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [x] AC1: Every generated **Claude** skill package has either zero or one file under `references/`, and when a reference file exists it is a human-facing presentation layout (plan summary, implementation gate, validation report, sync report, or commit-message style), not a phase result contract or plan-template contract. OpenCode and Pi skill packages keep their existing multi-file reference inventories. + - Validate: `tmp="$(mktemp -d)"; nix run .#pkl-generate -- "$tmp"; find "$tmp/config/.claude" -path '*/skills/*/references/*' | sort` and assert each Claude package directory contains ≤1 reference file with an allowed human-presentation name; confirm OpenCode/Pi still include machine contracts under `references/`. +- [x] AC2: Phase result contracts and plan-template content remain available inside each Claude package’s `SKILL.md` so commands still receive the same status variants and command-readable fields; no Claude skill depends on a sibling package for those contracts. + - Validate: inspect generated Claude `SKILL.md` files for the five Markdown phase-result skills plus `sce-validation`; confirm each still documents its return statuses/fields and, where applicable, plan-template rules; confirm no Claude `references/*-contract*` or `references/plan-template.md` paths remain. +- [x] AC3: Exact per-target metadata coverage and deterministic ephemeral generation accept Claude’s reduced inventory while OpenCode/Pi inventories stay byte-stable for skill document paths. + - Validate: `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, and `context/glossary.md` so the single human-presentation `references/` rule is described as a **Claude-only** render shape, not a canonical/OpenCode/Pi package change. +- Update `config/pkl/README.md` generation docs for the Claude-only single human-presentation reference rule. +- Do **not** require `.pi/` baseline inventory changes or OpenCode/Pi reference reductions. + +## Constraints and non-goals + +- **In scope:** Claude renderer packaging (`claude-workflow-results.pkl` / `claude-content.pkl`), Claude metadata coverage inventory, focused generation documentation, and durable context that names the Claude-only rule. +- **Out of scope:** Changing canonical Pkl workflow package inventories, OpenCode or Pi skill trees, project-root `.pi/` baselines, workflow status semantics, command sequencing, approval-gate content, Rust CLI behavior, hooks/settings/plugins, or inventing new user-facing surfaces. +- **Constraints:** Keep packages self-contained per target; keep OpenCode/Pi behavior and inventories equivalent to today; preserve every field Claude commands need to branch and render; author only in Pkl sources, not committed generated target trees. +- **Non-goal:** Applying the single-reference rule to OpenCode or Pi; removing human presentation layouts; collapsing multiple skills into one package; re-opening the YAML-vs-Markdown transport debate beyond relocating Claude’s machine contracts out of multi-file `references/`. + +## Assumptions + +- “Presenting to the human reviewer” means user-facing chat or plan-attached presentation layouts: `plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, and `commit-message-style.md`. Phase result contracts (`*-contract*`, `context-brief*`, `validation-result.md`) and `plan-template.md` are agent contracts and, **for Claude only**, move into `SKILL.md`. +- Claude skills that today only have a machine contract (`sce-context-load`, `sce-plan-review`) end with **zero** reference files after the fold. Skills that already have a single human report (`sce-*-context-sync`) keep that one file. +- Canonical packages continue to author multi-file `references/` including YAML contracts; Claude’s renderer is the sole place the reduced inventory is produced. +- Inlining contracts may lengthen Claude `SKILL.md`; that is acceptable if section headings remain unambiguous. + +## Task stack + +- [x] T01: `Fold Claude machine references into SKILL.md` (status:done) + - Task ID: T01 + - Goal: In the Claude renderer only, emit at most one `references/` document per skill package (human-presentation layouts only); fold Markdown phase-result contracts, plan-template, and validation-result content into the owning Claude `SKILL.md`; leave canonical packages and OpenCode/Pi inventories unchanged. + - Boundaries (in/out of scope): In — `config/pkl/renderers/claude-workflow-results.pkl`, `config/pkl/renderers/claude-content.pkl`, and Claude-only path rewrites/section appends for machine material. Out — canonical `config/pkl/base/workflow-*.pkl` inventory changes, OpenCode/Pi renderers, `.pi` baseline mirror. + - Dependencies: none + - Done when: Generated Claude packages keep only allowed human-presentation references (or none); each folded contract’s statuses/fields appear in Claude `SKILL.md`; generated OpenCode/Pi skill document path sets match the pre-change multi-file inventories. + - Verification notes (commands or checks): temporary `nix run .#pkl-generate` inventory of Claude vs OpenCode/Pi references; inspect Claude `SKILL.md` for `## Result contract` / `## Plan template`. + - Completed: 2026-07-28 + - Files changed: config/pkl/renderers/claude-workflow-results.pkl, config/pkl/renderers/claude-content.pkl + - Evidence: Generated Claude references are only commit-message-style, plan-summary, sync-report (×2), implementation-gate, validation-report. OpenCode/Pi still emit `references/*-contract.yaml`. Each of the six Claude skills with former machine contracts has `## Result contract` in SKILL.md; plan-authoring also has `## Plan template`. + - Notes: Scope revised mid-work from all-target to Claude-only; canonical base packages left unchanged. + +- [x] T02: `Align Claude coverage docs with single-reference packages` (status:done) + - Task ID: T02 + - Goal: Make exact metadata coverage and generation docs match Claude’s reduced single human-presentation reference inventories without changing OpenCode/Pi expected paths or workflow status semantics. + - Boundaries (in/out of scope): In — `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/README.md`, and durable context wording for the Claude-only rule. Out — OpenCode/Pi inventories, `.pi/skills/**`, application code. + - Dependencies: T01 + - Done when: Metadata coverage expects the reduced Claude inventory and unchanged OpenCode/Pi inventories; docs state the rule is Claude-only. + - Verification notes (commands or checks): `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. + - Completed: 2026-07-28 + - Files changed: config/pkl/renderers/metadata-coverage-check.pkl, config/pkl/README.md, context/patterns.md, context/architecture.md, context/overview.md, context/glossary.md + - Evidence: `pkl eval config/pkl/renderers/metadata-coverage-check.pkl` succeeded with Claude reduced inventory (14 skill documents) and OpenCode/Pi still on 21 multi-file paths. + - Notes: None. + +## Open questions + +- Is `commit-message-style.md` correctly treated as the human-presentation reference for Claude `/commit`, or should Claude commit packages have **zero** references with style folded into `SKILL.md` as well? Defaulting to keep the style guide as the single Claude reference. +- Should Claude keep `plan-summary.md` as the sole plan-authoring reference (default) rather than `plan-template.md`? Defaulting to `plan-summary.md` because it is the chat layout shown to the human after authoring. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-28 + +### Commands run + +- `tmp="$(mktemp -d)"; nix run .#pkl-generate -- "$tmp"; find "$tmp/config/.claude" -path '*/skills/*/references/*' | sort` (plus OpenCode/Pi inventory and per-package ref-count checks) -> exit 0 (Claude: 6 human-presentation refs, ≤1 per package; no machine contracts under Claude `references/`; OpenCode and Pi each still emit 13 multi-file refs including `*-contract.yaml` / `plan-template.md` / `validation-result.md`) +- Inspect generated Claude `SKILL.md` for phase-result skills plus `sce-validation` (and related packages) -> exit 0 (`## Result contract` present for sce-context-load, sce-plan-authoring, sce-plan-review, sce-task-execution, sce-validation, sce-atomic-commit; `## Plan template` present for sce-plan-authoring; no Claude `references/*-contract*`, `plan-template.md`, or `validation-result.md`) +- `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` -> exit 0 (all inventoryChecks complete, including claude-skill-documents and opencode/pi skill documents) +- `nix run .#pkl-check-generated` -> exit 0 (Ephemeral Pkl generation passed: 78 files) +- `nix flake check` -> exit 0 (all checks passed) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: Claude packages have 0–1 `references/` files, all human-presentation names only (`plan-summary`, `implementation-gate`, `validation-report`, `sync-report`×2, `commit-message-style`); OpenCode/Pi keep multi-file machine contracts -> ephemeral generate inventory +- [x] AC2: Folded result contracts and plan-template live in Claude `SKILL.md`; no Claude machine-contract reference paths remain -> SKILL.md inspection +- [x] AC3: Metadata coverage and ephemeral generation accept reduced Claude inventory with OpenCode/Pi inventories intact -> coverage eval + `pkl-check-generated` + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- Open questions remain about whether Claude should eventually drop `commit-message-style.md` / keep `plan-summary.md` vs fold further; current defaults match the plan and pass acceptance checks. +- None identified beyond those open questions. From 4133819ac48cd1f9e938657a5b5b6c68fd99ab59 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 15:03:43 +0200 Subject: [PATCH 13/21] config: Render Claude workflows as single-skill packages Collapse Claude workflow orchestration into four self-contained skills with one output reference each, while preserving the decomposed Pi and OpenCode packages. Co-authored-by: SCE --- .claude/commands/change-to-plan.md | 181 +-- .claude/commands/commit.md | 134 +- .claude/commands/next-task.md | 203 +-- .claude/commands/validate.md | 152 +-- .claude/skills/sce-atomic-commit/SKILL.md | 296 ----- .../SKILL.md | 503 +++++--- .../references/output.md} | 59 + .claude/skills/sce-commit/SKILL.md | 334 +++++ .../references/output.md} | 41 +- .claude/skills/sce-context-load/SKILL.md | 218 ---- .claude/skills/sce-next-task/SKILL.md | 939 ++++++++++++++ .../references/output.md} | 141 +++ .claude/skills/sce-plan-context-sync/SKILL.md | 317 ----- .../references/sync-report.md | 142 --- .claude/skills/sce-plan-review/SKILL.md | 267 ---- .claude/skills/sce-task-context-sync/SKILL.md | 319 ----- .claude/skills/sce-task-execution/SKILL.md | 432 ------- .../references/implementation-gate.md | 73 -- .claude/skills/sce-validate/SKILL.md | 767 ++++++++++++ .../skills/sce-validate/references/output.md | 429 +++++++ .claude/skills/sce-validation/SKILL.md | 387 ------ .../references/validation-report.md | 84 -- .opencode/agent/Shared Context Code.md | 1 + config/pkl/README.md | 8 +- config/pkl/renderers/claude-content.pkl | 166 +-- config/pkl/renderers/claude-metadata.pkl | 9 +- .../pkl/renderers/claude-workflow-results.pkl | 1090 ++++++----------- .../pkl/renderers/metadata-coverage-check.pkl | 43 +- config/pkl/renderers/opencode-metadata.pkl | 1 + context/architecture.md | 18 +- context/context-map.md | 9 +- ...-07-27-workflow-oriented-pkl-generation.md | 4 +- ...26-07-29-claude-workflow-skill-packages.md | 34 + context/glossary.md | 12 +- context/overview.md | 8 +- context/patterns.md | 19 +- .../claude-workflow-single-skill-packages.md | 70 ++ context/sce/atomic-commit-workflow.md | 36 +- context/sce/shared-context-code-workflow.md | 14 +- context/sce/shared-context-plan-workflow.md | 13 +- 40 files changed, 3708 insertions(+), 4265 deletions(-) delete mode 100644 .claude/skills/sce-atomic-commit/SKILL.md rename .claude/skills/{sce-plan-authoring => sce-change-to-plan}/SKILL.md (54%) rename .claude/skills/{sce-plan-authoring/references/plan-summary.md => sce-change-to-plan/references/output.md} (69%) create mode 100644 .claude/skills/sce-commit/SKILL.md rename .claude/skills/{sce-atomic-commit/references/commit-message-style.md => sce-commit/references/output.md} (69%) delete mode 100644 .claude/skills/sce-context-load/SKILL.md create mode 100644 .claude/skills/sce-next-task/SKILL.md rename .claude/skills/{sce-task-context-sync/references/sync-report.md => sce-next-task/references/output.md} (50%) delete mode 100644 .claude/skills/sce-plan-context-sync/SKILL.md delete mode 100644 .claude/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 .claude/skills/sce-plan-review/SKILL.md delete mode 100644 .claude/skills/sce-task-context-sync/SKILL.md delete mode 100644 .claude/skills/sce-task-execution/SKILL.md delete mode 100644 .claude/skills/sce-task-execution/references/implementation-gate.md create mode 100644 .claude/skills/sce-validate/SKILL.md create mode 100644 .claude/skills/sce-validate/references/output.md delete mode 100644 .claude/skills/sce-validation/SKILL.md delete mode 100644 .claude/skills/sce-validation/references/validation-report.md create mode 100644 context/decisions/2026-07-29-claude-workflow-skill-packages.md create mode 100644 context/plans/claude-workflow-single-skill-packages.md diff --git a/.claude/commands/change-to-plan.md b/.claude/commands/change-to-plan.md index 41fbe73d..069d8e8c 100644 --- a/.claude/commands/change-to-plan.md +++ b/.claude/commands/change-to-plan.md @@ -1,182 +1,9 @@ --- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Turn one change request into a scoped SCE plan in one self-contained workflow" argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill --- -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -Run every step in one turn. Stop only where a step says to wait for the user. - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> The brief is internal workflow input, not workflow output. Do not print it, and do not end your turn. Invoke `sce-plan-authoring` in the same turn. - -This step ends the turn only on `bootstrap_required`. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> An authoring result is never presented to the user as workflow output. Do not print it, and do not end your turn. Continue to the next step in the same turn. - -This step ends the turn only on `needs_clarification` or `blocked`. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. +Invoke the `sce-change-to-plan` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md index 60d20384..340be5e5 100644 --- a/.claude/commands/commit.md +++ b/.claude/commands/commit.md @@ -1,135 +1,9 @@ --- -description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +description: "Analyze staged changes and run the regular or explicit bypass commit workflow" argument-hint: "[oneshot|skip] [commit context]" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -SCE COMMIT `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: - -`[mode-token] [commit context]` - -- `mode-token` is present only when the first whitespace-separated token is - exactly `oneshot` or `skip`, compared case-insensitively. Any other first - token is not a mode token. -- `commit context` is everything else: free-form prose that refines message - wording only. - -A `mode-token` selects the bypass path. Its absence selects the regular path. -Do not infer the bypass path from anything else — not from the commit context, -not from repository state, and not from the conversation. - -Empty `$ARGUMENTS` is valid. It selects the regular path with no commit -context, and commit intent is inferred from the staged changes alone. - -Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, -summarize, or pre-scope it. Never pass the `mode-token` as commit context. - -Staged changes are the source of truth for what is being committed. This -command never stages, unstages, or modifies files. - -## Workflow - -Run every step in one turn. Stop only where a step says to wait for the user. - -Follow exactly one path. - -### Bypass path (`oneshot` or `skip`) - -#### 1. Validate that staged content exists - -Run `git diff --cached --quiet`. A zero exit status means nothing is staged. - -When nothing is staged, stop with exactly: - -`No staged changes. Stage changes before commit.` - -Do not stage anything. Do not proceed to the skill. - -#### 2. Request one commit message - -Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. - -Bypass mode is the skill's contract for producing exactly one message. Do not -restate its overrides here; `sce-atomic-commit` owns them. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and stop. Do not commit. - -`bypass_message` -> The message is internal workflow input, not workflow output. Do not print it as the deliverable, and do not end your turn. The commit is this path's deliverable, so continue to the next step in the same turn. - -This step ends the turn only on `blocked` or a contract violation. - -The skill never returns `proposal` in bypass mode. Treat a `proposal` result as -a contract violation: report it and stop without committing. - -#### 3. Execute exactly one commit - -Run `git commit` once with the returned message. - -On success, report the resulting commit hash and stop. - -On failure, report the failure as returned by Git and stop. Do not retry, do -not amend, do not stage additional files, and do not invent a fallback commit. - -### Regular path (no mode token) - -#### 1. Confirm staging - -Before invoking the skill, stop and prompt the user: - -``` -Please run `git add ` for all changes you want included in this commit. -Atomic commits should only include intentionally staged changes. -Confirm once staging is complete. -``` - -Wait for the user's confirmation. Do not stage files on their behalf, and do -not skip this prompt because the working tree looks ready. - -#### 2. Propose commits - -After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the -commit context. - -`sce-atomic-commit` exclusively owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Classifying staged scope and applying context-file guidance gating. -- Writing every commit message subject and body. -- Applying the plan-citation body rule. - -Do not duplicate any of it. Do not write commit messages yourself. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and the decision it requires. Stop. - -`proposal` -> Present each proposed commit: its message, the files it covers, -and, when more than one commit is proposed, why the split is recommended. - -Then stop. The regular path is proposal-only. - -Do not run `git commit`. Do not offer to commit on the user's behalf. The user -runs the commits they accept. - -## Rules - -- Produce at most one commit per invocation, and only on the bypass path. -- Never commit on the regular path. -- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. - They are behaviorally identical. -- Do not duplicate the internal instructions of `sce-atomic-commit`. -- Do not stage, unstage, restore, or otherwise modify files. -- Do not amend, reset, revert, rebase, or push. -- Do not read unstaged or untracked changes as commit input. -- Do not infer success when `sce-atomic-commit` returns a non-success status. -- Do not proceed past a failed `git commit`. -- Do not run plan, task, or validation workflows from this command. +Invoke the `sce-commit` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.claude/commands/next-task.md b/.claude/commands/next-task.md index c5846c65..5208ae96 100644 --- a/.claude/commands/next-task.md +++ b/.claude/commands/next-task.md @@ -1,204 +1,9 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +description: "Review, approve, implement, verify, and synchronize one SCE plan task" argument-hint: " [T0X] [approved]" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -Run every step in one turn. Stop only where a step says to wait for the user. - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> A readiness result is never presented to the user. Do not print it, and do not end your turn. Pass the complete readiness result to `sce-task-execution` in the same turn. - -The readiness result is a compact handoff: plan and task identity, relevant files, relevant context, and review assumptions. It deliberately omits the task's goal, scope, done checks, dependencies, and verification, which `sce-task-execution` reads from the plan and presents in its implementation gate. Do not reconstruct the omitted fields, and do not treat their absence as a stale handoff. - -This step ends the turn only on `blocked` or `plan_complete`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> Do not print the raw result, and do not end your turn. Invoke `sce-task-context-sync` in the same turn. - -This result stays full-size: `sce-task-context-sync` validates the changed files, implementation summary, verification evidence, done-check evidence, and context impact, and blocks when any is missing. Pass it through untouched rather than trimming it to match the compact readiness handoff. - -This step ends the turn only on `declined`, `blocked`, or `incomplete`. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, implementation summary, verification evidence, done-check evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned, then continue to the next step in the same turn. Do not end your turn before the continuation block. - -This step ends the turn only on `blocked`. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. +Invoke the `sce-next-task` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.claude/commands/validate.md b/.claude/commands/validate.md index 005c733f..a93d849e 100644 --- a/.claude/commands/validate.md +++ b/.claude/commands/validate.md @@ -1,153 +1,9 @@ --- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +description: "Validate one completed SCE plan and synchronize its durable context" argument-hint: "" allowed-tools: Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash --- -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -Run every step in one turn. Stop only where a step says to wait for the user. - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> A validated result is never presented to the user as workflow -output. Do not print it, and do not end your turn. Pass the complete validated -Markdown result to `sce-plan-context-sync` in the same turn. - -This step ends the turn only on `blocked` or `failed`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned, then continue to the next step in the same -turn. Do not end your turn before the completion block. - -This step ends the turn only on `blocked`. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. +Invoke the `sce-validate` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.claude/skills/sce-atomic-commit/SKILL.md b/.claude/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index ff7aec5c..00000000 --- a/.claude/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,296 +0,0 @@ ---- -name: sce-atomic-commit -description: > - Internal SCE workflow skill that analyzes the staged diff and returns atomic, - repository-style commit messages: coherent-unit detection, split guidance, - scope and subject wording, and the plan-citation body rule. Returns one Markdown - result (proposal, bypass_message, or blocked). Use from /commit. Do not stage - files, create commits, or ask the user to confirm staging. -compatibility: claude ---- - -# SCE Atomic Commit - -## Purpose - -Turn the current staged changes into atomic repository-style commit messages. - -This skill owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Choosing the scope and writing the subject and body of every message. -- Applying the plan-citation body rule. -- Classifying staged scope and applying context-file guidance gating. -- Returning one terminal Markdown result. - -Write messages matching: - -`references/commit-message-style.md` - -Return a result matching: - -the **Result contract** section in this file - -Committing is not this skill's job. The invoking `/commit` workflow decides -whether a returned message is committed, and it is the only thing that runs -`git commit`. - -## Input - -The invoking workflow provides: - -- A mode: `regular` or `bypass`. -- Optional commit context, in free-form prose. - -The mode is supplied by the workflow from an explicit user-supplied token. -Never infer it, and never switch modes mid-analysis. - -Commit context refines wording only. The staged diff decides what the change -is; context never overrides staged truth, and never adds a claim the diff does -not support. - -Do not accept an unstaged diff, a working-tree summary, or a conversational -description as a substitute for the staged diff. - -## Workflow - -### 1. Read the staged diff - -Read the staged changes with `git diff --cached`, and the staged file list with -`git diff --cached --name-status`. - -Read staged file contents only when the diff alone does not explain the change. - -Return `blocked` when nothing is staged. - -### 2. Identify coherent units - -Infer the main reason for the staged change from the diff first. - -A coherent unit is one goal a reviewer would accept as a single commit. Group -staged files by that goal, not by directory. - -In `bypass` mode, stop grouping here: the result is exactly one message -covering all staged files, whether or not the diff is coherent. Do not propose -splits, and do not report split guidance. - -### 3. Choose a scope for each unit - -Use the smallest stable subsystem or module name recognizable in the repository. - -When no such name applies, use the primary directory or package of the unit's -changes. - -### 4. Write each message - -Follow `references/commit-message-style.md` for the subject pattern, the body -rules, issue references, the plan-citation rule, and the anti-patterns. - -### 5. Apply the plan-citation rule - -When the unit's staged files include `context/plans/*.md`, cite the affected -plan slug and updated task IDs in the body. - -When the staged plan diff does not expose the slug or task ID clearly enough to -cite faithfully: - -- In `regular` mode, return `blocked` and ask for the reference to be stated or - staged explicitly. -- In `bypass` mode, infer the citation when the diff supports it, and otherwise - omit it. Never stop, and never invent a slug or task ID. - -### 6. Apply context-file guidance gating - -This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do -not classify staged scope there. - -Classify the staged diff: - -- Context-only (`context/**`): context-file-focused guidance is allowed. -- Mixed (`context/**` plus non-`context/**`): suppress default context-file - commit reminders and give guidance that reflects the full staged scope. - -### 7. Propose split guidance - -This step applies in `regular` mode only. - -When the units found in step 2 pursue unrelated goals, return one message per -unit, and state why the split is recommended and which staged files belong to -each. - -When the staged changes form one unit, return one message and no split -guidance. Do not split coherent work to appear thorough. - -### 8. Validate the result - -Confirm before returning that: - -- Every message describes its unit faithfully and covers only that unit's files. -- Every staged file belongs to exactly one returned message. -- No plan slug or task ID appears that the staged diff does not support. -- The mode's own constraints hold. - -### 9. Return Markdown - -Return exactly one Markdown document matching the **Result contract** section in this file: - -- `proposal` in `regular` mode, with one or more messages. -- `bypass_message` in `bypass` mode, with exactly one message. -- `blocked` when messages cannot be written faithfully. - -Return only the Markdown document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Run `git commit`, or any command that writes to the repository or its index. -- Stage, unstage, or modify files. -- Ask the user to stage or confirm staging. -- Analyze unstaged or untracked changes. -- Return more than one message in `bypass` mode. -- Return split guidance in `bypass` mode. -- Stop for plan-citation ambiguity in `bypass` mode. -- Invent plan slugs, task IDs, or issue references. -- Mention `context/` synchronization activity in a commit message. -- Claim a message was committed. -- Run plan, task, or validation workflows. - -## Completion - -The skill is complete after: - -- The staged diff was read, or reading it failed and was reported. -- Messages were written for every staged file, or a blocker prevented it. -- One valid terminal Markdown result matching the **Result contract** section in this file was - returned. - -## Result contract - -# SCE Atomic Commit Result Contract - -Return exactly one Markdown document using one layout below. `Status` is the -branch value consumed by `/commit`. Use every required heading and label -exactly as written, omit optional sections that do not apply, and do not add -prose outside the selected layout. - -Report paths exactly as `git diff --cached --name-only` reports them. Every -staged file belongs to exactly one proposed commit. Keep each message's body -in the same fenced block as its subject, separated by one blank line. Never -report a commit hash or guidance forbidden by the mode. - -## Status: `proposal` - -Use only in regular mode. Nothing is committed. - -````markdown -# Atomic Commit Result - -Status: proposal -Mode: regular - -## Commits - -### {commit.id} - -#### Message - -```text -{subject} - -{body} -``` - -#### Files - -- {file} - -#### Cites plan - -{true|false} - -## Split rationale - -{split_rationale} - -## Scope classification - -{context_only|mixed} - -## Notes - -- {note} -```` - -`Commits` is required. Repeat the commit block as needed. Include `Split -rationale` only for multiple commits. `Scope classification` and `Notes` are -optional. - -## Status: `bypass_message` - -Use only in bypass mode. Exactly one message covers every staged file. - -````markdown -# Atomic Commit Result - -Status: bypass_message -Mode: bypass - -## Message - -```text -{subject} - -{body} -``` - -## Files - -- {file} - -## Cites plan - -{true|false} - -## Notes - -- {note} -```` - -`Message` and `Files` are required. `Cites plan` and `Notes` are optional. -Never include commits, split rationale, or scope classification. - -## Status: `blocked` - -````markdown -# Atomic Commit Result - -Status: blocked -Mode: {regular|bypass} - -## Files - -- {file} - -## Issues - -### {issue.id} - -- Category: {no_staged_changes|plan_citation_ambiguity|unreadable_diff|contradictory_context} -- Problem: {problem} -- Impact: {impact} -- Decision required: {decision_required} -```` - -`Issues` is required. Include `Mode` when supplied and `Files` when staged -files were read. Plan-citation ambiguity blocks only in regular mode; bypass -mode omits the citation instead. - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-plan-authoring/SKILL.md b/.claude/skills/sce-change-to-plan/SKILL.md similarity index 54% rename from .claude/skills/sce-plan-authoring/SKILL.md rename to .claude/skills/sce-change-to-plan/SKILL.md index 06f4a7f5..1a504888 100644 --- a/.claude/skills/sce-plan-authoring/SKILL.md +++ b/.claude/skills/sce-change-to-plan/SKILL.md @@ -1,13 +1,346 @@ --- -name: sce-plan-authoring +name: sce-change-to-plan +description: > + Turn one change request into a scoped SCE plan in one self-contained workflow +compatibility: claude +--- + +# SCE Change to Plan + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Context load phase** -> the **Plan authoring phase** to turn a change request into a scoped SCE plan" +argument-hint: "" + + +SCE CHANGE TO PLAN `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; the **Plan authoring phase** owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to the **Plan authoring phase** unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan authoring phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Run the **Context load phase** with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, run the **Context load phase** again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Run the **Plan authoring phase** with the change request and the complete `loaded` brief from the **Context load phase**. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +the **Plan authoring phase** exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by the **Plan authoring phase** in `references/output.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Run the **Plan authoring phase** with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. the **Plan authoring phase** owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of the **Plan authoring phase** against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to the **Plan authoring phase** as written. +- Do not duplicate the internal instructions of embedded phases. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when the **Plan authoring phase** returns a non-`plan_ready` status. + +## Embedded phase behavior + +## Internal phase: Context load phase + + +name: Context load phase +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one internal state: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. + + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Recording one structured context brief. + +Return a result matching: + +the internal context-load state described by this workflow + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, set internal status `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Set exactly one internal state: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching the internal context-load state described by this workflow was returned. + +## Internal phase: Plan authoring phase + + +name: Plan authoring phase description: > Internal SCE workflow skill that turns one change request into a scoped plan in `context/plans/`, sliced into atomic implementation tasks, and returns one - Markdown result: plan_ready, needs_clarification, or blocked. Use from + internal state: plan_ready, needs_clarification, or blocked. Use from /change-to-plan. Do not implement plan tasks, request implementation approval, synchronize context, or run final validation. -compatibility: claude ---- + # SCE Plan Authoring @@ -26,26 +359,26 @@ This skill owns: non-goals. - Slicing the work into atomic implementation tasks. - Writing the plan file. -- Returning one structured authoring result. +- Recording one structured authoring result. Use the document format defined in: -the **Plan template** section in this file +the **Plan template** section embedded in this file Return a result matching: -the **Result contract** section in this file +the internal authoring state described by this workflow The invoking workflow renders that result as the summary defined in: -`references/plan-summary.md` +`references/output.md` ## Input The invoking workflow provides: - One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. +- The `loaded` context brief from the **Context load phase**. The change request may name a plan, describe a change to an existing plan, or describe entirely new work. Resolving which applies is this skill's @@ -65,7 +398,7 @@ A revision of a plan authored earlier in the session also arrives as the change request, and it is usually terse: a task boundary the user disagrees with, an ordering they want changed, work they want added or dropped. Read it against the existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the +Terseness is not ambiguity. Do not set internal status `needs_clarification` for detail the plan already carries; ask only when the revision itself is genuinely undecidable. ## Workflow @@ -135,7 +468,7 @@ unresolved detail: strategy, and risk tradeoffs. - Task ordering assumptions and prerequisite sequencing. -Return `needs_clarification` with one to three targeted questions when any of +Set internal status `needs_clarification` with one to three targeted questions when any of these would materially change the plan. Write no plan file in that case. Use repository conventions for ordinary local choices. Do not block on: @@ -191,7 +524,7 @@ place a plan says how it is validated. ### 6. Author the task stack Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in the **Plan template** section in this file. +atomic slicing contract in the **Plan template** section embedded in this file. Every executable task must be completable and landable as one coherent commit. Split any task that would require multiple independent commits. Convert broad @@ -210,25 +543,25 @@ is not, the task stack is incomplete. A finished stack always leaves at least one incomplete task, so the invoking workflow can always hand off to `/next-task`. When the request resolves to a plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category +or already covered by completed tasks, set internal status `blocked` with category `no_actionable_work` instead of writing the plan. ### 7. Write the plan -Write `context/plans/{plan_name}.md` using the **Plan template** section in this file. +Write `context/plans/{plan_name}.md` using the **Plan template** section embedded in this file. When updating an existing plan, keep completed tasks and their evidence intact, and append or renumber new tasks without disturbing recorded history. ### 8. Return the result -Return exactly one structured result: +Set exactly one internal state: - `plan_ready` - `needs_clarification` - `blocked` -Return only the structured result. Do not add explanatory prose before or after +Record only the internal state. Do not add explanatory prose before or after it. ## Tone @@ -261,7 +594,7 @@ constraint, a non-goal, or a task. Do not: -- Ask the user questions directly. Return `needs_clarification` and let the +- Ask the user questions directly. Set internal status `needs_clarification` and let the invoking workflow present the questions. - Answer your own clarification questions. - Write a plan file when returning `needs_clarification` or `blocked`. @@ -271,12 +604,12 @@ Do not: repair instead of performing it. - Mark any task complete. - Request implementation confirmation. -- Invoke task execution. +- Run task execution. - Synchronize context. - Run final validation. - Author a validation, cleanup, or context-verification task. `/validate` owns that phase. -- Return `plan_ready` for a plan with no incomplete task. +- Set internal status `plan_ready` for a plan with no incomplete task. - Create a Git commit. - Author more than one plan. @@ -287,123 +620,9 @@ The skill is complete after: - One plan target was resolved, or resolution failed and was reported. - The plan file was written, or no file was written because the result is `needs_clarification` or `blocked`. -- One valid result matching the **Result contract** section in this file was returned. - -## Result contract - -# SCE Plan Authoring Result Contract - -Return exactly one Markdown document using one layout below. `Status` is the -branch value consumed by the invoking command. Use every required heading and -label exactly as written, omit optional sections that do not apply, and do -not add prose outside the selected layout. Empty required lists must contain -`- None.`. - -Report plan names without extensions and paths exactly as written so emitted -commands are runnable. Only `plan_ready` writes a plan. Do not include -implementation, synchronization, or final-validation results. - -## Status: `plan_ready` - -Use after creating or updating a plan with at least one incomplete task. - -```markdown -# Plan Authoring Result - -Status: plan_ready - -## Plan - -- Path: {plan.path} -- Name: {plan.name} -- Action: {created|updated} -- Completed tasks: {plan.completed_tasks} -- Total tasks: {plan.total_tasks} - -## Summary - -{summary} - -## Tasks - -- {task.id} — {task.title} — {todo|done} - -## Next task - -- ID: {next_task.id} -- Title: {next_task.title} - -## Assumptions - -- {assumption} - -## Open questions - -- {open_question} -``` - -`Plan`, `Summary`, `Tasks`, `Next task`, and `Assumptions` are required. -List tasks in plan order, including completed tasks. `Next task` is the first -unchecked task. Include `Open questions` only for genuine non-blocking -questions. Summary describes resulting behavior rather than repeating tasks. - -## Status: `needs_clarification` - -Use when one to three critical questions block writing the plan. - -```markdown -# Plan Authoring Result - -Status: needs_clarification - -## Plan target - -- Name: {plan_target.name} -- Action: {created|updated} -- Path: {existing plan_target.path; omit this label when no plan exists} - -## Questions - -### {question.id} - -- Category: {scope|success_criteria|constraints|dependency|domain|architecture|sequencing} -- Question: {question} -- Why blocking: {why_blocking} -``` - -`Questions` is required. `Plan target` is optional and appears only when the -request resolved to one target before authoring stopped. Never report a path -for a plan that does not exist. - -## Status: `blocked` - -Use when the target cannot be resolved or the request cannot be safely -planned. Nothing is written. - -```markdown -# Plan Authoring Result - -Status: blocked - -## Candidates - -- {candidate_path} - -## Issues - -### {issue.id} - -- Category: {ambiguous_plan_target|missing_request|conflicting_request|no_actionable_work|other} -- Problem: {problem} -- Impact: {impact} -- Decision required: {decision_required} -``` - -`Issues` is required. Include `Candidates` only for an ambiguous existing-plan -match. Use `needs_clarification` when an answer would make the request -plannable; use `no_actionable_work` when no incomplete task would result. +- One valid result matching the internal authoring state described by this workflow was returned. -## Plan template +## Internal persisted-document format: Plan template # SCE Plan Template @@ -551,7 +770,7 @@ invent one: `None.` is the expected answer for a well-specified change.} ## Completion records -`sce-task-execution` appends evidence to a task when it completes, and flips the +the **Task execution phase** appends evidence to a task when it completes, and flips the checkbox and status: ```markdown @@ -576,10 +795,10 @@ Do not author either while planning. - Add acceptance criteria for newly planned outcomes rather than rewriting criteria already satisfied. -## Control flow +## Composite control flow -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.claude/skills/sce-plan-authoring/references/plan-summary.md b/.claude/skills/sce-change-to-plan/references/output.md similarity index 69% rename from .claude/skills/sce-plan-authoring/references/plan-summary.md rename to .claude/skills/sce-change-to-plan/references/output.md index 0261808d..c2351217 100644 --- a/.claude/skills/sce-plan-authoring/references/plan-summary.md +++ b/.claude/skills/sce-change-to-plan/references/output.md @@ -1,3 +1,62 @@ +# Change-to-plan output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Missing context bootstrap gate + +```markdown +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +## Clarification gate + +```markdown +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +## Blocked + +Present each issue's problem, impact, and required decision. For ambiguity, list +candidate plan paths and explain that naming one candidate resolves it. + +## Ready continuation + +```markdown +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} {task|tasks} planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +For revisions, replace `is ready` with `revised`. + # SCE Plan Summary The user-facing summary shown after a plan is written. The invoking workflow diff --git a/.claude/skills/sce-commit/SKILL.md b/.claude/skills/sce-commit/SKILL.md new file mode 100644 index 00000000..1464878d --- /dev/null +++ b/.claude/skills/sce-commit/SKILL.md @@ -0,0 +1,334 @@ +--- +name: sce-commit +description: > + Analyze staged changes and run the regular or explicit bypass commit workflow +compatibility: claude +--- + +# SCE Commit + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Atomic commit phase** to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" + + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to the **Atomic commit phase** unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Run the **Atomic commit phase** with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; the **Atomic commit phase** owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, run the **Atomic commit phase** with `mode: regular` and the +commit context. + +the **Atomic commit phase** exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of the **Atomic commit phase**. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when the **Atomic commit phase** returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. + +## Embedded phase behavior + +## Internal phase: Atomic commit phase + + +name: Atomic commit phase +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one internal state + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. + + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Recording one terminal internal state. + +Write messages matching: + +`references/output.md` + +Return a result matching: + +the internal commit state described by this workflow + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Set internal status `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/output.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, set internal status `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return internal state + +Set exactly one internal state matching the internal commit state described by this workflow: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal internal state matching the internal commit state described by this workflow was + returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.claude/skills/sce-atomic-commit/references/commit-message-style.md b/.claude/skills/sce-commit/references/output.md similarity index 69% rename from .claude/skills/sce-atomic-commit/references/commit-message-style.md rename to .claude/skills/sce-commit/references/output.md index 7a1b5084..fb62021a 100644 --- a/.claude/skills/sce-atomic-commit/references/commit-message-style.md +++ b/.claude/skills/sce-commit/references/output.md @@ -1,6 +1,45 @@ +# Commit output layouts + +Use only the applicable layout. Values come from staged truth and internal +workflow state. + +## Regular-mode staging gate + +```markdown +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +## No staged changes + +```markdown +No staged changes. Stage changes before commit. +``` + +## Regular proposal + +For each proposal, present the complete commit message and covered files. When +more than one commit is proposed, also present the split rationale. Do not claim a +commit was created. + +## Blocked + +Present every issue's problem, impact, and required decision. Do not commit. + +## Bypass success + +```markdown +Committed {commit-hash} +``` + +## Bypass Git failure + +Present Git's failure unchanged and stop without retrying. + # Commit message style -The wording rules for every message `sce-atomic-commit` returns, in either +The wording rules for every message the **Atomic commit phase** returns, in either mode. This file is the only authority for message content and shape. Messages are carried in the result's `message` field, subject first, then one diff --git a/.claude/skills/sce-context-load/SKILL.md b/.claude/skills/sce-context-load/SKILL.md deleted file mode 100644 index 70db93f3..00000000 --- a/.claude/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one Markdown result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. -compatibility: claude ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -the **Result contract** section in this file - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching the **Result contract** section in this file was returned. - -## Result contract - -# SCE Context Load Result Contract - -Return exactly one Markdown document using one layout below. The first line -after the title is the status source consumed by the invoking command. Use -the headings and labels exactly as written, omit optional sections that do -not apply, and do not add prose outside the selected layout. - -List every file read and no file that was not read. Key facts are durable -statements, not planning or implementation recommendations. Empty required -lists must contain `- None.`. This skill never reports context edits. - -## Status: `loaded` - -Use when the context root exists and relevant context was read. - -```markdown -# Context Load Result - -Status: loaded - -## Context root - -{context_root} - -## Entry points - -### {path} - -- Read: {true|false} -- Reason: {reason; omit only when read is true and no reason is needed} - -## Domain context - -### {path} - -**Relevance:** {relevance} - -**Key facts:** - -- {key_fact} - -## Gaps - -### {area} - -{detail} - -## Drift - -### {path} - -- Context says: {context_says} -- Code says: {code_says} -- Repair needed: {repair_needed} -``` - -`Context root`, `Entry points`, `Domain context`, and `Gaps` are required. -Repeat the entry-point, domain-context, gap, and drift blocks as needed. -Include `Drift` only when recorded context contradicts code. Record gaps for -absent entry points and focus areas without durable context. - -## Status: `bootstrap_required` - -Use when the context root does not exist. Read and create nothing. - -```markdown -# Context Load Result - -Status: bootstrap_required - -## Context root - -{context_root} - -## Reason - -{reason} -``` - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-next-task/SKILL.md b/.claude/skills/sce-next-task/SKILL.md new file mode 100644 index 00000000..bfd7866d --- /dev/null +++ b/.claude/skills/sce-next-task/SKILL.md @@ -0,0 +1,939 @@ +--- +name: sce-next-task +description: > + Review, approve, implement, verify, and synchronize one SCE plan task +compatibility: claude +--- + +# SCE Next Task + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Plan review phase** -> the **Task execution phase** -> the **Task context synchronization phase** for one SCE plan task" +argument-hint: " [T0X] [approved]" + + +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan review phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Run the **Plan review phase** with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to the **Plan review phase**. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not run implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to the **Task execution phase**. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Run the **Task execution phase** with the complete `ready` result from the **Plan review phase**. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. the **Task execution phase** then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. the **Task execution phase** shows its implementation gate and waits for the user's decision. + +the **Task execution phase** exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not run context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not run context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not run context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Run the **Task context synchronization phase** with the complete `complete` result returned by the **Task execution phase**. + +Pass that result verbatim. It is the authoritative handoff, and the **Task context synchronization phase** owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report the **Task context synchronization phase** returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of embedded phases. +- Do not ask for implementation confirmation outside "Task execution phase". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve completed work and evidence when a later phase fails. + +## Embedded phase behavior + +## Internal phase: Plan review phase + + +name: Plan review phase +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. + + +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Recording one structured readiness result. + +Return a result matching: + +the internal readiness state described by this workflow + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Set internal status `plan_complete` when no incomplete tasks remain. + +Set internal status `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Set internal status `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Set exactly one internal state: + +- `ready` +- `blocked` +- `plan_complete` + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Run task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching the internal readiness state described by this workflow was + returned. + +## Internal phase: Task execution phase + + +name: Task execution phase +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one internal state: declined, + blocked, incomplete, or complete. Accepts a ready result from + Plan review phase. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. + + +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Recording one terminal internal state. + +Use the gate defined in: + +`references/output.md` + +Return a final result matching: + +the internal execution state described by this workflow + +## Input + +The invoking workflow provides: + +- The complete `ready` result from the **Plan review phase**. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, set internal status `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/output.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return internal state, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and set internal status `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise set internal status `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, set internal status `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Set internal status `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Set internal status `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Set internal status `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Set internal status `declined` when the user rejected implementation. + +Set internal status `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by the internal execution state described by this workflow. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return internal state + +After the skill reaches a terminal state, set exactly one internal state +matching the internal execution state described by this workflow. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal internal state matching the internal execution state described by this workflow + was returned. + +## Internal phase: Task context synchronization phase + + +name: Task context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from Task execution phase, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Run only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. + + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by the **Task execution phase**. + +The execution result must have: + +```text +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be run for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.claude/skills/sce-task-context-sync/references/sync-report.md b/.claude/skills/sce-next-task/references/output.md similarity index 50% rename from .claude/skills/sce-task-context-sync/references/sync-report.md rename to .claude/skills/sce-next-task/references/output.md index 581177da..791f8f21 100644 --- a/.claude/skills/sce-task-context-sync/references/sync-report.md +++ b/.claude/skills/sce-next-task/references/output.md @@ -1,3 +1,144 @@ +# Next-task output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Review blocked + +Present the selected task, then each issue's problem, impact, and required +decision. If plan resolution is ambiguous, list candidate paths and +`/next-task {candidate-path}`. State whether another task remains executable. + +## Plan already complete + +```markdown +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +## Declined + +```markdown +You have declined to proceed with this task +``` + +## Execution blocked or incomplete + +For `blocked`, present the blocker, work completed before it, and the required +decision or action. For `incomplete`, present completed work, verification +evidence, remaining work, and the reason it remains incomplete. + +## Context synchronization blocked + +State that task `{completed-task-id}` was implemented, verified, and recorded; +report the contradiction or synchronization failure, preserved edits, required +action, and retry condition. State that durable context is out of date and must +be synchronized before continuing. + +## More tasks remain + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +## All tasks complete + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +# Implementation gate + +Always show this gate at the start of the **Task execution phase**, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. + # Context Sync Report Return only one completed Markdown report using the applicable variant below. diff --git a/.claude/skills/sce-plan-context-sync/SKILL.md b/.claude/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index ca14c2ee..00000000 --- a/.claude/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,317 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. -compatibility: claude ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-plan-context-sync/references/sync-report.md b/.claude/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/.claude/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/.claude/skills/sce-plan-review/SKILL.md b/.claude/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 0f29e07b..00000000 --- a/.claude/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,267 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. -compatibility: claude ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -the **Result contract** section in this file - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching the **Result contract** section in this file was - returned. - -## Result contract - -# SCE Plan Review Result Contract - -Return exactly one Markdown document using one layout below. `Status` is the -branch value consumed by `/next-task`. Use every required heading and label -exactly as written, omit optional sections that do not apply, and do not add -prose outside the selected layout. Empty required lists must contain -`- None.`. - -Report task counts as they stand and the plan path exactly as resolved. Do -not request implementation confirmation or include implementation, -synchronization, or final-validation results. - -## Status: `ready` - -```markdown -# Plan Review Result - -Status: ready - -## Plan - -- Path: {plan.path} -- Name: {plan.name} -- Completed tasks: {plan.completed_tasks} -- Total tasks: {plan.total_tasks} - -## Task - -- ID: {task.id} -- Title: {task.title} - -## Relevant files - -- {relevant_file} - -## Relevant context - -- {relevant_context} - -## Assumptions - -- {assumption} -``` - -Every section is required. `Name` is the plan basename without its extension. -Repeat list items as needed. - -This layout is a compact handoff, not a task presentation. It carries only -what review discovered and the next phase cannot recover on its own. The -task's goal, scope boundaries, done checks, dependencies, and verification -stay in the plan file, where `sce-task-execution` reads them. Do not restate -them here. - -## Status: `blocked` - -```markdown -# Plan Review Result - -Status: blocked - -## Plan - -- Path: {plan.path} -- Completed tasks: {plan.completed_tasks} -- Total tasks: {plan.total_tasks} - -## Task - -- ID: {task.id} -- Title: {task.title} - -## Candidates - -- {candidate_path} - -## Issues - -### {issue.id} - -- Category: {missing_decision|ambiguity|missing_acceptance_criteria|dependency|scope} -- Problem: {problem} -- Impact: {impact} -- Decision required: {decision_required} - -## Executable tasks remaining - -{true|false} -``` - -`Issues` is required. Include `Plan` whenever exactly one plan resolved, -`Task` when one was selected, and `Candidates` only when plan resolution -failed or was ambiguous. Include `Executable tasks remaining` when a plan -resolved. - -## Status: `plan_complete` - -```markdown -# Plan Review Result - -Status: plan_complete - -## Plan - -- Path: {plan.path} -- Completed tasks: {plan.completed_tasks} -- Total tasks: {plan.total_tasks} -``` - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-task-context-sync/SKILL.md b/.claude/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index fa3eafa6..00000000 --- a/.claude/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. -compatibility: claude ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-task-execution/SKILL.md b/.claude/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 3d484c76..00000000 --- a/.claude/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,432 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one Markdown result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. -compatibility: claude ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal Markdown result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -the **Result contract** section in this file - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- Relevant files and context. -- Review assumptions. - -The readiness result is a compact handoff carrying only what review -discovered. Read the task's goal, scope boundaries, done checks, -dependencies, and verification from that task's entry in the plan file. -The handoff does not repeat them, and their absence from it is not a -handoff problem. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task entry in the plan still matches the reviewed task ID and title. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. Read that task's entry in the plan file for -the gate's goal, scope, done-check, and verification fields. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return Markdown, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with the verification declared by that task's entry in the plan. Add -nearby or directly relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by the **Result contract** section in this file. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return Markdown - -After the skill reaches a terminal state, return exactly one Markdown document -matching the **Result contract** section in this file. - -Return only the Markdown document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal Markdown result matching the **Result contract** section in this file - was returned. - -## Result contract - -# SCE Task Execution Result Contract - -Return exactly one Markdown document using one layout below after the -implementation gate reaches a terminal state. `Status` is the branch value -consumed by `/next-task`. Use every required heading and label exactly as -written, omit optional sections that do not apply, and do not add prose -outside the selected layout. Empty required lists must contain `- None.`. - -Report task counts as they stand. Never serialize the implementation gate, -select the next task, or include synchronization or final-validation results. - -## Shared Plan and Task layout - -Every status includes these sections: - -```markdown -## Plan - -- Path: {plan.path} -- Completed tasks: {plan.completed_tasks} -- Total tasks: {plan.total_tasks} - -## Task - -- ID: {task.id} -- Title: {task.title} -``` - -## Status: `declined` - -```markdown -# Task Execution Result - -Status: declined - -{Shared Plan and Task layout} -``` - -Use only when the user declines and no implementation changes were made. - -## Status: `blocked` - -```markdown -# Task Execution Result - -Status: blocked - -{Shared Plan and Task layout} - -## Blocker - -- Category: {stale_review|scope|dependency|architecture|security|data|destructive_operation|other} -- Problem: {problem} -- Impact: {impact} -- Decision required: {decision_required} - -## Changes - -### Files changed - -- {file} - -## Verification - -### {command} - -- Outcome: {passed|failed|not_run} -- Summary: {summary} - -## Work preserved - -{true|false} -``` - -`Blocker` and `Work preserved` are required. `Changes` and `Verification` are -optional and appear only when work or checks occurred. - -## Status: `incomplete` - -```markdown -# Task Execution Result - -Status: incomplete - -{Shared Plan and Task layout} - -## Changes - -### Files changed - -- {file} - -### Summary - -- {change_summary} - -## Verification - -### {command} - -- Outcome: {passed|failed|not_run} -- Summary: {summary} - -## Satisfied done checks - -- {check} - -## Unsatisfied done checks - -- {check} - -## Remaining work - -- {remaining_work} - -## Reason - -{reason} -``` - -`Changes`, `Verification`, and `Remaining work` are required. The done-check -sections and `Reason` are optional. - -## Status: `complete` - -```markdown -# Task Execution Result - -Status: complete - -{Shared Plan and Task layout} - -## Changes - -### Files changed - -- {file} - -### Summary - -- {change_summary} - -## Verification - -### {command} - -- Outcome: passed -- Summary: {summary} - -## Done checks - -### {check} - -{evidence} - -## Context impact - -- Classification: {none|local|domain|root} -- Affected areas: {comma-separated areas, or none} -- Reason: {reason} -``` - -Every shown section is required. Repeat verification and done-check blocks as -needed. This layout is the authoritative handoff to context synchronization. - -Keep it at exactly these sections. `sce-task-context-sync` validates the -changed files, implementation summary, verification evidence, done-check -evidence, and context impact, and blocks when any is missing, so none of them -may be dropped. `Status: complete` already asserts the task was marked -complete in the plan with evidence recorded; do not restate that as a section. - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-task-execution/references/implementation-gate.md b/.claude/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index 76f1446e..00000000 --- a/.claude/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,73 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a Markdown result. This -file is the only authority for the gate's content and order. - -Every `{task.*}` field below comes from that task's entry in the plan file. -The readiness result supplies only the plan and task identity, relevant files -and context, and review assumptions. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit Markdown while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/.claude/skills/sce-validate/SKILL.md b/.claude/skills/sce-validate/SKILL.md new file mode 100644 index 00000000..ab530f63 --- /dev/null +++ b/.claude/skills/sce-validate/SKILL.md @@ -0,0 +1,767 @@ +--- +name: sce-validate +description: > + Validate one completed SCE plan and synchronize its durable context +compatibility: claude +--- + +# SCE Validate + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Validation phase** -> the **Plan context synchronization phase** to finish an SCE plan" +argument-hint: "" + + +SCE VALIDATE `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to the **Validation phase** unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by the **Validation phase** in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Run the **Validation phase** with the plan name or path. + +the **Validation phase** exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not run context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not run context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +the **Plan context synchronization phase**. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Run the **Plan context synchronization phase** only with a `Status: validated` Markdown result +from the **Validation phase**. + +Do not run the **Plan context synchronization phase** for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +the **Plan context synchronization phase** owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +the **Plan context synchronization phase** returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of embedded phases. +- Do not run final validation when implementation tasks remain; the **Validation phase** + returns `blocked`, and this workflow stops. +- Run the **Plan context synchronization phase** only when the **Validation phase** returned + `Status: validated`. Do not run it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. + +## Embedded phase behavior + +## Internal phase: Validation phase + + +name: Validation phase +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one internal state (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. + + +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Recording one Markdown validation result. + +Return a result matching: + +`references/output.md` + +Write plan-file evidence matching: + +the **Plan-file validation report** section embedded in this file + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs the **Plan context synchronization phase** only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Set internal status `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Set internal status `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + the **Plan-file validation report** section embedded in this file. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so the **Plan context synchronization phase** can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the internal state + +Set exactly one internal state: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/output.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. Do not return internal state. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a internal state. +- Run plan context synchronization. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid internal state matching `references/output.md` was + returned. + +## Internal phase: Plan context synchronization phase + + +name: Plan context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful Status: validated + internal state from Validation phase, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Run only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. + + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete internal state returned by the **Validation phase**. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be run for `failed` or `blocked` validation results. +Those are not success states. Same rule as the **Task context synchronization phase**: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated internal state: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + +## Internal persisted-document format: Plan-file validation report + +# Plan-file Validation Report + +The Markdown section the **Validation phase** appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +the **Validation phase** writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.claude/skills/sce-validate/references/output.md b/.claude/skills/sce-validate/references/output.md new file mode 100644 index 00000000..3e4c5519 --- /dev/null +++ b/.claude/skills/sce-validate/references/output.md @@ -0,0 +1,429 @@ +# Validate output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Validation blocked + +```markdown +# Validation blocked + +**Status:** blocked +**Plan:** `{plan-path when resolved}` +**Name:** `{plan-name when resolved}` + +## Issues + +- **{issue-id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision-or-action} + +## Incomplete tasks + +- `{task-id}` — {title} + +## Candidates + +- `{candidate-plan-path}` + +## Next step + +{one continuation matching the blocker} +``` + +Omit inapplicable optional sections. + +## Validation failed handoff + +```markdown +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan-path}` +**Name:** `{plan-name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan-path}` + +## Goal for the next session + +{repair goal} + +## What failed + +- `{check-or-AC}`: {problem} + - Evidence: {evidence} + - Required action: {action} + +## Acceptance criteria + +- [{x-or-space}] {criterion}: {evidence} + +## Commands run + +- `{command}` -> {passed|failed|not_run} — {summary} + +## Constraints + +{canonical validation constraints} + +## Residual risks + +- {risk-or-none} + +## Recommended work + +1. {repair} +2. Rerun final validation after repairs: + +`/validate {plan-path}` +``` + +## Context synchronization blocked + +State that validation passed and its report is recorded, then report the context +failure, preserved edits, required action, and retry condition. State that durable +context remains out of date and synchronization must finish before closure. + +## Completion + +```markdown +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not run for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs the **Plan context synchronization phase** only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. + +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not run for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.claude/skills/sce-validation/SKILL.md b/.claude/skills/sce-validation/SKILL.md deleted file mode 100644 index 1898cb10..00000000 --- a/.claude/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,387 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. -compatibility: claude ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -the **Result contract** section in this file - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - the **Result contract** section in this file, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching the **Result contract** section in this file was - returned. - -## Result contract - -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. - -## Control flow - -This skill is one phase of a workflow, not a turn. Return the result to the -invoking command and let it continue in the same turn. Do not present the -result to the user as workflow output, and do not end your turn after -returning it — the invoking command decides what the user sees and when the -workflow stops. diff --git a/.claude/skills/sce-validation/references/validation-report.md b/.claude/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/.claude/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/.opencode/agent/Shared Context Code.md b/.opencode/agent/Shared Context Code.md index c88395a2..45e2debd 100644 --- a/.opencode/agent/Shared Context Code.md +++ b/.opencode/agent/Shared Context Code.md @@ -28,6 +28,7 @@ permission: "sce-task-context-sync": allow "sce-validation": allow "sce-plan-context-sync": allow + "sce-atomic-commit": allow --- Route implementation work through `/next-task` and final plan validation through `/validate`. diff --git a/config/pkl/README.md b/config/pkl/README.md index 60d900a3..095f7cf7 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -20,13 +20,13 @@ Apply target-specific rendering and supported metadata under `config/pkl/rendere | Target | Workflow Markdown | Retained non-Markdown | | --- | --- | --- | | OpenCode | Four commands, eight self-contained skill packages, two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | -| Claude | Four commands and eight self-contained skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | +| Claude | Four thin commands and four self-contained workflow skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | | Pi | Four prompts and eight self-contained skill packages; no agent-role prompts | `extensions/sce/index.ts` | | SCE config | None | `config/schema/sce-config.schema.json` | -Each skill package includes its package-local `SKILL.md` and any nested `references/` documents. Generated skill trees must remain self-contained; a generated skill must not depend on a sibling skill package. +Pi and OpenCode skill packages include package-local `SKILL.md` files and their nested `references/` documents. Their generated trees remain self-contained; no skill depends on a sibling package. -Pi and OpenCode consume the canonical multi-file packages, including YAML phase-result contracts under `references/`. Claude receives the same skills with two Claude-only transforms: Markdown phase-result contracts for `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`, and a reduced package shape where machine contracts and plan templates are folded into `SKILL.md` so each Claude package keeps at most one human-presentation file under `references/` (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, or `commit-message-style.md`). Validation and context-synchronization reports remain Markdown for every target; on Claude, `validation-result` lives in `SKILL.md` while `validation-report` / `sync-report` stay as the single human-facing reference when present. +Pi and OpenCode consume the canonical eight multi-file phase packages, including YAML phase-result contracts under `references/`. Claude instead composes each canonical workflow into one target-specific package: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each Claude command invokes exactly its corresponding workflow skill, and each package contains exactly `SKILL.md` plus `references/output.md`. The entrypoint owns the complete phase sequence, internal statuses, waits and same-session resume behavior; `output.md` is the sole package reference and defines the workflow's human-visible gates and terminal Markdown layouts. Canonical phase contracts remain unchanged for Pi and OpenCode and are not emitted as Claude inter-skill handoffs. The automated OpenCode profile, the generated `/handover` command, legacy bootstrap/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. @@ -71,7 +71,7 @@ nix run .#pkl-check-generated The check: - rejects committed `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, and `cli/assets/generated` outputs; -- evaluates `metadata-coverage-check.pkl` for exact per-target four-command, eight-skill-package, and nested-reference inventories, including Claude's reduced single human-presentation reference inventory (machine contracts inlined in `SKILL.md`), plus the two-agent OpenCode inventory; +- evaluates `metadata-coverage-check.pkl` for exact inventories: four commands and eight phase-skill packages for OpenCode/Pi, four one-to-one workflow skill packages with exactly two files each for Claude, and two OpenCode agents; - generates twice into temporary directories and compares sorted SHA-256 inventories; - requires all generated target roots and the SCE config schema while rejecting removed surfaces such as `config/automated/.opencode` and `config/.claude/agents`; - prints the stable inventory count and digest without preserving generated files. diff --git a/config/pkl/renderers/claude-content.pkl b/config/pkl/renderers/claude-content.pkl index f85ea5b9..a5fce0ce 100644 --- a/config/pkl/renderers/claude-content.pkl +++ b/config/pkl/renderers/claude-content.pkl @@ -1,8 +1,3 @@ -import "../base/workflow-change-to-plan.pkl" as changeToPlan -import "../base/workflow-next-task.pkl" as nextTask -import "../base/workflow-validate.pkl" as validate -import "../base/workflow-commit.pkl" as commit -import "../base/workflow-content.pkl" as model import "common.pkl" as common import "claude-metadata.pkl" as metadata import "claude-workflow-results.pkl" as workflowResults @@ -13,146 +8,6 @@ local claudeSceHookScriptPath = "$CLAUDE_PROJECT_DIR/.claude/hooks/run-sce-or-sh local function sceHookCommand(arguments: String): String = "bash \\\"\(claudeSceHookScriptPath)\\\" \(arguments)" -local workflows = new Listing { - changeToPlan.workflow - nextTask.workflow - validate.workflow - commit.workflow -} - -/// Claude reads a phase result as a finished deliverable and ends the turn -/// unless the continuation branch is at least as vivid as the stop branch. The -/// canonical bodies specify stopping in detail and continuing in four words, so -/// Claude-only command bodies name the next skill and rule out ending the turn. -local turnBoundaryRule = "Run every step in one turn. Stop only where a step says to wait for the user." - -local withTurnBoundaryRule = (text: String) -> - text.replaceFirst("## Workflow\n\n", "## Workflow\n\n\(turnBoundaryRule)\n\n") - -local changeToPlanContinuations = (text: String) -> - text - .replaceFirst( - "`loaded` -> Continue to the next step.", - """ - `loaded` -> The brief is internal workflow input, not workflow output. Do not print it, and do not end your turn. Invoke `sce-plan-authoring` in the same turn. - - This step ends the turn only on `bootstrap_required`. - """ - ) - .replaceFirst( - "`plan_ready` -> Continue to the next step.", - """ - `plan_ready` -> An authoring result is never presented to the user as workflow output. Do not print it, and do not end your turn. Continue to the next step in the same turn. - - This step ends the turn only on `needs_clarification` or `blocked`. - """ - ) - -local nextTaskContinuations = (text: String) -> - text - .replaceFirst( - "`ready` -> Pass the complete readiness result to `sce-task-execution`.", - """ - `ready` -> A readiness result is never presented to the user. Do not print it, and do not end your turn. Pass the complete readiness result to `sce-task-execution` in the same turn. - - The readiness result is a compact handoff: plan and task identity, relevant files, relevant context, and review assumptions. It deliberately omits the task's goal, scope, done checks, dependencies, and verification, which `sce-task-execution` reads from the plan and presents in its implementation gate. Do not reconstruct the omitted fields, and do not treat their absence as a stale handoff. - - This step ends the turn only on `blocked` or `plan_complete`. - """ - ) - .replaceFirst( - "`complete` -> continue to the next step.", - """ - `complete` -> Do not print the raw result, and do not end your turn. Invoke `sce-task-context-sync` in the same turn. - - This result stays full-size: `sce-task-context-sync` validates the changed files, implementation summary, verification evidence, done-check evidence, and context impact, and blocks when any is missing. Pass it through untouched rather than trimming it to match the compact readiness handoff. - - This step ends the turn only on `declined`, `blocked`, or `incomplete`. - """ - ) - .replaceFirst( - "`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step.", - """ - `synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned, then continue to the next step in the same turn. Do not end your turn before the continuation block. - - This step ends the turn only on `blocked`. - """ - ) - -local validateContinuations = (text: String) -> - text - .replaceFirst( - """ - `validated` -> Pass the complete validated Markdown result to - `sce-plan-context-sync`. - """, - """ - `validated` -> A validated result is never presented to the user as workflow - output. Do not print it, and do not end your turn. Pass the complete validated - Markdown result to `sce-plan-context-sync` in the same turn. - - This step ends the turn only on `blocked` or `failed`. - """ - ) - .replaceFirst( - """ - `synced` | `no_context_change` -> Print out the report - `sce-plan-context-sync` returned. Continue to the next step. - """, - """ - `synced` | `no_context_change` -> Print out the report - `sce-plan-context-sync` returned, then continue to the next step in the same - turn. Do not end your turn before the completion block. - - This step ends the turn only on `blocked`. - """ - ) - -local nextTaskHandoffProse = (text: String) -> - text.replaceFirst( - "`sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it.", - "`sce-task-context-sync` owns reading the plan, task, changed files, implementation summary, verification evidence, done-check evidence, and reported context impact out of it." - ) - -local commitContinuations = (text: String) -> - text.replaceFirst( - "`bypass_message` -> Continue to the next step.", - """ - `bypass_message` -> The message is internal workflow input, not workflow output. Do not print it as the deliverable, and do not end your turn. The commit is this path's deliverable, so continue to the next step in the same turn. - - This step ends the turn only on `blocked` or a contract violation. - """ - ) - -local renderCommandBody = (slug: String, text: String) -> - if (slug == "change-to-plan") changeToPlanContinuations.apply(withTurnBoundaryRule.apply(text)) - else if (slug == "next-task") nextTaskHandoffProse.apply(nextTaskContinuations.apply(withTurnBoundaryRule.apply(text))) - else if (slug == "validate") validateContinuations.apply(withTurnBoundaryRule.apply(text)) - else if (slug == "commit") commitContinuations.apply(withTurnBoundaryRule.apply(text)) - else text - -local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { - path = command.document.path - text = renderCommandBody.apply( - command.slug, - command.document.text.replaceFirst( - "\n---\n", - "\nallowed-tools: \(metadata.commandAllowedTools[command.slug])\n---\n" - ) - ) -} - -local withClaudeEntrypointMetadata = (document: model.WorkflowDocument) -> - if (document.path == "SKILL.md") - new model.WorkflowDocument { - path = document.path - text = document.text.replaceFirst( - "\n---\n", - "\ncompatibility: \(metadata.skillCompatibility)\n---\n" - ) - } - else document - settings = new common.RenderedTextFile { slug = "settings" rendered = """ @@ -229,23 +84,18 @@ exec "$@" """ } +/// Claude commands are intentionally thin. Each routes to exactly one composite +/// workflow skill, which owns all phases, waits, and final response rendering. commands { - for (workflow in workflows) { - [workflow.command.slug] = renderCommand.apply(workflow.command) + for (slug, workflow in workflowResults.workflows) { + [slug] = workflowResults.renderCommand.apply(workflow, metadata.commandAllowedTools[slug]) } } -/// Flatten package-relative document paths while retaining each skill's -/// self-contained directory layout and adding only Claude-supported metadata -/// to the package entrypoint. Machine contracts are folded into SKILL.md by -/// the Claude workflow-results renderer so each package keeps at most one -/// human-presentation `references/` file. +/// Claude has four workflow packages, each with exactly SKILL.md and one +/// references/output.md presentation contract. skillDocuments { - for (workflow in workflows) { - for (skillSlug, skillPackage in workflow.skills) { - for (documentPath, document in workflowResults.renderSkillPackage.apply(skillSlug, skillPackage)) { - ["\(skillSlug)/\(documentPath)"] = withClaudeEntrypointMetadata.apply(document) - } - } + for (path, document in workflowResults.skillDocuments) { + [path] = document } } diff --git a/config/pkl/renderers/claude-metadata.pkl b/config/pkl/renderers/claude-metadata.pkl index 52684fc2..755282f9 100644 --- a/config/pkl/renderers/claude-metadata.pkl +++ b/config/pkl/renderers/claude-metadata.pkl @@ -5,4 +5,11 @@ commandAllowedTools = new Mapping { ["commit"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" } -skillCompatibility = "claude" +/// One command routes to one workflow-level package. Phase-skill names are not +/// part of Claude's generated inventory. +workflowSkillSlugByCommand = new Mapping { + ["change-to-plan"] = "sce-change-to-plan" + ["next-task"] = "sce-next-task" + ["validate"] = "sce-validate" + ["commit"] = "sce-commit" +} diff --git a/config/pkl/renderers/claude-workflow-results.pkl b/config/pkl/renderers/claude-workflow-results.pkl index b77eabc7..de747669 100644 --- a/config/pkl/renderers/claude-workflow-results.pkl +++ b/config/pkl/renderers/claude-workflow-results.pkl @@ -1,811 +1,521 @@ +import "../base/workflow-change-to-plan.pkl" as changeToPlan +import "../base/workflow-next-task.pkl" as nextTask +import "../base/workflow-validate.pkl" as validate +import "../base/workflow-commit.pkl" as commit import "../base/workflow-content.pkl" as model - -/// Claude cannot reliably transport YAML-only phase handoffs between workflow -/// skills and commands. Keep the canonical Pi/OpenCode documents unchanged and -/// replace only Claude's five structured phase-result contracts with Markdown. -/// -/// Claude also collapses multi-file skill `references/` so each package emits at -/// most one human-facing presentation layout. Machine contracts and plan -/// templates are folded into that package's `SKILL.md`. - -local markdownContractPathBySkill = new Mapping { - ["sce-context-load"] = "references/context-brief.md" - ["sce-plan-authoring"] = "references/authoring-contract.md" - ["sce-plan-review"] = "references/readiness-contract.md" - ["sce-task-execution"] = "references/execution-contract.md" - ["sce-atomic-commit"] = "references/commit-contract.md" +import "claude-metadata.pkl" as metadata + +/// Claude executes a skill as the unit of durable control flow. Compose the +/// canonical phase packages into one workflow package instead of asking a +/// command to transport phase results between sibling skills. +class ClaudeWorkflow { + slug: String + skillSlug: String + title: String + description: String + argumentHint: String + command: model.WorkflowDocument + phaseDocuments: Listing + internalDocuments: Listing + outputText: String } -local markdownContractBySkill = new Mapping { - ["sce-context-load"] = CONTEXT_BRIEF - ["sce-plan-authoring"] = AUTHORING_CONTRACT - ["sce-plan-review"] = READINESS_CONTRACT - ["sce-task-execution"] = EXECUTION_CONTRACT - ["sce-atomic-commit"] = COMMIT_CONTRACT +local stripFrontmatterMarkers = (text: String) -> + text.replaceFirst("---", "").replaceFirst("---", "") + +local phaseNameBySlug = new Mapping { + ["sce-context-load"] = "Context load phase" + ["sce-plan-authoring"] = "Plan authoring phase" + ["sce-plan-review"] = "Plan review phase" + ["sce-task-execution"] = "Task execution phase" + ["sce-task-context-sync"] = "Task context synchronization phase" + ["sce-validation"] = "Validation phase" + ["sce-plan-context-sync"] = "Plan context synchronization phase" + ["sce-atomic-commit"] = "Atomic commit phase" } -/// Presentation layouts shown to a human reviewer. All other `references/` -/// documents are machine contracts and fold into Claude's `SKILL.md`. -local humanPresentationPaths = Set( - "references/plan-summary.md", - "references/implementation-gate.md", - "references/validation-report.md", - "references/sync-report.md", - "references/commit-message-style.md" -) - -local planTemplatePath = "references/plan-template.md" -local validationResultPath = "references/validation-result.md" - -local rewriteMachineReferencePaths = (text: String) -> +/// Remove sibling-package routing language while preserving canonical phase +/// semantics. Status values become internal workflow state inside the composite +/// skill; only layouts in references/output.md are rendered to the user. +local internalize = (text: String) -> text - .replaceAll("`references/context-brief.md`", "the **Result contract** section in this file") - .replaceAll("`references/authoring-contract.md`", "the **Result contract** section in this file") - .replaceAll("`references/readiness-contract.md`", "the **Result contract** section in this file") - .replaceAll("`references/execution-contract.md`", "the **Result contract** section in this file") - .replaceAll("`references/commit-contract.md`", "the **Result contract** section in this file") - .replaceAll("`references/validation-result.md`", "the **Result contract** section in this file") - .replaceAll("`references/plan-template.md`", "the **Plan template** section in this file") - -/// Per-document Claude transform: Markdown phase contracts and YAML→Markdown -/// wording for the five structured skills. Package-level folding happens in -/// `renderSkillPackage`. -renderSkillDocument = (skillSlug: String, document: model.WorkflowDocument) -> - if (document.path == "SKILL.md" && markdownContractPathBySkill.containsKey(skillSlug)) - new model.WorkflowDocument { - path = document.path - text = document.text - .replaceAll("YAML", "Markdown") - .replaceAll(".yaml", ".md") - } - else if (markdownContractPathBySkill.containsKey(skillSlug) && document.path.endsWith(".yaml")) - new model.WorkflowDocument { - path = markdownContractPathBySkill[skillSlug] - text = markdownContractBySkill[skillSlug] - } - else if (markdownContractPathBySkill.containsKey(skillSlug)) - new model.WorkflowDocument { - path = document.path - text = document.text - .replaceAll("YAML", "Markdown") - .replaceAll(".yaml", ".md") - } - else document - -/// Claude's readiness handoff carries only what plan review discovered, because -/// a skill "returning" a result and printing it to the user are the same act. -/// Point `sce-task-execution` at the plan file for the fields the compact -/// handoff no longer repeats. -local rewriteTaskExecutionSourcing = (path: String, text: String) -> - if (path == "SKILL.md") - text - .replaceFirst( - """ - - One resolved plan. - - Exactly one incomplete task. - - The task goal and scope boundaries. - - Done checks. - - Verification expectations. - - Relevant files and context. - - Review assumptions. - """, - """ - - One resolved plan. - - Exactly one incomplete task. - - Relevant files and context. - - Review assumptions. - - The readiness result is a compact handoff carrying only what review - discovered. Read the task's goal, scope boundaries, done checks, - dependencies, and verification from that task's entry in the plan file. - The handoff does not repeat them, and their absence from it is not a - handoff problem. - """ - ) - .replaceFirst( - "- The task has not materially changed since review.", - "- The task entry in the plan still matches the reviewed task ID and title." - ) - .replaceFirst( - """ - At the start of the skill, before any file modification, present the task using - `references/implementation-gate.md`. - """, - """ - At the start of the skill, before any file modification, present the task using - `references/implementation-gate.md`. Read that task's entry in the plan file for - the gate's goal, scope, done-check, and verification fields. - """ - ) - .replaceFirst( - """ - Start with verification supplied by the readiness result. Add nearby or directly - relevant checks only when needed. - """, - """ - Start with the verification declared by that task's entry in the plan. Add - nearby or directly relevant checks only when needed. - """ - ) - else if (path == "references/implementation-gate.md") - text.replaceFirst( - "file is the only authority for the gate's content and order.", - """ - file is the only authority for the gate's content and order. - - Every `{task.*}` field below comes from that task's entry in the plan file. - The readiness result supplies only the plan and task identity, relevant files - and context, and review assumptions. - """ - ) - else text - -local rewriteHandoffSourcing = (skillSlug: String, document: model.WorkflowDocument) -> - if (skillSlug == "sce-task-execution") - new model.WorkflowDocument { - path = document.path - text = rewriteTaskExecutionSourcing.apply(document.path, document.text) - } - else document - -local renderPackageDocuments = (skillSlug: String, skillPackage: model.SkillPackage) -> new Mapping { - for (_, document in skillPackage.documents) { - [renderSkillDocument.apply(skillSlug, document).path] = - rewriteHandoffSourcing.apply(skillSlug, renderSkillDocument.apply(skillSlug, document)) - } + .replaceAll("`sce-context-load`", "the **Context load phase**") + .replaceAll("`sce-plan-authoring`", "the **Plan authoring phase**") + .replaceAll("`sce-plan-review`", "the **Plan review phase**") + .replaceAll("`sce-task-execution`", "the **Task execution phase**") + .replaceAll("`sce-task-context-sync`", "the **Task context synchronization phase**") + .replaceAll("`sce-validation`", "the **Validation phase**") + .replaceAll("`sce-plan-context-sync`", "the **Plan context synchronization phase**") + .replaceAll("`sce-atomic-commit`", "the **Atomic commit phase**") + .replaceAll("sce-context-load", "Context load phase") + .replaceAll("sce-plan-authoring", "Plan authoring phase") + .replaceAll("sce-plan-review", "Plan review phase") + .replaceAll("sce-task-execution", "Task execution phase") + .replaceAll("sce-task-context-sync", "Task context synchronization phase") + .replaceAll("sce-validation", "Validation phase") + .replaceAll("sce-plan-context-sync", "Plan context synchronization phase") + .replaceAll("sce-atomic-commit", "Atomic commit phase") + .replaceAll("`references/context-brief.yaml`", "the internal context-load state described by this workflow") + .replaceAll("`references/authoring-contract.yaml`", "the internal authoring state described by this workflow") + .replaceAll("`references/readiness-contract.yaml`", "the internal readiness state described by this workflow") + .replaceAll("`references/execution-contract.yaml`", "the internal execution state described by this workflow") + .replaceAll("`references/commit-contract.yaml`", "the internal commit state described by this workflow") + .replaceAll("`references/implementation-gate.md`", "`references/output.md`") + .replaceAll("`references/plan-summary.md`", "`references/output.md`") + .replaceAll("`references/validation-result.md`", "`references/output.md`") + .replaceAll("`references/sync-report.md`", "`references/output.md`") + .replaceAll("`references/commit-message-style.md`", "`references/output.md`") + .replaceAll("Invoke the **", "Run the **") + .replaceAll("invoke the **", "run the **") + .replaceAll("invoked skills", "embedded phases") + .replaceAll("invoked skill", "embedded phase") + .replaceAll("Invoke task execution", "Run task execution") + .replaceAll("Invoke plan context sync", "Run plan context synchronization") + .replaceAll("invoke implementation", "run implementation") + .replaceAll("invoke context synchronization", "run context synchronization") + .replaceAll("invoke it", "run it") + .replaceAll("Invoke only", "Run only") + .replaceAll("invoked for", "run for") + +local internalizePhase = (text: String) -> + internalize.apply(text) + .replaceAll("`references/plan-template.md`", "the **Plan template** section embedded in this file") + .replaceAll("`references/validation-report.md`", "the **Plan-file validation report** section embedded in this file") + .replaceAll("YAML result", "internal state") + .replaceAll("YAML document", "internal state") + .replaceAll("```yaml", "```text") + .replaceAll("YAML", "internal state") + .replaceAll("structured result", "internal state") + .replaceAll("terminal Markdown result", "terminal internal state") + .replaceAll("Markdown result", "internal state") + .replaceAll("Return exactly one", "Set exactly one") + .replaceAll("return exactly one", "set exactly one") + .replaceAll("Return only the", "Record only the") + .replaceAll("return only the", "record only the") + .replaceAll("Return `", "Set internal status `") + .replaceAll("return `", "set internal status `") + .replaceAll("Returning one", "Recording one") + .replaceAll("returning one", "recording one") + +local renderPhase = (slug: String, document: model.WorkflowDocument) -> + "## Internal phase: \(phaseNameBySlug[slug])\n\n" + internalizePhase.apply(stripFrontmatterMarkers.apply(document.text)) + +local renderInternalDocument = (title: String, document: model.WorkflowDocument) -> + "## Internal persisted-document format: \(title)\n\n" + internalize.apply(document.text) + +local renderSkill = (workflow: ClaudeWorkflow) -> new model.WorkflowDocument { + path = "SKILL.md" + text = """ +--- +name: \(workflow.skillSlug) +description: > + \(workflow.description) +compatibility: claude +--- + +# \(workflow.title) + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + +\(internalize.apply(stripFrontmatterMarkers.apply(workflow.command.text))) + +## Embedded phase behavior + +\(new Listing { for (document in workflow.phaseDocuments) { renderPhase.apply(document.path, document) } }.join("\n\n")) + +\(new Listing { for (document in workflow.internalDocuments) { renderInternalDocument.apply(document.path, document) } }.join("\n\n")) + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. +""" } -local foldResultContract = (skillSlug: String, skillText: String, renderedByPath: Mapping) -> - if (markdownContractBySkill.containsKey(skillSlug)) - skillText + "\n\n## Result contract\n\n" + markdownContractBySkill[skillSlug] - else if (renderedByPath.containsKey(validationResultPath)) - skillText + "\n\n## Result contract\n\n" + renderedByPath[validationResultPath].text - else skillText - -local foldPlanTemplate = (skillText: String, renderedByPath: Mapping) -> - if (renderedByPath.containsKey(planTemplatePath)) - skillText + "\n\n## Plan template\n\n" + renderedByPath[planTemplatePath].text - else skillText - -/// Claude treats the most recently injected instruction block as the strongest -/// one, so a phase skill that ends on "return only the result" reads as the end -/// of the turn and the invoking command never resumes. State the turn boundary -/// explicitly at the end of every Claude `SKILL.md`. -local appendControlFlow = (skillText: String) -> skillText + "\n\n" + CONTROL_FLOW - -local buildClaudeSkillText = (skillSlug: String, renderedByPath: Mapping) -> - appendControlFlow.apply( - foldPlanTemplate.apply( - foldResultContract.apply( - skillSlug, - rewriteMachineReferencePaths.apply(renderedByPath["SKILL.md"].text), - renderedByPath - ), - renderedByPath - ) - ) - -/// Emit Claude skill documents with machine contracts folded into `SKILL.md` -/// and at most one human-presentation file under `references/`. -renderSkillPackage = (skillSlug: String, skillPackage: model.SkillPackage) -> - let (renderedByPath = renderPackageDocuments.apply(skillSlug, skillPackage)) - new Mapping { - ["SKILL.md"] = new model.WorkflowDocument { - path = "SKILL.md" - text = buildClaudeSkillText.apply(skillSlug, renderedByPath) - } - for (path, document in renderedByPath) { - when (humanPresentationPaths.contains(path)) { - [path] = document - } - } - } - -local CONTROL_FLOW = """ - ## Control flow - - This skill is one phase of a workflow, not a turn. Return the result to the - invoking command and let it continue in the same turn. Do not present the - result to the user as workflow output, and do not end your turn after - returning it — the invoking command decides what the user sees and when the - workflow stops. - """ - -local CONTEXT_BRIEF = """ - # SCE Context Load Result Contract - - Return exactly one Markdown document using one layout below. The first line - after the title is the status source consumed by the invoking command. Use - the headings and labels exactly as written, omit optional sections that do - not apply, and do not add prose outside the selected layout. - - List every file read and no file that was not read. Key facts are durable - statements, not planning or implementation recommendations. Empty required - lists must contain `- None.`. This skill never reports context edits. - - ## Status: `loaded` - - Use when the context root exists and relevant context was read. - - ```markdown - # Context Load Result - - Status: loaded - - ## Context root - - {context_root} - - ## Entry points - - ### {path} - - - Read: {true|false} - - Reason: {reason; omit only when read is true and no reason is needed} - - ## Domain context - - ### {path} - - **Relevance:** {relevance} - - **Key facts:** - - - {key_fact} - - ## Gaps - - ### {area} - - {detail} - - ## Drift - - ### {path} - - - Context says: {context_says} - - Code says: {code_says} - - Repair needed: {repair_needed} - ``` - - `Context root`, `Entry points`, `Domain context`, and `Gaps` are required. - Repeat the entry-point, domain-context, gap, and drift blocks as needed. - Include `Drift` only when recorded context contradicts code. Record gaps for - absent entry points and focus areas without durable context. - - ## Status: `bootstrap_required` - - Use when the context root does not exist. Read and create nothing. - - ```markdown - # Context Load Result - - Status: bootstrap_required - - ## Context root - - {context_root} - - ## Reason - - {reason} - ``` - """ - -local AUTHORING_CONTRACT = """ - # SCE Plan Authoring Result Contract - - Return exactly one Markdown document using one layout below. `Status` is the - branch value consumed by the invoking command. Use every required heading and - label exactly as written, omit optional sections that do not apply, and do - not add prose outside the selected layout. Empty required lists must contain - `- None.`. - - Report plan names without extensions and paths exactly as written so emitted - commands are runnable. Only `plan_ready` writes a plan. Do not include - implementation, synchronization, or final-validation results. - - ## Status: `plan_ready` - - Use after creating or updating a plan with at least one incomplete task. - - ```markdown - # Plan Authoring Result - - Status: plan_ready - - ## Plan - - - Path: {plan.path} - - Name: {plan.name} - - Action: {created|updated} - - Completed tasks: {plan.completed_tasks} - - Total tasks: {plan.total_tasks} - - ## Summary - - {summary} - - ## Tasks - - - {task.id} — {task.title} — {todo|done} - - ## Next task - - - ID: {next_task.id} - - Title: {next_task.title} - - ## Assumptions - - - {assumption} - - ## Open questions - - - {open_question} - ``` - - `Plan`, `Summary`, `Tasks`, `Next task`, and `Assumptions` are required. - List tasks in plan order, including completed tasks. `Next task` is the first - unchecked task. Include `Open questions` only for genuine non-blocking - questions. Summary describes resulting behavior rather than repeating tasks. - - ## Status: `needs_clarification` - - Use when one to three critical questions block writing the plan. - - ```markdown - # Plan Authoring Result - - Status: needs_clarification - - ## Plan target - - - Name: {plan_target.name} - - Action: {created|updated} - - Path: {existing plan_target.path; omit this label when no plan exists} - - ## Questions - - ### {question.id} - - - Category: {scope|success_criteria|constraints|dependency|domain|architecture|sequencing} - - Question: {question} - - Why blocking: {why_blocking} - ``` - - `Questions` is required. `Plan target` is optional and appears only when the - request resolved to one target before authoring stopped. Never report a path - for a plan that does not exist. - - ## Status: `blocked` - - Use when the target cannot be resolved or the request cannot be safely - planned. Nothing is written. - - ```markdown - # Plan Authoring Result - - Status: blocked - - ## Candidates - - - {candidate_path} - - ## Issues - - ### {issue.id} - - - Category: {ambiguous_plan_target|missing_request|conflicting_request|no_actionable_work|other} - - Problem: {problem} - - Impact: {impact} - - Decision required: {decision_required} - ``` - - `Issues` is required. Include `Candidates` only for an ambiguous existing-plan - match. Use `needs_clarification` when an answer would make the request - plannable; use `no_actionable_work` when no incomplete task would result. - """ - -local READINESS_CONTRACT = """ - # SCE Plan Review Result Contract - - Return exactly one Markdown document using one layout below. `Status` is the - branch value consumed by `/next-task`. Use every required heading and label - exactly as written, omit optional sections that do not apply, and do not add - prose outside the selected layout. Empty required lists must contain - `- None.`. - - Report task counts as they stand and the plan path exactly as resolved. Do - not request implementation confirmation or include implementation, - synchronization, or final-validation results. - - ## Status: `ready` - - ```markdown - # Plan Review Result - - Status: ready - - ## Plan - - - Path: {plan.path} - - Name: {plan.name} - - Completed tasks: {plan.completed_tasks} - - Total tasks: {plan.total_tasks} - - ## Task - - - ID: {task.id} - - Title: {task.title} - - ## Relevant files - - - {relevant_file} - - ## Relevant context - - - {relevant_context} - - ## Assumptions - - - {assumption} - ``` - - Every section is required. `Name` is the plan basename without its extension. - Repeat list items as needed. - - This layout is a compact handoff, not a task presentation. It carries only - what review discovered and the next phase cannot recover on its own. The - task's goal, scope boundaries, done checks, dependencies, and verification - stay in the plan file, where `sce-task-execution` reads them. Do not restate - them here. - - ## Status: `blocked` - - ```markdown - # Plan Review Result - - Status: blocked - - ## Plan - - - Path: {plan.path} - - Completed tasks: {plan.completed_tasks} - - Total tasks: {plan.total_tasks} - - ## Task - - - ID: {task.id} - - Title: {task.title} - - ## Candidates - - - {candidate_path} - - ## Issues - - ### {issue.id} - - - Category: {missing_decision|ambiguity|missing_acceptance_criteria|dependency|scope} - - Problem: {problem} - - Impact: {impact} - - Decision required: {decision_required} - - ## Executable tasks remaining - - {true|false} - ``` - - `Issues` is required. Include `Plan` whenever exactly one plan resolved, - `Task` when one was selected, and `Candidates` only when plan resolution - failed or was ambiguous. Include `Executable tasks remaining` when a plan - resolved. - - ## Status: `plan_complete` - - ```markdown - # Plan Review Result - - Status: plan_complete - - ## Plan - - - Path: {plan.path} - - Completed tasks: {plan.completed_tasks} - - Total tasks: {plan.total_tasks} - ``` - """ - -local EXECUTION_CONTRACT = """ - # SCE Task Execution Result Contract - - Return exactly one Markdown document using one layout below after the - implementation gate reaches a terminal state. `Status` is the branch value - consumed by `/next-task`. Use every required heading and label exactly as - written, omit optional sections that do not apply, and do not add prose - outside the selected layout. Empty required lists must contain `- None.`. +renderCommand = (workflow: ClaudeWorkflow, allowedTools: String) -> new model.WorkflowDocument { + path = workflow.command.path + text = """ +--- +description: "\(workflow.description)" +argument-hint: "\(workflow.argumentHint)" +allowed-tools: \(allowedTools) +--- + +Invoke the `\(workflow.skillSlug)` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. +""" +} - Report task counts as they stand. Never serialize the implementation gate, - select the next task, or include synchronization or final-validation results. +local CHANGE_OUTPUT = """ +# Change-to-plan output layouts - ## Shared Plan and Task layout +Use only the applicable layout. Values come from internal workflow state. - Every status includes these sections: +## Missing context bootstrap gate - ```markdown - ## Plan +```markdown +------------------------------------- - - Path: {plan.path} - - Completed tasks: {plan.completed_tasks} - - Total tasks: {plan.total_tasks} +# This repository has no durable context. - ## Task +Bootstrap it, then continue in this session: - - ID: {task.id} - - Title: {task.title} - ``` +`sce setup --bootstrap-context` +``` - ## Status: `declined` +## Clarification gate - ```markdown - # Task Execution Result +```markdown +------------------------------------- - Status: declined +# Clarification needed. - {Shared Plan and Task layout} - ``` +No plan was written. - Use only when the user declines and no implementation changes were made. +Answer each question below.\(" ") - ## Status: `blocked` +## {question-id} · {category} - ```markdown - # Task Execution Result +{question} - Status: blocked +Why this blocks planning: {why_blocking} +``` - {Shared Plan and Task layout} +## Blocked - ## Blocker +Present each issue's problem, impact, and required decision. For ambiguity, list +candidate plan paths and explain that naming one candidate resolves it. - - Category: {stale_review|scope|dependency|architecture|security|data|destructive_operation|other} - - Problem: {problem} - - Impact: {impact} - - Decision required: {decision_required} +## Ready continuation - ## Changes +```markdown +------------------------------------- - ### Files changed +# Plan {plan-name} is ready. - - {file} +{total-tasks} {task|tasks} planned. - ## Verification +This plan is a draft. State a correction and it will be updated. - ### {command} +Next up: - - Outcome: {passed|failed|not_run} - - Summary: {summary} +{next-task-id} — {next-task-title} - ## Work preserved +`/next-task {plan-path} {next-task-id}` +``` - {true|false} - ``` +For revisions, replace `is ready` with `revised`. +""" - `Blocker` and `Work preserved` are required. `Changes` and `Verification` are - optional and appear only when work or checks occurred. +local NEXT_OUTPUT = """ +# Next-task output layouts - ## Status: `incomplete` +Use only the applicable layout. Values come from internal workflow state. - ```markdown - # Task Execution Result +## Review blocked - Status: incomplete +Present the selected task, then each issue's problem, impact, and required +decision. If plan resolution is ambiguous, list candidate paths and +`/next-task {candidate-path}`. State whether another task remains executable. - {Shared Plan and Task layout} +## Plan already complete - ## Changes +```markdown +------------------------------------- - ### Files changed +# Implementation tasks are complete. - - {file} +Run the final validation: - ### Summary +`/validate {plan-path}` +``` - - {change_summary} +## Declined - ## Verification +```markdown +You have declined to proceed with this task +``` - ### {command} +## Execution blocked or incomplete - - Outcome: {passed|failed|not_run} - - Summary: {summary} +For `blocked`, present the blocker, work completed before it, and the required +decision or action. For `incomplete`, present completed work, verification +evidence, remaining work, and the reason it remains incomplete. - ## Satisfied done checks +## Context synchronization blocked - - {check} +State that task `{completed-task-id}` was implemented, verified, and recorded; +report the contradiction or synchronization failure, preserved edits, required +action, and retry condition. State that durable context is out of date and must +be synchronized before continuing. - ## Unsatisfied done checks +## More tasks remain - - {check} +```markdown +------------------------------------- - ## Remaining work +# Task {completed-task-id} completed. - - {remaining_work} +{completed-tasks} of {total-tasks} tasks complete. - ## Reason +Next up: - {reason} - ``` +{next-task-id} — {next-task-title} - `Changes`, `Verification`, and `Remaining work` are required. The done-check - sections and `Reason` are optional. +`/next-task {plan-path} {next-task-id}` +``` - ## Status: `complete` +## All tasks complete - ```markdown - # Task Execution Result +```markdown +------------------------------------- - Status: complete +# Task {completed-task-id} completed. - {Shared Plan and Task layout} +All tasks are complete. - ## Changes +Run the final validation: - ### Files changed +`/validate {plan-path}` +``` +""" - - {file} +local VALIDATE_OUTPUT = """ +# Validate output layouts - ### Summary +Use only the applicable layout. Values come from internal workflow state. - - {change_summary} +## Validation blocked - ## Verification +```markdown +# Validation blocked - ### {command} +**Status:** blocked\(" ") +**Plan:** `{plan-path when resolved}`\(" ") +**Name:** `{plan-name when resolved}` - - Outcome: passed - - Summary: {summary} +## Issues - ## Done checks +- **{issue-id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision-or-action} - ### {check} +## Incomplete tasks - {evidence} +- `{task-id}` — {title} - ## Context impact +## Candidates - - Classification: {none|local|domain|root} - - Affected areas: {comma-separated areas, or none} - - Reason: {reason} - ``` +- `{candidate-plan-path}` - Every shown section is required. Repeat verification and done-check blocks as - needed. This layout is the authoritative handoff to context synchronization. +## Next step - Keep it at exactly these sections. `sce-task-context-sync` validates the - changed files, implementation summary, verification evidence, done-check - evidence, and context impact, and blocks when any is missing, so none of them - may be dropped. `Status: complete` already asserts the task was marked - complete in the plan with evidence recorded; do not restate that as a section. - """ +{one continuation matching the blocker} +``` -local COMMIT_CONTRACT = """ - # SCE Atomic Commit Result Contract +Omit inapplicable optional sections. - Return exactly one Markdown document using one layout below. `Status` is the - branch value consumed by `/commit`. Use every required heading and label - exactly as written, omit optional sections that do not apply, and do not add - prose outside the selected layout. +## Validation failed handoff - Report paths exactly as `git diff --cached --name-only` reports them. Every - staged file belongs to exactly one proposed commit. Keep each message's body - in the same fenced block as its subject, separated by one blank line. Never - report a commit hash or guidance forbidden by the mode. +```markdown +# Validation failed — handoff - ## Status: `proposal` +**Status:** failed\(" ") +**Plan:** `{plan-path}`\(" ") +**Name:** `{plan-name}`\(" ") +**Tasks:** `{completed}/{total} complete`\(" ") +**Date:** `{YYYY-MM-DD}`\(" ") +**Validation report:** written to `{plan-path}` - Use only in regular mode. Nothing is committed. +## Goal for the next session - ````markdown - # Atomic Commit Result +{repair goal} - Status: proposal - Mode: regular +## What failed - ## Commits +- `{check-or-AC}`: {problem} + - Evidence: {evidence} + - Required action: {action} - ### {commit.id} +## Acceptance criteria - #### Message +- [{x-or-space}] {criterion}: {evidence} - ```text - {subject} +## Commands run - {body} - ``` +- `{command}` -> {passed|failed|not_run} — {summary} - #### Files +## Constraints - - {file} +{canonical validation constraints} - #### Cites plan +## Residual risks - {true|false} +- {risk-or-none} - ## Split rationale +## Recommended work - {split_rationale} +1. {repair} +2. Rerun final validation after repairs: - ## Scope classification +`/validate {plan-path}` +``` - {context_only|mixed} +## Context synchronization blocked - ## Notes +State that validation passed and its report is recorded, then report the context +failure, preserved edits, required action, and retry condition. State that durable +context remains out of date and synchronization must finish before closure. - - {note} - ```` +## Completion - `Commits` is required. Repeat the commit block as needed. Include `Split - rationale` only for multiple commits. `Scope classification` and `Notes` are - optional. +```markdown +------------------------------------- - ## Status: `bypass_message` +# Plan {plan-name} validated. - Use only in bypass mode. Exactly one message covers every staged file. +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. - ````markdown - # Atomic Commit Result +Validation report: {plan-path} +``` +""" - Status: bypass_message - Mode: bypass +local COMMIT_OUTPUT = """ +# Commit output layouts - ## Message +Use only the applicable layout. Values come from staged truth and internal +workflow state. - ```text - {subject} +## Regular-mode staging gate - {body} - ``` +```markdown +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` - ## Files +## No staged changes - - {file} +```markdown +No staged changes. Stage changes before commit. +``` - ## Cites plan +## Regular proposal - {true|false} +For each proposal, present the complete commit message and covered files. When +more than one commit is proposed, also present the split rationale. Do not claim a +commit was created. - ## Notes +## Blocked - - {note} - ```` +Present every issue's problem, impact, and required decision. Do not commit. - `Message` and `Files` are required. `Cites plan` and `Notes` are optional. - Never include commits, split rationale, or scope classification. +## Bypass success - ## Status: `blocked` +```markdown +Committed {commit-hash} +``` - ````markdown - # Atomic Commit Result +## Bypass Git failure - Status: blocked - Mode: {regular|bypass} +Present Git's failure unchanged and stop without retrying. +""" - ## Files +local changeWorkflow = new ClaudeWorkflow { + slug = "change-to-plan" + skillSlug = metadata.workflowSkillSlugByCommand["change-to-plan"] + title = "SCE Change to Plan" + description = "Turn one change request into a scoped SCE plan in one self-contained workflow" + argumentHint = "" + command = changeToPlan.workflow.command.document + phaseDocuments = new Listing { + new model.WorkflowDocument { path = "sce-context-load"; text = changeToPlan.workflow.skills["sce-context-load"].documents["SKILL.md"].text } + new model.WorkflowDocument { path = "sce-plan-authoring"; text = changeToPlan.workflow.skills["sce-plan-authoring"].documents["SKILL.md"].text } + } + internalDocuments = new Listing { + new model.WorkflowDocument { path = "Plan template"; text = changeToPlan.workflow.skills["sce-plan-authoring"].documents["references/plan-template.md"].text } + } + outputText = internalize.apply(CHANGE_OUTPUT + "\n\n" + changeToPlan.workflow.skills["sce-plan-authoring"].documents["references/plan-summary.md"].text) +} - - {file} +local nextWorkflow = new ClaudeWorkflow { + slug = "next-task" + skillSlug = metadata.workflowSkillSlugByCommand["next-task"] + title = "SCE Next Task" + description = "Review, approve, implement, verify, and synchronize one SCE plan task" + argumentHint = " [T0X] [approved]" + command = nextTask.workflow.command.document + phaseDocuments = new Listing { + new model.WorkflowDocument { path = "sce-plan-review"; text = nextTask.workflow.skills["sce-plan-review"].documents["SKILL.md"].text } + new model.WorkflowDocument { path = "sce-task-execution"; text = nextTask.workflow.skills["sce-task-execution"].documents["SKILL.md"].text } + new model.WorkflowDocument { path = "sce-task-context-sync"; text = nextTask.workflow.skills["sce-task-context-sync"].documents["SKILL.md"].text } + } + internalDocuments = new Listing {} + outputText = internalize.apply(NEXT_OUTPUT + "\n\n" + nextTask.workflow.skills["sce-task-execution"].documents["references/implementation-gate.md"].text + "\n\n" + nextTask.workflow.skills["sce-task-context-sync"].documents["references/sync-report.md"].text) +} - ## Issues +local validateWorkflow = new ClaudeWorkflow { + slug = "validate" + skillSlug = metadata.workflowSkillSlugByCommand["validate"] + title = "SCE Validate" + description = "Validate one completed SCE plan and synchronize its durable context" + argumentHint = "" + command = validate.workflow.command.document + phaseDocuments = new Listing { + new model.WorkflowDocument { path = "sce-validation"; text = validate.workflow.skills["sce-validation"].documents["SKILL.md"].text } + new model.WorkflowDocument { path = "sce-plan-context-sync"; text = validate.workflow.skills["sce-plan-context-sync"].documents["SKILL.md"].text } + } + internalDocuments = new Listing { + new model.WorkflowDocument { path = "Plan-file validation report"; text = validate.workflow.skills["sce-validation"].documents["references/validation-report.md"].text } + } + outputText = internalize.apply(VALIDATE_OUTPUT + "\n\n" + validate.workflow.skills["sce-validation"].documents["references/validation-result.md"].text + "\n\n" + validate.workflow.skills["sce-plan-context-sync"].documents["references/sync-report.md"].text) +} - ### {issue.id} +local commitWorkflow = new ClaudeWorkflow { + slug = "commit" + skillSlug = metadata.workflowSkillSlugByCommand["commit"] + title = "SCE Commit" + description = "Analyze staged changes and run the regular or explicit bypass commit workflow" + argumentHint = "[oneshot|skip] [commit context]" + command = commit.workflow.command.document + phaseDocuments = new Listing { + new model.WorkflowDocument { path = "sce-atomic-commit"; text = commit.workflow.skills["sce-atomic-commit"].documents["SKILL.md"].text } + } + internalDocuments = new Listing {} + outputText = internalize.apply(COMMIT_OUTPUT + "\n\n" + commit.workflow.skills["sce-atomic-commit"].documents["references/commit-message-style.md"].text) +} - - Category: {no_staged_changes|plan_citation_ambiguity|unreadable_diff|contradictory_context} - - Problem: {problem} - - Impact: {impact} - - Decision required: {decision_required} - ```` +workflows = new Mapping { + [changeWorkflow.slug] = changeWorkflow + [nextWorkflow.slug] = nextWorkflow + [validateWorkflow.slug] = validateWorkflow + [commitWorkflow.slug] = commitWorkflow +} - `Issues` is required. Include `Mode` when supplied and `Files` when staged - files were read. Plan-citation ambiguity blocks only in regular mode; bypass - mode omits the citation instead. - """ +skillDocuments { + for (_, workflow in workflows) { + ["\(workflow.skillSlug)/SKILL.md"] = renderSkill.apply(workflow) + ["\(workflow.skillSlug)/references/output.md"] = new model.WorkflowDocument { + path = "references/output.md" + text = workflow.outputText + } + } +} diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index 8351f5cb..c0e6ac63 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -1,5 +1,6 @@ import "opencode-content.pkl" as opencode import "claude-content.pkl" as claude +import "claude-metadata.pkl" as claudeMetadata import "pi-content.pkl" as pi local expectedCommandSlugs = Set( @@ -14,6 +15,8 @@ local expectedAgentSlugs = Set( "shared-context-code" ) +local expectedClaudeSkillByCommand = claudeMetadata.workflowSkillSlugByCommand + local expectedCanonicalSkillDocumentPaths = Set( "sce-atomic-commit/SKILL.md", "sce-atomic-commit/references/commit-contract.yaml", @@ -38,23 +41,18 @@ local expectedCanonicalSkillDocumentPaths = Set( "sce-validation/references/validation-result.md" ) -/// Claude folds machine contracts and plan templates into SKILL.md, so each -/// package keeps at most one human-presentation `references/` file. +/// Claude collapses each workflow into one package with one entrypoint and one +/// user-visible Markdown output reference. Exact coverage rejects stale phase +/// packages and any additional package-local references. local expectedClaudeSkillDocumentPaths = Set( - "sce-atomic-commit/SKILL.md", - "sce-atomic-commit/references/commit-message-style.md", - "sce-context-load/SKILL.md", - "sce-plan-authoring/SKILL.md", - "sce-plan-authoring/references/plan-summary.md", - "sce-plan-context-sync/SKILL.md", - "sce-plan-context-sync/references/sync-report.md", - "sce-plan-review/SKILL.md", - "sce-task-context-sync/SKILL.md", - "sce-task-context-sync/references/sync-report.md", - "sce-task-execution/SKILL.md", - "sce-task-execution/references/implementation-gate.md", - "sce-validation/SKILL.md", - "sce-validation/references/validation-report.md" + "sce-change-to-plan/SKILL.md", + "sce-change-to-plan/references/output.md", + "sce-next-task/SKILL.md", + "sce-next-task/references/output.md", + "sce-validate/SKILL.md", + "sce-validate/references/output.md", + "sce-commit/SKILL.md", + "sce-commit/references/output.md" ) local opencodeAgents = new Mapping { @@ -100,12 +98,25 @@ local assertExactKeys = (actual: Mapping, expected: Set, label: String) ) "\(label): complete" else error("\(label) inventory does not match the canonical workflow matrix") +local assertClaudeCommandRoute = (slug: String, document: String) -> + let (expectedInvocation = "Invoke the `\(expectedClaudeSkillByCommand[slug])` skill exactly once") + if ( + document.contains(expectedInvocation) + && expectedClaudeSkillByCommand.every((otherSlug, skillSlug) -> + otherSlug == slug || !document.contains("`\(skillSlug)`") + ) + ) "Claude \(slug) command route: complete" + else error("Claude \(slug) command must invoke exactly its corresponding workflow skill") + inventoryChecks { ["opencode-agents"] = assertExactKeys.apply(opencodeAgents, expectedAgentSlugs, "OpenCode agent") ["opencode-commands"] = assertExactKeys.apply(opencodeCommands, expectedCommandSlugs, "OpenCode command") ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedCanonicalSkillDocumentPaths, "OpenCode skill document") ["claude-commands"] = assertExactKeys.apply(claudeCommands, expectedCommandSlugs, "Claude command") ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedClaudeSkillDocumentPaths, "Claude skill document") + for (slug, document in claudeCommands) { + ["claude-command-route-\(slug)"] = assertClaudeCommandRoute.apply(slug, document.text) + } ["pi-commands"] = assertExactKeys.apply(piCommands, expectedCommandSlugs, "Pi command") ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedCanonicalSkillDocumentPaths, "Pi skill document") } diff --git a/config/pkl/renderers/opencode-metadata.pkl b/config/pkl/renderers/opencode-metadata.pkl index 6af1008b..3a1b1ccf 100644 --- a/config/pkl/renderers/opencode-metadata.pkl +++ b/config/pkl/renderers/opencode-metadata.pkl @@ -69,6 +69,7 @@ permission: "sce-task-context-sync": allow "sce-validation": allow "sce-plan-context-sync": allow + "sce-atomic-commit": allow """ } diff --git a/context/architecture.md b/context/architecture.md index b5b3f36d..64881489 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -21,7 +21,7 @@ Current target renderer helper modules: - `config/pkl/renderers/opencode-content.pkl` - `config/pkl/renderers/claude-content.pkl` -- `config/pkl/renderers/claude-workflow-results.pkl` (Claude-only Markdown phase-result contracts and package-local path overrides) +- `config/pkl/renderers/claude-workflow-results.pkl` (Claude-only composition of canonical phases into four workflow-level skills and their single `references/output.md` presentation documents) - `config/pkl/renderers/pi-content.pkl` - `config/pkl/renderers/common.pkl` - `config/pkl/renderers/opencode-metadata.pkl` @@ -37,14 +37,14 @@ The scaffold provides stable canonical content-unit identifiers and reusable tar Renderer modules apply target-specific metadata/frontmatter rules while reusing canonical content bodies: - The manual OpenCode renderer consumes the four canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. -- Claude renderer consumes the four canonical workflow packages, extends command and skill entrypoint frontmatter with `allowed-tools` and `compatibility: claude`, and emits exactly four commands plus eight self-contained skill packages without generated agents. `claude-workflow-results.pkl` replaces the five canonical YAML-returning skill contracts with Markdown layouts, folds those contracts (plus plan-template and validation-result) into each package's `SKILL.md`, and keeps at most one human-presentation file under `references/` per Claude package. Validation and context-sync human reports remain package-local `references/` documents when present. Claude settings and the hook helper remain separate retained outputs. +- Claude renderer consumes the four canonical workflow packages as behavior sources but emits four target-specific workflow packages without generated agents: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command invokes exactly one corresponding workflow skill. `claude-workflow-results.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Claude settings and the hook helper remain separate retained outputs. - Pi renderer consumes the four canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly four prompts to `config/.pi/prompts/{slug}.md` and eight self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). -- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tool and compatibility fields. Pi workflow documents own their supported frontmatter directly. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode/Pi's 21 multi-file skill documents, Claude's reduced single human-presentation skill inventory (machine contracts inlined in `SKILL.md`), and two OpenCode agents—then forces every rendered document and target metadata lookup to evaluate. -- OpenCode, Claude, and Pi renderers expose canonical command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`. -- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete skill packages with nested references, and two thin routing agents; Claude's four workflow commands and eight complete skill packages with nested references but no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four workflow prompts, eight complete skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. +- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and the exact command-to-workflow-skill slug mapping. Pi workflow documents own their supported frontmatter directly. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode/Pi's 21 multi-file skill documents, Claude's four two-file workflow packages, and two OpenCode agents—then verifies every Claude command's one-to-one workflow-skill route and forces every rendered document and target metadata lookup to evaluate. +- OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; Claude's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. +- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete phase-skill packages with nested references, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four workflow prompts, eight complete phase-skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. - `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. @@ -185,8 +185,6 @@ Shared Context Plan and Shared Context Code remain separate architectural roles. - `/change-to-plan` and `/next-task` remain separate command entrypoints aligned to those roles. - Reuse is handled through shared canonical guidance blocks and skill-owned phase contracts, not by collapsing both roles into one agent. - OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole behavior owners. -- `/change-to-plan` sequences `sce-context-load` and `sce-plan-authoring`, preserving context loading, clarification, plan output, and `/next-task` handoff ownership. -- `/next-task` owns one-task sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, including its implementation gate and continuation contract. -- `/validate` owns final sequencing across `sce-validation` and validated-only `sce-plan-context-sync`. -- `/commit` owns regular proposal-only and bypass sequencing around `sce-atomic-commit`. +- Canonical Pi/OpenCode `/change-to-plan` sequences `sce-context-load` and `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` and validated-only `sce-plan-context-sync`; `/commit` sequences around `sce-atomic-commit`. +- Claude embeds those same phase boundaries inside `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, so no Claude command or workflow skill invokes a phase or sibling SCE package. - OpenCode, Claude, and Pi expose the generated `/commit` workflow but no generated `/handover` command; the automated OpenCode profile is removed. diff --git a/context/context-map.md b/context/context-map.md index 69dccee2..e016185a 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -22,12 +22,12 @@ Feature/domain context: - `context/cli/capability-traits.md` (current broad CLI capability seam in `cli/src/services/capabilities.rs`, including `FsOps`/`StdFsOps`, `GitOps`/`ProcessGitOps`, git root/hooks resolution behavior, compile-time-typed borrowed AppContext wiring with associated-type narrow capability accessors plus `ContextWithRepoRoot` repo-root-scoped context derivation, generic command execution bounds, and test-only unimplemented stubs; current service internals do not consume fs/git traits until later lifecycle migration tasks) - `context/cli/service-lifecycle.md` (current compile-safe lifecycle seam in `cli/src/services/lifecycle.rs`, including default no-op `ServiceLifecycle` diagnose/fix/setup methods against narrow `HasRepoRoot`, lifecycle-owned health/fix/setup result types with generic setup messages, doctor/setup adapter boundaries, the static `LifecycleProvider` enum catalog/dispatcher, hook/config/local_db/auth_db/agent_trace_db lifecycle providers including setup-time repository-scoped Agent Trace DB initialization plus checkout identity diagnostics, implemented doctor aggregation over diagnose/fix providers, and implemented setup aggregation over `setup` providers in order config → local_db → auth_db → agent_trace_db → hooks when requested) - `context/sce/cli-observability-contract.md` (implemented config-backed runtime observability contract for the flat logging config-file shape with env-over-config fallback, concrete logger/telemetry runtime behavior plus logger and object-safe telemetry trait boundaries, AppContext observability wiring, generic `RunOutcome` final rendering, runtime-classified repeated telemetry action protection, operator-facing `sce config show` observability reporting, and the trimmed `sce config validate` status-only validation surface) -- `context/sce/shared-context-code-workflow.md` -- `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, and one-task/one-atomic-commit task-slicing policy) +- `context/sce/shared-context-code-workflow.md` (canonical `/next-task` and `/validate` lifecycles, including Pi/OpenCode phase ownership and Claude's single-skill `sce-next-task` / `sce-validate` composition) +- `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, one-task/one-atomic-commit task slicing, and Claude's `sce-change-to-plan` ownership) - [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) - `context/sce/plan-code-overlap-map.md` (overlap matrix for thin OpenCode Plan/Code routing agents and workflow phase ownership; its original three-workflow inventory predates the generated `/commit` package) - `context/sce/dedup-ownership-table.md` (canonical owner-vs-consumer boundaries for workflow packages, phase skills, the shared sync skeleton, and thin OpenCode agents; its original three-workflow/seven-skill inventory predates generated `/commit` and `sce-atomic-commit`) -- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, command-vs-`sce-atomic-commit` ownership boundary, staged-truth rule, plan-citation rule, and result contract; now canonical Pkl and generated for OpenCode, Claude, and Pi) +- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, staged-truth and plan-citation rules, canonical Pi/OpenCode `sce-atomic-commit` phase ownership, and Claude's composite `sce-commit` package) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) @@ -83,7 +83,8 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` -- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (current workflow-oriented target matrix and canonical Pkl ownership) +- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (canonical workflow-oriented ownership and current Pi/OpenCode phase-package matrix; Claude inventory claims are superseded) +- `context/decisions/2026-07-29-claude-workflow-skill-packages.md` (Claude's four command-to-workflow-skill routes, two-file package rule, internal phase state, and Pi/OpenCode preservation) - `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes pre-Cargo generation, validated copying into Cargo `OUT_DIR`, and crates.io/Flatpak packaging fallbacks) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) diff --git a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md index 223dd088..522ae7d4 100644 --- a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md +++ b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md @@ -1,7 +1,7 @@ # Decision: Use Workflow-Oriented Pkl Generation Date: 2026-07-27 -Status: Accepted +Status: Accepted (Claude inventory and transport superseded 2026-07-29) Plan: `context/plans/rebuild-pkl-workflow-markdown.md` ## Decision @@ -32,4 +32,6 @@ The automated profile and obsolete Markdown catalog represented a second behavio This decision supersedes the generated path matrix, paired-output counts, and target inventory in `2026-02-28-pkl-generation-architecture.md`. That decision's canonical-Pkl-source, deterministic-rendering, and generated-vs-runtime ownership principles remain in force. +`2026-07-29-claude-workflow-skill-packages.md` supersedes this decision's claims that Claude receives the same eight phase packages and transports Markdown phase results. Pi/OpenCode decomposition and all other ownership decisions here remain in force. + The separate Plan/Code role decision in `2026-03-03-plan-code-agent-separation.md` remains in force, with agents now explicitly limited to routing. diff --git a/context/decisions/2026-07-29-claude-workflow-skill-packages.md b/context/decisions/2026-07-29-claude-workflow-skill-packages.md new file mode 100644 index 00000000..24370fbb --- /dev/null +++ b/context/decisions/2026-07-29-claude-workflow-skill-packages.md @@ -0,0 +1,34 @@ +# Decision: Collapse Claude Workflows into Single-Skill Packages + +Date: 2026-07-29 +Status: Accepted +Plan: `context/plans/claude-workflow-single-skill-packages.md` +Supersedes in part: `2026-07-27-workflow-oriented-pkl-generation.md` + +## Decision + +- Keep the four canonical workflow definitions and eight phase-skill packages as the behavioral source for Pi and OpenCode. +- Render Claude as exactly four thin commands and four workflow-level skills: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. +- Route each Claude command to exactly one corresponding workflow skill. Claude commands do not sequence phase skills. +- Compose each Claude workflow skill from the canonical command, phase behavior, and context-sync policy in `config/pkl/renderers/claude-workflow-results.pkl`. +- Keep phase statuses and phase-to-phase data as internal workflow state. A Claude workflow skill never invokes another SCE skill or sibling package. +- Emit exactly two files per Claude package: `SKILL.md` and `references/output.md`. The latter is the sole package reference and owns all human-visible gates, reports, and terminal Markdown layouts. +- Preserve Pi and OpenCode generated command behavior, eight-skill inventories, and phase contracts byte-for-byte. + +## Rationale + +Claude executes a skill as the durable unit of control flow. Returning a phase result through one skill and asking a command to resume another phase creates an unreliable turn boundary: the intermediate result can become the apparent deliverable and terminate the workflow. Putting the complete lifecycle in one skill removes that transport seam while retaining the canonical gates, waits, writes, verification, synchronization, and continuation rules. + +The target-specific collapse belongs in the renderer rather than the canonical base because Pi and OpenCode support the existing decomposed workflow and rely on its explicit phase contracts. + +## Consequences + +- Claude no longer emits `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, or `sce-atomic-commit` packages. +- Claude has no inter-skill YAML or Markdown phase-result contracts. Internal statuses still mirror canonical variants so behavior remains aligned. +- `config/pkl/renderers/claude-metadata.pkl` owns the exact command-to-workflow-skill slug mapping. +- `config/pkl/renderers/metadata-coverage-check.pkl` rejects stale phase packages, extra references, missing two-file packages, and incorrect command routes. +- Claude's generated workflow inventory is eight Markdown files total across four packages, in addition to four command files and retained settings/hooks. + +## Superseded scope + +This decision supersedes only the Claude inventory and Claude phase-result transport claims in `2026-07-27-workflow-oriented-pkl-generation.md`. That decision remains authoritative for canonical workflow ownership, Pi/OpenCode's eight phase packages, the shared context-sync skeleton, thin OpenCode agents, removed automated profiles, and retained non-Markdown outputs. diff --git a/context/glossary.md b/context/glossary.md index 6ed9508b..bd653b56 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -9,8 +9,8 @@ - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. -- `Claude Markdown phase-result contract`: Claude-only transport form for the structured results returned by `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`. Fixed `Status` lines, headings, and labels preserve the canonical status variants and command-readable values while Pi and OpenCode retain package-local YAML contracts under `references/`. On Claude these contracts (and plan-template / validation-result) are inlined into `SKILL.md` so each package keeps at most one human-presentation `references/` file; validation and context-sync human reports remain Markdown for every target. -- `Claude human-presentation reference`: Optional single file under a Claude skill package's `references/` used only for human-facing layouts (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, `commit-message-style.md`). Machine contracts stay multi-file under `references/` for OpenCode and Pi. +- `Claude workflow skill package`: One of the four renderer-composed Claude packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`). Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Pi and OpenCode retain the canonical eight phase-skill packages and their YAML handoff contracts. +- `Claude workflow output reference`: The required `references/output.md` in every Claude workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. @@ -143,10 +143,10 @@ - `SCE dedup ownership table`: Context artifact at `context/sce/dedup-ownership-table.md` that assigns one canonical owner per shared behavior domain, lists reference-only consumers, and labels each overlap as `intentional/keep` or `dedup/remove`. - `shared context plan workflow`: Canonical workflow document at `context/sce/shared-context-plan-workflow.md` defining `/change-to-plan` planning flow, clarification gate semantics, readiness contract, and `/next-task` handoff format. - `SCE Plan/Code role separation`: Architecture decision recorded in `context/decisions/2026-03-03-plan-code-agent-separation.md` that keeps Shared Context Plan and Shared Context Code as separate OpenCode routing roles. The thin Plan agent routes to `/change-to-plan`; the thin Code agent routes to `/next-task` and `/validate`; canonical commands and skills own behavior. -- `next-task thin orchestration contract`: `/next-task` command pattern where the command keeps one-task sequencing/readiness gates and delegates phase behavior to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. -- `change-to-plan thin orchestration contract`: `/change-to-plan` command pattern that sequences `sce-context-load` before `sce-plan-authoring`, preserving clarification, plan output, and `/next-task` handoff contracts in their declared owners. -- `validate thin orchestration contract`: `/validate` command pattern that delegates final checks to `sce-validation` and invokes `sce-plan-context-sync` only after a validated result. -- `OpenCode command skill metadata`: Machine-readable frontmatter on the three generated OpenCode workflow commands, using `entry-skill` for the initial phase and `skills` for the complete ordered chain defined by `config/pkl/renderers/opencode-content.pkl`. +- `next-task thin orchestration contract`: Canonical Pi/OpenCode `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; Claude embeds the same behavior in `sce-next-task` and routes its command directly to that one skill. +- `change-to-plan thin orchestration contract`: Canonical Pi/OpenCode `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`; Claude embeds the same behavior in `sce-change-to-plan` and routes its command directly to that one skill. +- `validate thin orchestration contract`: Canonical Pi/OpenCode `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`; Claude embeds the same behavior in `sce-validate` and routes its command directly to that one skill. +- `OpenCode command skill metadata`: Machine-readable frontmatter on the four generated OpenCode workflow commands, using `entry-skill` for the initial phase and `skills` for the complete ordered chain defined by `config/pkl/renderers/opencode-content.pkl`. - `one-task/one-atomic-commit planning contract`: `sce-plan-authoring` requirement that each executable plan task represents one coherent commit unit; broad multi-commit tasks must be split into sequential atomic tasks before execution handoff. - `agent trace historical reference docs`: Retained `context/sce/agent-trace-*.md` artifacts that describe the removed pre-v0.3 Agent Trace design and task slices; they are reference-only and do not describe the active local-hook runtime. - `agent trace commit-msg co-author policy`: Current contract in `cli/src/services/hooks/mod.rs` (`apply_commit_msg_coauthor_policy`) that applies exactly one canonical trailer (`Co-authored-by: SCE `) only when attribution hooks are enabled, SCE is not disabled, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); `NoOverlap` and `Error` both suppress the trailer, with `Error` logged via `sce.hooks.commit_msg.ai_overlap_error`; duplicate canonical trailers are deduped idempotently. diff --git a/context/overview.md b/context/overview.md index 49345b38..c47b42dc 100644 --- a/context/overview.md +++ b/context/overview.md @@ -55,8 +55,8 @@ The downstream publish-stage implementation is now complete for both registries: The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four canonical commands and eight self-contained skill packages rather than in agent bodies. -The `/change-to-plan` command sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. -Claude preserves these shared workflow semantics but uses target-specific Markdown result contracts for the five phase skills whose canonical Pi/OpenCode handoffs are YAML (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, and `sce-atomic-commit`). Fixed status lines, headings, and labels carry the same command-readable values without exposing raw phase reports as user-facing workflow output. Claude alone also folds those machine contracts and plan templates into each skill's `SKILL.md` so generated Claude packages keep at most one human-presentation `references/` file. +The canonical Pi/OpenCode workflows remain phase-decomposed: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. +Claude preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin Claude command invokes exactly one corresponding skill. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. Claude emits no phase-skill packages or inter-skill machine contracts. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. The prior no-git-wrapper Agent Trace design artifacts under `context/sce/agent-trace-*.md` are retained only as historical reference; the current CLI runtime no longer wires the removed Agent Trace schema adaptation, payload building, retry replay, or rewrite handling paths into local hook execution. @@ -70,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi and OpenCode consume the canonical result contracts directly, while Claude applies its phase-result transport override in the renderer layer. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi and OpenCode consume the canonical phase packages and result contracts directly, while Claude composes each full workflow into one target-specific skill and one `references/output.md` in the renderer layer. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. @@ -102,7 +102,7 @@ Lightweight post-task verification baseline (required after each completed task) ## Cross-target parity -- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four prompts and eight self-contained skill packages with no agent-role prompts. Manual OpenCode consumes the same workflow packages as exactly four commands, eight self-contained skill packages, and two thin routing agents. Claude consumes exactly four commands and eight self-contained skill packages with no generated agents, while retaining its generated settings and hook helper. +- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four prompts and eight self-contained phase-skill packages with no agent-role prompts. Manual OpenCode consumes the same phase packages as exactly four commands, eight skills, and two thin routing agents. Claude consumes exactly four thin commands and four workflow-level skill packages, each containing only `SKILL.md` and `references/output.md`, with no generated agents; its generated settings and hook helper remain. - When capabilities differ, parity is implemented by supported target-specific behavior rather than forcing unsupported fields. ## Context navigation diff --git a/context/patterns.md b/context/patterns.md index 1bc51898..198859b8 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -54,25 +54,22 @@ - Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. -- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`. Keep canonical Pi/OpenCode YAML phase-result contracts and multi-file `references/` inventories unchanged. For Claude only: render the five structured phase results as package-local Markdown contracts with fixed `Status` lines, headings, and labels, and fold machine contracts plus plan templates into each package's `SKILL.md` so Claude packages keep at most one human-presentation `references/` file when present (`plan-summary.md`, `implementation-gate.md`, `validation-report.md`, `sync-report.md`, or `commit-message-style.md`). +- Implement target-specific formatting and composition in dedicated renderer modules under `config/pkl/renderers/`. Keep canonical Pi/OpenCode YAML phase-result contracts and eight multi-file phase-package inventories unchanged. For Claude only, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi-compatible metadata remains in canonical workflow documents. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. - Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path; run it whenever workflow documents or target metadata change. -- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve the workflow body, and append only the required final newline at the output mapping. Claude is the single exception: it may also apply target-specific body transforms for harness behavior that other targets do not need, currently the phase-contract folding above and the turn-boundary rules below. -- Claude runs a skill inside the assistant's turn, so returning a phase result and printing it to the user are the same act and "do not print the result" is unenforceable. Keep Claude inter-phase handoffs shrunk to what the next phase cannot recover on its own: `sce-plan-review` `ready` carries plan and task identity, relevant files, relevant context, and assumptions, while goal, scope, done checks, dependencies, and verification stay in the plan file where `sce-task-execution` reads them for its implementation gate. `sce-task-execution` `complete` stays full-size because `sce-task-context-sync` validates changed files, implementation summary, verification evidence, done-check evidence, and context impact and blocks when any is missing. Check the consuming skill before shrinking any handoff field; user-facing layouts (`blocked`, `plan_complete`, `declined`, `incomplete`) are presentations, not handoffs, and stay whole. -- Claude ends a turn after a phase skill unless the rendered text says otherwise, so `config/pkl/renderers/` owns Claude-only turn-boundary text: append a `## Control flow` section to every Claude `SKILL.md` declaring the skill one phase of a workflow rather than a turn, and rewrite command continuation branches so that every step branching on a skill status carries exactly one `This step ends the turn only on {statuses}.` line, names the next skill or step, and states that the result is not workflow output. All four commands satisfy this invariant; a step whose only terminal branches are stop branches is the gap to look for. Keep this in the renderers; `config/pkl/base/workflow-*.pkl` stays target-agnostic and OpenCode and Pi output stays byte-identical. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Claude is the composition exception: its renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided Pi/OpenCode output remains byte-identical and every canonical gate, branch, write, and continuation retains one Claude owner. +- Claude commands must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. +- A Claude workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. - Validate each renderer module directly with `nix develop -c pkl eval ` before wiring output emission. ## Thin command orchestration -- Keep SCE command bodies thin when phase skills already define detailed contracts. -- For `/change-to-plan`, sequence `sce-context-load` before `sce-plan-authoring`; keep context loading, clarification, plan output, and `/next-task` handoff in their declared owners. -- For `/next-task`, retain one-task sequencing and confirmation gates while delegating phase details to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. -- For `/validate`, run `sce-validation` first and invoke `sce-plan-context-sync` only for a validated result. -- For `/commit`, delegate staged-diff analysis and commit-message construction to `sce-atomic-commit`, preserving regular proposal-only and explicit bypass behavior. -- Preserve mandatory gates and authoritative handoffs while removing duplicated phase instructions from agents or sibling skills. +- Keep OpenCode/Pi command bodies thin when phase skills define detailed contracts: `/change-to-plan` sequences context load then plan authoring; `/next-task` sequences review, execution, and task context sync; `/validate` sequences validation then validated-only plan context sync; `/commit` delegates staged-diff analysis to atomic commit. +- Keep Claude commands thinner still: parse nothing and invoke exactly one workflow-level skill. The composite skill owns input parsing, every phase, user waits, writes, verification, synchronization, and continuation rendering. +- Preserve mandatory gates and authoritative internal state while removing duplicated behavior from agents, commands, or sibling packages. ## Multi-file generation entrypoint @@ -89,7 +86,7 @@ - Encode internal-agent parity by target capability, not by forcing unsupported frontmatter keys. - Keep manual OpenCode Plan and Code agent bodies limited to routing to their approved commands; keep target permissions and presentation metadata in `config/pkl/renderers/opencode-metadata.pkl`. -- Do not generate Claude agents; Claude receives the canonical workflow commands and self-contained skill packages directly, with only supported command/skill metadata added by `config/pkl/renderers/claude-content.pkl`. +- Do not generate Claude agents; Claude receives four thin commands and four renderer-composed workflow skill packages, with supported command tools and one-to-one workflow-skill slugs owned under `config/pkl/renderers/`. - Keep parity decisions reproducible by validating generated outputs directly. ## Placeholder CLI scaffolding diff --git a/context/plans/claude-workflow-single-skill-packages.md b/context/plans/claude-workflow-single-skill-packages.md new file mode 100644 index 00000000..941b1a69 --- /dev/null +++ b/context/plans/claude-workflow-single-skill-packages.md @@ -0,0 +1,70 @@ +# Plan: claude-workflow-single-skill-packages + +## Change summary + +Replace Claude's multi-skill workflow rendering with one self-contained package per workflow. Each of `/change-to-plan`, `/next-task`, `/validate`, and `/commit` will have exactly one generated command entrypoint, one corresponding workflow skill, and one `references/output.md` document defining that workflow's user-visible Markdown return shapes. The skill's `SKILL.md` owns the complete phase sequence, internal status handling, user wait/resume gates, and final response rendering. + +This removes Claude's inter-skill handoff seam instead of trying to make structured phase results continue reliably. Canonical Pi and OpenCode workflows remain decomposed into their current eight skills, while Claude renders four workflow-level skills and no Claude phase-skill packages. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the check that proves it. `/validate` runs these checks; no task in the stack performs final validation. + +- [ ] AC1: Generated Claude contains exactly four workflow command entrypoints and four workflow skill packages, with every command invoking exactly one corresponding skill and no Claude command sequencing multiple skills. + - Validate: generate a temporary payload with `tmp="$(mktemp -d)"; nix run .#pkl-generate -- "$tmp"`; inspect `config/.claude/commands/` and `config/.claude/skills/` and assert a one-entrypoint-to-one-skill mapping for `change-to-plan`, `next-task`, `validate`, and `commit`. +- [ ] AC2: Every generated Claude workflow skill is self-contained: its `SKILL.md` owns all former phase behavior, status branching, approval or clarification waits, same-session resume behavior, plan/evidence writes, and workflow continuation rules without invoking any other SCE skill. + - Validate: inspect all four generated Claude `SKILL.md` files; confirm no `Skill` invocation targets a phase or sibling `sce-*` package and verify the former phase boundaries and terminal statuses remain represented inside the owning workflow skill. +- [ ] AC3: Every generated Claude workflow skill package contains exactly two files—`SKILL.md` and `references/output.md`—and `output.md` is the package's single reference document defining all and only that workflow's user-visible Markdown return and gate layouts. + - Validate: `find "$tmp/config/.claude/skills" -type f | sort`; assert exactly one `references/output.md` per package and no other reference, machine-contract, plan-template, result-contract, or sibling-package dependency files; inspect each `SKILL.md` branch against `output.md` and confirm every user-visible outcome names and follows one defined Markdown shape. +- [ ] AC4: Claude preserves the established workflow behavior despite package collapse: `/change-to-plan` loads context before authoring and supports clarification/revision; `/next-task` reviews one task, presents the implementation gate, waits for approval, executes, records evidence, and synchronizes task context; `/validate` validates only complete plans and synchronizes plan context only after success; `/commit` preserves regular proposal and explicit bypass modes. + - Validate: inspect the generated commands, four composite skills, and four output references against `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` and `workflow-context-sync.pkl`; verify every canonical gate, branch, and user-facing layout has one Claude owner. +- [ ] AC5: Exact metadata coverage enforces the four-command/four-skill/two-files-per-skill Claude inventory and rejects stale phase-skill packages or extra references. + - Validate: `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. +- [ ] AC6: OpenCode and Pi retain their canonical eight-skill packages, YAML phase contracts, command behavior, and generated content byte-for-byte. + - Validate: generate payloads from the implementation base and working tree, then run `diff -rq` over their `config/.opencode` and `config/.pi` trees; only Claude workflow Markdown may differ. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, and `context/context-map.md` to describe Claude's four workflow-level skill packages and the one-output-reference rule. +- Update `context/sce/shared-context-plan-workflow.md`, `context/sce/shared-context-code-workflow.md`, and `context/sce/atomic-commit-workflow.md` only where target-specific ownership needs clarification; preserve canonical Pi/OpenCode phase semantics. +- Add or update an architecture decision that supersedes the claim in `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` that Claude receives the same eight generated skill packages as Pi and OpenCode. + +## Constraints and non-goals + +- **In scope:** Claude renderer composition, four command entrypoints with one-to-one command-to-skill routing, four workflow-level `SKILL.md` documents, one Markdown-shape `references/output.md` per workflow, exact Claude inventory coverage, and affected generation documentation. +- **Out of scope:** Canonical Pi/OpenCode workflow decomposition, status or approval semantics, application runtime code, hooks/settings/plugins, generated repository target trees, or changes to the project-root `.pi/` baseline. +- **Constraints:** Author behavior from canonical `config/pkl/base/workflow-*.pkl` and `workflow-context-sync.pkl`; implement the collapse only in `config/pkl/renderers/`; preserve all user decision points and same-session resume behavior; keep each generated Claude workflow package independent of every sibling package. +- **Non-goal:** Preserve machine-readable inter-phase result contracts inside Claude. Those contracts exist to cross phase boundaries that the composite Claude skills remove; retain only internal state and branching instructions needed to execute the workflow correctly. + +## Assumptions + +- The four Claude workflow skill slugs may be normalized to workflow-level names such as `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`; exact names follow existing naming conventions as long as the command mapping is unambiguous. +- `references/output.md` may contain multiple exact Markdown layouts for different statuses or user gates, but it is the package's only reference file and contains no inter-skill machine handoff contract. +- The composite skill directly renders user-facing workflow output according to `references/output.md`. The command is a thin entrypoint and does not consume a structured result from the skill after invocation. +- Wait points remain real turn boundaries inside the composite skill: bootstrap, clarification, plan revision, implementation approval, blocked/incomplete execution, and failed validation resume in the same workflow session where the canonical behavior requires it. +- `/commit` already has one behavioral skill, but it is normalized to the same workflow-package shape and one `output.md` reference so Claude's inventory follows one rule. + +## Task stack + +- [x] T01: `Collapse Claude workflows into four self-contained skills` (status:done) + - Task ID: T01 + - Goal: Render each Claude workflow as one command entrypoint, one complete workflow skill, and one reference defining its Markdown output shapes while preserving canonical behavior and leaving Pi/OpenCode unchanged. + - Boundaries (in/out of scope): In — `config/pkl/renderers/claude-content.pkl`, `config/pkl/renderers/claude-workflow-results.pkl` or a replacement focused Claude composition module, `config/pkl/renderers/claude-metadata.pkl`, `config/pkl/renderers/metadata-coverage-check.pkl`, and directly affected Pkl generation documentation. Out — canonical workflow package edits for Claude-only behavior, Pi/OpenCode renderers or baselines, CLI runtime code, and unrelated generated assets. + - Dependencies: none + - Done when: Temporary generation emits four Claude command entrypoints and four two-file workflow skill packages; each entrypoint routes to one skill; each skill contains all former phase behavior and invokes no other SCE skill; each package has only `SKILL.md` plus `references/output.md`; every user-visible branch follows a Markdown shape defined by that reference; exact coverage rejects stale phase skills/references; base/current OpenCode and Pi trees are byte-identical. + - Verification notes (commands or checks): `nix develop -c pkl eval config/pkl/renderers/{claude-content,metadata-coverage-check}.pkl`; generate a temporary payload and inspect command/skill/reference inventories plus workflow gates; compare implementation-base/current OpenCode and Pi payload trees; `nix run .#pkl-check-generated`; `git diff --check -- config/pkl context/plans/claude-workflow-single-skill-packages.md`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/README.md`, `config/pkl/renderers/claude-content.pkl`, `config/pkl/renderers/claude-metadata.pkl`, `config/pkl/renderers/claude-workflow-results.pkl`, `config/pkl/renderers/metadata-coverage-check.pkl`, `context/plans/claude-workflow-single-skill-packages.md` + - Evidence: Both renderer evaluations passed; temporary generation produced four Claude commands and four two-file workflow packages with exact one-to-one routes and no phase-skill slug references; HEAD/current generated OpenCode and Pi trees were byte-identical; `nix run .#pkl-check-generated` passed with 72 files and inventory SHA-256 `8cbbdcdc903e677916de1ed8cbe6b90ec21666d04afe677bbb4514c6ee7a359c`; scoped `git diff --check` passed. + - Notes: Claude now keeps phase statuses as internal state within workflow-level skills; canonical Pi/OpenCode phase packages and contracts were not modified. + +## Open questions + +None. The requested architecture is explicit: Claude gets one skill and one output reference per workflow, while canonical phase decomposition remains available to Pi and OpenCode. diff --git a/context/sce/atomic-commit-workflow.md b/context/sce/atomic-commit-workflow.md index b3ff9aa0..723eb70b 100644 --- a/context/sce/atomic-commit-workflow.md +++ b/context/sce/atomic-commit-workflow.md @@ -1,27 +1,21 @@ # Atomic Commit Workflow -Behavior contract for the `/commit` workflow and its `sce-atomic-commit` skill -package. +Behavior contract for the generated `/commit` workflow. ## Current surface -The workflow currently exists only as the project-root `.pi/` behavioral -baseline: +Canonical behavior is authored in `config/pkl/base/workflow-commit.pkl` from the +project-root `.pi/` baseline and generated for OpenCode, Claude, and Pi. -- `.pi/prompts/commit.md` — the command. -- `.pi/skills/sce-atomic-commit/SKILL.md` — the skill. -- `.pi/skills/sce-atomic-commit/references/commit-contract.yaml` — the result - contract. -- `.pi/skills/sce-atomic-commit/references/commit-message-style.md` — the - message wording rules. +- Pi/OpenCode emit the canonical command plus the `sce-atomic-commit` phase + package, its YAML result contract, and commit-message style reference. +- Claude emits one thin command invoking `sce-commit`. The composite package + contains only `SKILL.md`, which owns mode routing, staged-diff analysis, + proposal/commit behavior, and internal statuses, plus `references/output.md`, + which owns all human-visible prompts and result layouts. -Canonical Pkl ownership and generated OpenCode/Claude/Pi payloads do not carry -it yet. Until they do, the emitted workflow inventory described in -[the ownership table](dedup-ownership-table.md) remains three commands and seven -skill packages. - -Per the root `.pi/` baseline convention in `context/patterns.md`, this package is -the authoring source for the canonical Pkl workflow package, not the reverse. +Claude's package invokes no `sce-atomic-commit` sibling skill; it embeds the +canonical phase behavior directly. ## Modes @@ -115,7 +109,7 @@ staged explicitly; bypass mode omits the citation instead of stopping. ## Result contract -The skill returns exactly one YAML result: +Pi/OpenCode's phase skill returns exactly one YAML result: - `proposal` — regular mode, one or more messages, optional split rationale and staged-scope classification. @@ -125,8 +119,10 @@ The skill returns exactly one YAML result: `no_staged_changes`, `plan_citation_ambiguity`, `unreadable_diff`, and `contradictory_context`. -Every staged file appears under exactly one returned commit. No result carries a -commit hash, because the skill never commits. +Claude keeps the equivalent status as internal `sce-commit` state and renders +only the applicable layout from `references/output.md`. Every staged file still +belongs to exactly one commit message. The analysis phase never reports a hash; +only successful bypass-mode `git commit` produces one. ## Related context diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index f2d4d692..cbd7d308 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -2,7 +2,7 @@ ## Purpose -The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. +The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. Pi/OpenCode retain phase-skill sequencing; Claude embeds each complete lifecycle in `sce-next-task` or `sce-validate`. ## `/next-task` entrypoint @@ -36,7 +36,7 @@ The implementation lifecycle executes at most one reviewed task per `/next-task` - Emits exactly one next-task command for the first unchecked task in plan order, or a `/validate` command when all implementation tasks are complete. - Never executes the continuation in the same invocation. -A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. +A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. On Claude, review, approval, execution, evidence recording, synchronization, and continuation are internal phases of one `sce-next-task` invocation rather than sibling skill calls. ## `/validate` entrypoint @@ -46,7 +46,7 @@ A context-sync blocker does not undo successful implementation: the task remains 2. Failed or blocked validation ends the session without repair edits; retry uses `/validate {plan-path}`. 3. `sce-plan-context-sync` runs only from a successful `Status: validated` handoff and reconciles the completed plan with durable repository context. -Final validation never runs from an individual implementation task. +On Claude, those validation and plan-sync phases execute inside one `sce-validate` skill; failed and blocked statuses stop before synchronization exactly as in the canonical flow. Final validation never runs from an individual implementation task. ## Flow @@ -68,9 +68,15 @@ flowchart TD M -- "No" --> O["Stop and retry /validate later"] ``` +## Target ownership + +- Pi/OpenCode: command sequencing plus the canonical review, execution, validation, and context-sync phase packages. +- Claude: thin commands invoking `sce-next-task` or `sce-validate`; each package contains only `SKILL.md` and `references/output.md`. + ## Canonical sources - `config/pkl/base/workflow-next-task.pkl` - `config/pkl/base/workflow-validate.pkl` - `config/pkl/base/workflow-context-sync.pkl` -- Generated baselines: `.pi/prompts/{next-task,validate}.md` +- Claude composition: `config/pkl/renderers/claude-workflow-results.pkl` +- Behavioral baselines: `.pi/prompts/{next-task,validate}.md` diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index 77ae2e95..46be1f92 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -2,7 +2,7 @@ ## Purpose -`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface for this command; workflow behavior belongs to the command and its two phase skills. +`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface. Pi/OpenCode behavior is owned by the command and two canonical phase skills; Claude renders the same behavior into the single `sce-change-to-plan` workflow skill. ## Command entrypoint @@ -23,7 +23,7 @@ The request must be non-empty. The workflow does not accept approval or executio - Creates or updates one plan with stable task IDs, explicit scope, dependencies, done checks, and verification notes. - Returns `plan_ready`, `needs_clarification`, or `blocked`. -The command forwards each phase result as the authoritative handoff rather than reconstructing it. +Pi/OpenCode forward each phase result as the authoritative handoff rather than reconstructing it. Claude keeps the equivalent status and data as internal state inside `sce-change-to-plan`; no sibling skill handoff exists. ## Bootstrap boundary @@ -57,8 +57,13 @@ flowchart TD F -- "plan_ready" --> I["Emit /next-task handoff"] ``` +## Target ownership + +- Pi/OpenCode: command sequencing plus `sce-context-load` and `sce-plan-authoring` packages. +- Claude: one thin command invoking `sce-change-to-plan`; package files are `SKILL.md` and `references/output.md`. + ## Canonical sources - `config/pkl/base/workflow-change-to-plan.pkl` -- Generated baseline: `.pi/prompts/change-to-plan.md` -- Skills: `sce-context-load`, `sce-plan-authoring` +- Claude composition: `config/pkl/renderers/claude-workflow-results.pkl` +- Behavioral baseline: `.pi/prompts/change-to-plan.md` From fa204e313fd8fca1b9c2e53273d7a7f19cb5e365 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 16:17:58 +0200 Subject: [PATCH 14/21] config: Promote the Claude composite renderer to a shared module Workflow composition lived in `claude-workflow-results.pkl`, which imported Claude metadata directly and hardcoded `compatibility: claude` and the `allowed-tools:` frontmatter line into its skill and command renderers. Pi and OpenCode cannot reuse it in that shape, so collapsing them to workflow-level packages would mean duplicating the phase internalization tables and output layouts per target and guaranteeing drift between texts meant to be identical. Rename the module to `workflow-composite.pkl` and make it target-neutral: `ClaudeWorkflow` becomes `CompositeWorkflow`, the command-to-workflow-skill slug mapping moves here from `claude-metadata.pkl`, and `renderSkill`, `renderCommand`, and `skillDocuments` each take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a target supports. Claude now passes `compatibility: claude` and its `allowed-tools` line at the call site and re-exports the shared slug mapping, so its generated bytes are unchanged while Pi and OpenCode gain a consumable entrypoint. Co-authored-by: SCE --- config/pkl/renderers/claude-content.pkl | 6 +- config/pkl/renderers/claude-metadata.pkl | 13 +- ...low-results.pkl => workflow-composite.pkl} | 57 +++-- context/architecture.md | 7 +- ...-07-27-workflow-oriented-pkl-generation.md | 2 +- ...26-07-29-claude-workflow-skill-packages.md | 2 +- context/glossary.md | 2 + context/patterns.md | 3 +- ...opencode-workflow-single-skill-packages.md | 235 ++++++++++++++++++ context/sce/shared-context-code-workflow.md | 2 +- context/sce/shared-context-plan-workflow.md | 2 +- 11 files changed, 291 insertions(+), 40 deletions(-) rename config/pkl/renderers/{claude-workflow-results.pkl => workflow-composite.pkl} (89%) create mode 100644 context/plans/pi-opencode-workflow-single-skill-packages.md diff --git a/config/pkl/renderers/claude-content.pkl b/config/pkl/renderers/claude-content.pkl index a5fce0ce..407f6495 100644 --- a/config/pkl/renderers/claude-content.pkl +++ b/config/pkl/renderers/claude-content.pkl @@ -1,6 +1,6 @@ import "common.pkl" as common import "claude-metadata.pkl" as metadata -import "claude-workflow-results.pkl" as workflowResults +import "workflow-composite.pkl" as workflowResults local missingSceInstallMessage = "sce CLI not found. Install it from https://sce.crocoder.dev/docs/getting-started#install-cli" @@ -88,14 +88,14 @@ exec "$@" /// workflow skill, which owns all phases, waits, and final response rendering. commands { for (slug, workflow in workflowResults.workflows) { - [slug] = workflowResults.renderCommand.apply(workflow, metadata.commandAllowedTools[slug]) + [slug] = workflowResults.renderCommand.apply(workflow, "allowed-tools: \(metadata.commandAllowedTools[slug])\n") } } /// Claude has four workflow packages, each with exactly SKILL.md and one /// references/output.md presentation contract. skillDocuments { - for (path, document in workflowResults.skillDocuments) { + for (path, document in workflowResults.skillDocuments.apply("compatibility: claude\n")) { [path] = document } } diff --git a/config/pkl/renderers/claude-metadata.pkl b/config/pkl/renderers/claude-metadata.pkl index 755282f9..6effbaac 100644 --- a/config/pkl/renderers/claude-metadata.pkl +++ b/config/pkl/renderers/claude-metadata.pkl @@ -1,3 +1,5 @@ +import "workflow-composite.pkl" as composite + commandAllowedTools = new Mapping { ["next-task"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" ["change-to-plan"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" @@ -5,11 +7,6 @@ commandAllowedTools = new Mapping { ["commit"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" } -/// One command routes to one workflow-level package. Phase-skill names are not -/// part of Claude's generated inventory. -workflowSkillSlugByCommand = new Mapping { - ["change-to-plan"] = "sce-change-to-plan" - ["next-task"] = "sce-next-task" - ["validate"] = "sce-validate" - ["commit"] = "sce-commit" -} +/// The workflow slugs are target-neutral; Claude re-exports the shared mapping +/// so command routing and coverage checks read it from one place. +workflowSkillSlugByCommand = composite.workflowSkillSlugByCommand diff --git a/config/pkl/renderers/claude-workflow-results.pkl b/config/pkl/renderers/workflow-composite.pkl similarity index 89% rename from config/pkl/renderers/claude-workflow-results.pkl rename to config/pkl/renderers/workflow-composite.pkl index de747669..60489951 100644 --- a/config/pkl/renderers/claude-workflow-results.pkl +++ b/config/pkl/renderers/workflow-composite.pkl @@ -3,12 +3,12 @@ import "../base/workflow-next-task.pkl" as nextTask import "../base/workflow-validate.pkl" as validate import "../base/workflow-commit.pkl" as commit import "../base/workflow-content.pkl" as model -import "claude-metadata.pkl" as metadata -/// Claude executes a skill as the unit of durable control flow. Compose the -/// canonical phase packages into one workflow package instead of asking a -/// command to transport phase results between sibling skills. -class ClaudeWorkflow { +/// A skill is the unit of durable control flow. Compose the canonical phase +/// packages into one workflow package instead of asking a command to transport +/// phase results between sibling skills. Composition is target-neutral: targets +/// differ only in the frontmatter lines their skills and commands support. +class CompositeWorkflow { slug: String skillSlug: String title: String @@ -103,15 +103,17 @@ local renderPhase = (slug: String, document: model.WorkflowDocument) -> local renderInternalDocument = (title: String, document: model.WorkflowDocument) -> "## Internal persisted-document format: \(title)\n\n" + internalize.apply(document.text) -local renderSkill = (workflow: ClaudeWorkflow) -> new model.WorkflowDocument { +/// `extraFrontmatterLines` carries the target-specific frontmatter a skill +/// entrypoint supports. Each line ends with a newline; a target that adds none +/// passes the empty string. +local renderSkill = (workflow: CompositeWorkflow, extraFrontmatterLines: String) -> new model.WorkflowDocument { path = "SKILL.md" text = """ --- name: \(workflow.skillSlug) description: > \(workflow.description) -compatibility: claude ---- +\(extraFrontmatterLines)--- # \(workflow.title) @@ -147,14 +149,16 @@ as the workflow's final response. """ } -renderCommand = (workflow: ClaudeWorkflow, allowedTools: String) -> new model.WorkflowDocument { +/// `extraFrontmatterLines` carries the target-specific routing frontmatter a +/// command supports, under the same newline-terminated convention as +/// `renderSkill`. +renderCommand = (workflow: CompositeWorkflow, extraFrontmatterLines: String) -> new model.WorkflowDocument { path = workflow.command.path text = """ --- description: "\(workflow.description)" argument-hint: "\(workflow.argumentHint)" -allowed-tools: \(allowedTools) ---- +\(extraFrontmatterLines)--- Invoke the `\(workflow.skillSlug)` skill exactly once with `$ARGUMENTS`. The skill owns the complete workflow, including all waits and same-session resume @@ -439,9 +443,18 @@ Committed {commit-hash} Present Git's failure unchanged and stop without retrying. """ -local changeWorkflow = new ClaudeWorkflow { +/// One command routes to one workflow-level package. Phase-skill names are not +/// part of any target's generated inventory. +workflowSkillSlugByCommand = new Mapping { + ["change-to-plan"] = "sce-change-to-plan" + ["next-task"] = "sce-next-task" + ["validate"] = "sce-validate" + ["commit"] = "sce-commit" +} + +local changeWorkflow = new CompositeWorkflow { slug = "change-to-plan" - skillSlug = metadata.workflowSkillSlugByCommand["change-to-plan"] + skillSlug = workflowSkillSlugByCommand["change-to-plan"] title = "SCE Change to Plan" description = "Turn one change request into a scoped SCE plan in one self-contained workflow" argumentHint = "" @@ -456,9 +469,9 @@ local changeWorkflow = new ClaudeWorkflow { outputText = internalize.apply(CHANGE_OUTPUT + "\n\n" + changeToPlan.workflow.skills["sce-plan-authoring"].documents["references/plan-summary.md"].text) } -local nextWorkflow = new ClaudeWorkflow { +local nextWorkflow = new CompositeWorkflow { slug = "next-task" - skillSlug = metadata.workflowSkillSlugByCommand["next-task"] + skillSlug = workflowSkillSlugByCommand["next-task"] title = "SCE Next Task" description = "Review, approve, implement, verify, and synchronize one SCE plan task" argumentHint = " [T0X] [approved]" @@ -472,9 +485,9 @@ local nextWorkflow = new ClaudeWorkflow { outputText = internalize.apply(NEXT_OUTPUT + "\n\n" + nextTask.workflow.skills["sce-task-execution"].documents["references/implementation-gate.md"].text + "\n\n" + nextTask.workflow.skills["sce-task-context-sync"].documents["references/sync-report.md"].text) } -local validateWorkflow = new ClaudeWorkflow { +local validateWorkflow = new CompositeWorkflow { slug = "validate" - skillSlug = metadata.workflowSkillSlugByCommand["validate"] + skillSlug = workflowSkillSlugByCommand["validate"] title = "SCE Validate" description = "Validate one completed SCE plan and synchronize its durable context" argumentHint = "" @@ -489,9 +502,9 @@ local validateWorkflow = new ClaudeWorkflow { outputText = internalize.apply(VALIDATE_OUTPUT + "\n\n" + validate.workflow.skills["sce-validation"].documents["references/validation-result.md"].text + "\n\n" + validate.workflow.skills["sce-plan-context-sync"].documents["references/sync-report.md"].text) } -local commitWorkflow = new ClaudeWorkflow { +local commitWorkflow = new CompositeWorkflow { slug = "commit" - skillSlug = metadata.workflowSkillSlugByCommand["commit"] + skillSlug = workflowSkillSlugByCommand["commit"] title = "SCE Commit" description = "Analyze staged changes and run the regular or explicit bypass commit workflow" argumentHint = "[oneshot|skip] [commit context]" @@ -510,9 +523,11 @@ workflows = new Mapping { [commitWorkflow.slug] = commitWorkflow } -skillDocuments { +/// Each target renders the same two documents per workflow package and differs +/// only in the frontmatter its skill entrypoint carries. +skillDocuments = (extraSkillFrontmatterLines: String) -> new Mapping { for (_, workflow in workflows) { - ["\(workflow.skillSlug)/SKILL.md"] = renderSkill.apply(workflow) + ["\(workflow.skillSlug)/SKILL.md"] = renderSkill.apply(workflow, extraSkillFrontmatterLines) ["\(workflow.skillSlug)/references/output.md"] = new model.WorkflowDocument { path = "references/output.md" text = workflow.outputText diff --git a/context/architecture.md b/context/architecture.md index 64881489..7d1b5019 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -21,7 +21,7 @@ Current target renderer helper modules: - `config/pkl/renderers/opencode-content.pkl` - `config/pkl/renderers/claude-content.pkl` -- `config/pkl/renderers/claude-workflow-results.pkl` (Claude-only composition of canonical phases into four workflow-level skills and their single `references/output.md` presentation documents) +- `config/pkl/renderers/workflow-composite.pkl` (target-neutral composition of canonical phases into four workflow-level skills and their single `references/output.md` presentation documents, parameterized by the frontmatter lines each target supports) - `config/pkl/renderers/pi-content.pkl` - `config/pkl/renderers/common.pkl` - `config/pkl/renderers/opencode-metadata.pkl` @@ -37,11 +37,12 @@ The scaffold provides stable canonical content-unit identifiers and reusable tar Renderer modules apply target-specific metadata/frontmatter rules while reusing canonical content bodies: - The manual OpenCode renderer consumes the four canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. -- Claude renderer consumes the four canonical workflow packages as behavior sources but emits four target-specific workflow packages without generated agents: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command invokes exactly one corresponding workflow skill. `claude-workflow-results.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Claude settings and the hook helper remain separate retained outputs. +- Claude renderer consumes the four canonical workflow packages as behavior sources but emits four target-specific workflow packages without generated agents: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command invokes exactly one corresponding workflow skill. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Claude settings and the hook helper remain separate retained outputs. - Pi renderer consumes the four canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly four prompts to `config/.pi/prompts/{slug}.md` and eight self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). +- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions, the phase-internalization substitution tables, the four output layouts, and the target-neutral command-to-workflow-skill slug mapping. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and its `allowed-tools` line for commands. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). -- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and the exact command-to-workflow-skill slug mapping. Pi workflow documents own their supported frontmatter directly. +- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and re-exports the shared command-to-workflow-skill slug mapping from `workflow-composite.pkl`. Pi workflow documents own their supported frontmatter directly. - `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode/Pi's 21 multi-file skill documents, Claude's four two-file workflow packages, and two OpenCode agents—then verifies every Claude command's one-to-one workflow-skill route and forces every rendered document and target metadata lookup to evaluate. - OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; Claude's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. - `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete phase-skill packages with nested references, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four workflow prompts, eight complete phase-skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. diff --git a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md index 522ae7d4..7d057689 100644 --- a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md +++ b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md @@ -23,7 +23,7 @@ The automated profile and obsolete Markdown catalog represented a second behavio ## Consequences -- Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`; Claude phase-result overrides live in `config/pkl/renderers/claude-workflow-results.pkl`. +- Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`; Claude phase-result overrides live in `config/pkl/renderers/claude-workflow-results.pkl` (since promoted to the target-neutral `config/pkl/renderers/workflow-composite.pkl`). - Generated inventory is four commands and eight skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. - `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/check-generated.sh`, and the root flake parity check enforce exact inventories, nested package references, and forbidden removed trees. - `config/automated/.opencode` and `config/.claude/agents` are forbidden outputs rather than compatibility surfaces. diff --git a/context/decisions/2026-07-29-claude-workflow-skill-packages.md b/context/decisions/2026-07-29-claude-workflow-skill-packages.md index 24370fbb..be6899f3 100644 --- a/context/decisions/2026-07-29-claude-workflow-skill-packages.md +++ b/context/decisions/2026-07-29-claude-workflow-skill-packages.md @@ -10,7 +10,7 @@ Supersedes in part: `2026-07-27-workflow-oriented-pkl-generation.md` - Keep the four canonical workflow definitions and eight phase-skill packages as the behavioral source for Pi and OpenCode. - Render Claude as exactly four thin commands and four workflow-level skills: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. - Route each Claude command to exactly one corresponding workflow skill. Claude commands do not sequence phase skills. -- Compose each Claude workflow skill from the canonical command, phase behavior, and context-sync policy in `config/pkl/renderers/claude-workflow-results.pkl`. +- Compose each Claude workflow skill from the canonical command, phase behavior, and context-sync policy in `config/pkl/renderers/claude-workflow-results.pkl` (since promoted to the target-neutral `config/pkl/renderers/workflow-composite.pkl`). - Keep phase statuses and phase-to-phase data as internal workflow state. A Claude workflow skill never invokes another SCE skill or sibling package. - Emit exactly two files per Claude package: `SKILL.md` and `references/output.md`. The latter is the sole package reference and owns all human-visible gates, reports, and terminal Markdown layouts. - Preserve Pi and OpenCode generated command behavior, eight-skill inventories, and phase contracts byte-for-byte. diff --git a/context/glossary.md b/context/glossary.md index bd653b56..51554144 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -10,6 +10,8 @@ - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. - `Claude workflow skill package`: One of the four renderer-composed Claude packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`). Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Pi and OpenCode retain the canonical eight phase-skill packages and their YAML handoff contracts. +- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite workflow definitions, the phase-internalization substitution tables, and the command-to-workflow-skill slug mapping. +- `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. - `Claude workflow output reference`: The required `references/output.md` in every Claude workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. diff --git a/context/patterns.md b/context/patterns.md index 198859b8..0658067a 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -54,7 +54,8 @@ - Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. -- Implement target-specific formatting and composition in dedicated renderer modules under `config/pkl/renderers/`. Keep canonical Pi/OpenCode YAML phase-result contracts and eight multi-file phase-package inventories unchanged. For Claude only, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. +- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Duplicating the internalization substitution tables per target would guarantee drift between targets whose composed text is meant to be identical. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. +- Keep canonical Pi/OpenCode YAML phase-result contracts and eight multi-file phase-package inventories unchanged. For Claude only, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi-compatible metadata remains in canonical workflow documents. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. diff --git a/context/plans/pi-opencode-workflow-single-skill-packages.md b/context/plans/pi-opencode-workflow-single-skill-packages.md new file mode 100644 index 00000000..2af6bcfd --- /dev/null +++ b/context/plans/pi-opencode-workflow-single-skill-packages.md @@ -0,0 +1,235 @@ +# Plan: pi-opencode-workflow-single-skill-packages + +## Change summary + +Pi and OpenCode currently consume the canonical SCE workflows as eight +phase-decomposed skill packages (`sce-context-load`, `sce-plan-authoring`, +`sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, +`sce-validation`, `sce-plan-context-sync`, `sce-atomic-commit`) with commands +that sequence phases and transport YAML phase-result contracts between sibling +packages. Claude was collapsed on 2026-07-29 into four thin commands plus four +workflow-level single-skill packages (`sce-change-to-plan`, `sce-next-task`, +`sce-validate`, `sce-commit`), each containing only `SKILL.md` and +`references/output.md`, composed in `config/pkl/renderers/claude-workflow-results.pkl`. + +This plan applies the same collapse to Pi and OpenCode. The composition logic in +`claude-workflow-results.pkl` is promoted to a target-neutral renderer that all +three targets consume, parameterized only by the per-target frontmatter each +target supports. After this change every target emits four commands (Pi: +prompts) and four two-file workflow packages; no target emits the eight phase +packages. The canonical workflow definitions in `config/pkl/base/workflow-*.pkl` +remain the single behavioral source and are unchanged — the phase packages stay +as authoring inputs to the composite renderer, they simply stop being a +generated output surface. + +OpenCode keeps its two thin routing agents (`2026-03-03-plan-code-agent-separation.md` +remains in force); their `skill:` permission allowlists collapse to the four new +workflow slugs. Claude's generated bytes must not change. + +## Acceptance criteria + +- [ ] AC1: Pi generates exactly four prompts and eight skill Markdown files — + `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, + each with exactly `SKILL.md` and `references/output.md` — and no + phase-skill package. + - Validate: `nix run .#pkl-generate -- "$(mktemp -d)"` then inspect + `config/.pi/skills` for exactly those eight paths and `config/.pi/prompts` + for exactly four files. +- [ ] AC2: OpenCode generates exactly four commands and the same eight skill + Markdown files under four packages, plus its two unchanged routing agents. + - Validate: same generation root; inspect `config/.opencode/skills`, + `config/.opencode/command`, and `config/.opencode/agent`. +- [ ] AC3: Each Pi prompt and OpenCode command routes to exactly its one + corresponding workflow skill and names no other workflow skill; OpenCode + command frontmatter declares that single skill as both entry skill and the + whole skill chain. + - Validate: `pkl eval config/pkl/renderers/metadata-coverage-check.pkl` — the + route assertion covers Pi and OpenCode, not only Claude. +- [ ] AC4: Claude's generated output is byte-identical to the pre-change output. + - Validate: generate into a temp root before the first commit of this plan and + after the last, then + `diff -r /config/.claude /config/.claude` reports no + differences. +- [ ] AC5: OpenCode routing agents allow exactly the four workflow skills and no + phase skill. + - Validate: inspect the generated `config/.opencode/agent/*.md` `permission.skill` + blocks for `sce-change-to-plan` (Plan) and `sce-next-task` / `sce-validate` / + `sce-commit` (Code), with no `sce-context-load`-style entries. +- [ ] AC6: Durable context describes the single-skill package model for all three + targets, and a decision record supersedes the Pi/OpenCode decomposition + claims in `2026-07-27-workflow-oriented-pkl-generation.md` and the + Pi/OpenCode preservation clause in `2026-07-29-claude-workflow-skill-packages.md`. + - Validate: read `context/decisions/`, `context/overview.md`, and + `context/sce/shared-context-{plan,code}-workflow.md`; no durable file still + claims Pi/OpenCode consume eight phase packages as current state. + +### Full validation + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- `context/overview.md` +- `context/context-map.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/sce/shared-context-plan-workflow.md` +- `context/sce/shared-context-code-workflow.md` +- `context/sce/atomic-commit-workflow.md` +- `context/sce/dedup-ownership-table.md` +- `context/sce/plan-code-overlap-map.md` +- `context/decisions/` (new record; annotate the two superseded records) + +## Constraints and non-goals + +- **In scope:** `config/pkl/renderers/` (composite renderer promotion, + `pi-content.pkl`, `opencode-content.pkl`, `opencode-metadata.pkl`, + `claude-content.pkl`, `metadata-coverage-check.pkl`), + `config/pkl/check-generated.sh` if required-path expectations change, and the + durable context files listed under Context sync. +- **Out of scope:** `config/pkl/base/workflow-*.pkl` canonical behavior. No gate, + wait, verification rule, or report layout changes wording as part of this + plan. Also out of scope: the Rust CLI, `sce setup`/`sce doctor`, OpenCode + plugins, the Pi extension, and generated settings/hooks. +- **Constraints:** Generated output stays deterministic and ephemeral. Claude + output must not change. OpenCode skill entrypoints keep their + `compatibility: opencode` frontmatter line; Pi documents keep no added + frontmatter, matching current per-target rendering. +- **Non-goal:** Introducing a general per-target packaging abstraction beyond the + three targets that exist. The composite renderer takes exactly the + parameters the three current targets need. + +## Assumptions + +- The composite renderer is shared rather than duplicated per target. Duplicating + the `internalize` substitution tables three times would guarantee drift between + targets whose behavior is meant to be identical. +- OpenCode retains its two thin routing agents. + `2026-03-03-plan-code-agent-separation.md` is in force and is independent of + how workflows are packaged; "similar to Claude" is read as the workflow + packaging model, not as removing OpenCode's agent layer. +- Stale installed phase-skill directories in existing checkouts are handled by + the existing setup remove-and-replace policy for the whole target directory + (`context/sce/setup-no-backup-policy-seam.md`); no migration code is planned. + +## Task stack + +- [x] T01: `Promote the Claude composite renderer to a shared target-neutral renderer` (status:done) + - Task ID: T01 + - Goal: Move the workflow-composition logic out of `claude-workflow-results.pkl` + into a target-neutral `config/pkl/renderers/workflow-composite.pkl` that + takes the per-target skill-frontmatter parameters, with Claude consuming it + and producing byte-identical output. + - Boundaries (in/out of scope): In — new shared renderer module, the four + `ClaudeWorkflow`-equivalent workflow definitions, `internalize`/`internalizePhase` + substitution tables, `renderSkill`/`renderCommand`, the four output-layout + strings, and `claude-content.pkl`/`claude-metadata.pkl` import updates. Out — + Pi and OpenCode renderers, coverage-check expectations, any wording change to + the composed text. + - Dependencies: none + - Done when: `config/pkl/renderers/workflow-composite.pkl` owns composition and + is parameterized by target; Claude renders through it; generating before and + after the change yields an identical `config/.claude` tree. + - Verification notes (commands or checks): generate into two temp roots across + the change and `diff -r` the `config/.claude` subtrees; `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-check-generated`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/renderers/workflow-composite.pkl` (renamed from + `config/pkl/renderers/claude-workflow-results.pkl`), + `config/pkl/renderers/claude-content.pkl`, + `config/pkl/renderers/claude-metadata.pkl`, + `context/plans/pi-opencode-workflow-single-skill-packages.md` + - Evidence: Composition, the substitution tables, the four output layouts, the + four workflow definitions, and the target-neutral `workflowSkillSlugByCommand` + now live in `workflow-composite.pkl`; `renderSkill` and `renderCommand` take a + newline-terminated `extraFrontmatterLines` parameter and `skillDocuments` is a + function of the target's extra skill frontmatter. Claude passes + `compatibility: claude` and `allowed-tools: …`. `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl` passed; generation into temp + roots before and after the change gave `diff -r` with no differences for + `config/.claude` and for the whole tree (Pi and OpenCode unchanged); + `nix develop -c ./config/pkl/check-generated.sh` passed with 72 files and + inventory SHA-256 `46651558b7eafffbbcb407d77a3fe2a6bbe929ae9a8aa25950c6f8e726e0f6cb`. + - Notes: `claude-workflow-results.pkl` was removed rather than kept as an + adapter; `claude-metadata.pkl` re-exports the shared slug mapping so + `metadata-coverage-check.pkl` needed no edit. + +- [ ] T02: `Render Pi as four thin prompts and four workflow skill packages` (status:todo) + - Task ID: T02 + - Goal: Emit Pi's workflows as four prompts each routing to exactly one + workflow skill, plus four packages containing only `SKILL.md` and + `references/output.md`. + - Boundaries (in/out of scope): In — `pi-content.pkl`, Pi's slug mapping, and + the Pi inventory plus command-route expectations in + `metadata-coverage-check.pkl` (generalizing `assertClaudeCommandRoute` to + take a target label). Out — OpenCode renderers and expectations, Claude, + `check-generated.sh` unless a required path breaks. + - Dependencies: T01 + - Done when: generated `config/.pi/skills` contains exactly the eight paths for + the four workflow packages, `config/.pi/prompts` contains exactly four + single-skill prompts, and the coverage check asserts the Pi inventory and Pi + routes and passes. + - Verification notes (commands or checks): `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-generate -- + "$(mktemp -d)"` then list `config/.pi/skills` and `config/.pi/prompts`; + `nix run .#pkl-check-generated`. + +- [ ] T03: `Render OpenCode as four thin commands and four workflow skill packages` (status:todo) + - Task ID: T03 + - Goal: Emit OpenCode's workflows as four commands whose frontmatter declares + one entry skill and a one-entry skill chain, plus four two-file packages + carrying `compatibility: opencode`, and narrow both routing agents' + `skill:` permission allowlists to the four workflow slugs. + - Boundaries (in/out of scope): In — `opencode-content.pkl` + (`commandSkillMetadataBySlug`, `renderCommand`, `renderSkillDocument`, + skill-document flattening), `opencode-metadata.pkl` permission blocks, the + OpenCode inventory and route expectations in `metadata-coverage-check.pkl`, + and removal of the now-unused `expectedCanonicalSkillDocumentPaths` set. Out + — agent names, descriptions, colors, and bodies; OpenCode plugins and + `opencode.json`. + - Dependencies: T02 + - Done when: generated `config/.opencode/skills` contains exactly the eight + workflow-package paths, each command routes to exactly its one skill, both + agents allow exactly the four workflow skills, and the coverage check asserts + the OpenCode inventory and routes and passes. + - Verification notes (commands or checks): `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-generate -- + "$(mktemp -d)"` then inspect `config/.opencode/{skills,command,agent}`; + `nix run .#pkl-check-generated`; `nix flake check`. + +- [ ] T04: `Record the cross-target single-skill decision and realign durable context` (status:todo) + - Task ID: T04 + - Goal: Add a decision record establishing single-skill workflow packages for + all three targets, mark the superseded scope in the two prior records, and + update the durable context files that still describe Pi/OpenCode phase + decomposition as current state. + - Boundaries (in/out of scope): In — a new `context/decisions/` record, + superseded-scope notes in `2026-07-27-workflow-oriented-pkl-generation.md` + and `2026-07-29-claude-workflow-skill-packages.md`, and the files listed + under Context sync. Out — plan files under `context/plans/`, historical + reference documents, and any renderer or generation change. + - Dependencies: T03 + - Done when: the new decision record exists with rationale and consequences; + both prior records name what this supersedes; and no durable context file + outside `context/plans/` still states Pi or OpenCode consume eight phase + packages as current behavior. + - Verification notes (commands or checks): `grep -rn + "sce-context-load\|sce-plan-review\|sce-atomic-commit" context/ --include=*.md` + and confirm every remaining hit is a plan file, a historical record, or an + explicit superseded/authoring-source reference; `nix flake check`. + +## Open questions + +- The Claude collapse was justified by a Claude-specific failure mode: a phase + result returned through one skill can become the apparent deliverable and end + the turn, so a command sequencing sibling skills is an unreliable transport. + Do Pi and OpenCode actually exhibit that failure? If they do not, this trades + away explicit phase contracts and eight independently-loadable packages for + four large `SKILL.md` files, and buys only cross-target uniformity. Worth + saying which one you have observed breaking — that answer does not change the + task stack, but it belongs in the decision record's rationale. +- OpenCode's routing agents are kept and their allowlists narrowed. If the intent + of "similar to Claude" extends to Claude's no-generated-agents posture, say so + and T03 grows to remove `config/.opencode/agent` and retire + `2026-03-03-plan-code-agent-separation.md`. diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index cbd7d308..46bb18ef 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -78,5 +78,5 @@ flowchart TD - `config/pkl/base/workflow-next-task.pkl` - `config/pkl/base/workflow-validate.pkl` - `config/pkl/base/workflow-context-sync.pkl` -- Claude composition: `config/pkl/renderers/claude-workflow-results.pkl` +- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude consumes it) - Behavioral baselines: `.pi/prompts/{next-task,validate}.md` diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index 46be1f92..cdf12c35 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -65,5 +65,5 @@ flowchart TD ## Canonical sources - `config/pkl/base/workflow-change-to-plan.pkl` -- Claude composition: `config/pkl/renderers/claude-workflow-results.pkl` +- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude consumes it) - Behavioral baseline: `.pi/prompts/change-to-plan.md` From 2fc64fd3b598c0557386aa2a9044a73aa569e9f4 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 16:28:30 +0200 Subject: [PATCH 15/21] config: Render Pi as thin prompts and workflow skill packages Pi consumed the canonical phase packages directly, emitting four prompts carrying full command bodies plus eight self-contained phase-skill packages. That left Pi on a different composition model than Claude, even though neither target adds target-specific frontmatter, so the composite renderer was duplicated work waiting to happen. pi-content.pkl now renders through the shared workflow-composite.pkl, passing an empty extra-frontmatter string for both prompts and skills. Pi emits four thin prompts, each routing to exactly one workflow skill, and four packages containing only SKILL.md and references/output.md. The coverage check drops its Claude-specific naming: the expected skill mapping and document paths become target-neutral, assertClaudeCommandRoute becomes assertCommandRoute(target, slug, document), and four Pi route checks are added so Pi prompts are held to the same one-skill routing rule as Claude commands. OpenCode keeps the canonical phase packages and byte-identical output. Co-authored-by: SCE --- .../pkl/renderers/metadata-coverage-check.pkl | 31 +++++++++------- config/pkl/renderers/pi-content.pkl | 36 +++++++------------ context/architecture.md | 14 ++++---- context/context-map.md | 8 ++--- context/glossary.md | 12 +++---- context/overview.md | 8 ++--- context/patterns.md | 10 +++--- ...opencode-workflow-single-skill-packages.md | 26 +++++++++++++- context/sce/atomic-commit-workflow.md | 6 ++-- context/sce/plan-code-overlap-map.md | 2 +- context/sce/shared-context-code-workflow.md | 12 +++---- context/sce/shared-context-plan-workflow.md | 10 +++--- 12 files changed, 97 insertions(+), 78 deletions(-) diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index c0e6ac63..a553da55 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -15,7 +15,7 @@ local expectedAgentSlugs = Set( "shared-context-code" ) -local expectedClaudeSkillByCommand = claudeMetadata.workflowSkillSlugByCommand +local expectedWorkflowSkillByCommand = claudeMetadata.workflowSkillSlugByCommand local expectedCanonicalSkillDocumentPaths = Set( "sce-atomic-commit/SKILL.md", @@ -41,10 +41,10 @@ local expectedCanonicalSkillDocumentPaths = Set( "sce-validation/references/validation-result.md" ) -/// Claude collapses each workflow into one package with one entrypoint and one -/// user-visible Markdown output reference. Exact coverage rejects stale phase -/// packages and any additional package-local references. -local expectedClaudeSkillDocumentPaths = Set( +/// A collapsed target renders each workflow as one package with one entrypoint +/// and one user-visible Markdown output reference. Exact coverage rejects stale +/// phase packages and any additional package-local references. +local expectedWorkflowSkillDocumentPaths = Set( "sce-change-to-plan/SKILL.md", "sce-change-to-plan/references/output.md", "sce-next-task/SKILL.md", @@ -98,27 +98,32 @@ local assertExactKeys = (actual: Mapping, expected: Set, label: String) ) "\(label): complete" else error("\(label) inventory does not match the canonical workflow matrix") -local assertClaudeCommandRoute = (slug: String, document: String) -> - let (expectedInvocation = "Invoke the `\(expectedClaudeSkillByCommand[slug])` skill exactly once") +/// Routing is target-neutral: every collapsed target's command names exactly its +/// own workflow skill and no other. `target` labels which one is being checked. +local assertCommandRoute = (target: String, slug: String, document: String) -> + let (expectedInvocation = "Invoke the `\(expectedWorkflowSkillByCommand[slug])` skill exactly once") if ( document.contains(expectedInvocation) - && expectedClaudeSkillByCommand.every((otherSlug, skillSlug) -> + && expectedWorkflowSkillByCommand.every((otherSlug, skillSlug) -> otherSlug == slug || !document.contains("`\(skillSlug)`") ) - ) "Claude \(slug) command route: complete" - else error("Claude \(slug) command must invoke exactly its corresponding workflow skill") + ) "\(target) \(slug) command route: complete" + else error("\(target) \(slug) command must invoke exactly its corresponding workflow skill") inventoryChecks { ["opencode-agents"] = assertExactKeys.apply(opencodeAgents, expectedAgentSlugs, "OpenCode agent") ["opencode-commands"] = assertExactKeys.apply(opencodeCommands, expectedCommandSlugs, "OpenCode command") ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedCanonicalSkillDocumentPaths, "OpenCode skill document") ["claude-commands"] = assertExactKeys.apply(claudeCommands, expectedCommandSlugs, "Claude command") - ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedClaudeSkillDocumentPaths, "Claude skill document") + ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedWorkflowSkillDocumentPaths, "Claude skill document") for (slug, document in claudeCommands) { - ["claude-command-route-\(slug)"] = assertClaudeCommandRoute.apply(slug, document.text) + ["claude-command-route-\(slug)"] = assertCommandRoute.apply("Claude", slug, document.text) } ["pi-commands"] = assertExactKeys.apply(piCommands, expectedCommandSlugs, "Pi command") - ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedCanonicalSkillDocumentPaths, "Pi skill document") + ["pi-skill-documents"] = assertExactKeys.apply(piSkillDocuments, expectedWorkflowSkillDocumentPaths, "Pi skill document") + for (slug, document in piCommands) { + ["pi-command-route-\(slug)"] = assertCommandRoute.apply("Pi", slug, document.text) + } } /// Force rendering after exact inventory checks so target-specific metadata diff --git a/config/pkl/renderers/pi-content.pkl b/config/pkl/renderers/pi-content.pkl index 7af64a01..3a535425 100644 --- a/config/pkl/renderers/pi-content.pkl +++ b/config/pkl/renderers/pi-content.pkl @@ -1,31 +1,21 @@ -import "../base/workflow-change-to-plan.pkl" as changeToPlan -import "../base/workflow-next-task.pkl" as nextTask -import "../base/workflow-validate.pkl" as validate -import "../base/workflow-commit.pkl" as commit - -/// Pi consumes the canonical workflow documents directly because those -/// documents are authored against the project-root `.pi/` baseline. -local workflows = new Listing { - changeToPlan.workflow - nextTask.workflow - validate.workflow - commit.workflow -} +import "workflow-composite.pkl" as workflowResults +/// Pi prompts are intentionally thin. Each routes to exactly one composite +/// workflow skill, which owns all phases, waits, and final response rendering. +/// Pi prompts carry no target-specific frontmatter beyond the shared +/// description and argument hint. commands { - for (workflow in workflows) { - [workflow.command.slug] = workflow.command.document + for (slug, workflow in workflowResults.workflows) { + [slug] = workflowResults.renderCommand.apply(workflow, "") } } -/// Flatten package-relative document paths for deterministic generation while -/// retaining each skill's self-contained directory layout. +/// Pi has four workflow packages, each with exactly SKILL.md and one +/// references/output.md presentation contract, and no target-specific skill +/// frontmatter. Package-relative document paths stay flattened for +/// deterministic generation while retaining each skill's directory layout. skillDocuments { - for (workflow in workflows) { - for (skillSlug, skillPackage in workflow.skills) { - for (documentPath, document in skillPackage.documents) { - ["\(skillSlug)/\(documentPath)"] = document - } - } + for (path, document in workflowResults.skillDocuments.apply("")) { + [path] = document } } diff --git a/context/architecture.md b/context/architecture.md index 7d1b5019..d5930cd1 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -38,14 +38,14 @@ Renderer modules apply target-specific metadata/frontmatter rules while reusing - The manual OpenCode renderer consumes the four canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. - Claude renderer consumes the four canonical workflow packages as behavior sources but emits four target-specific workflow packages without generated agents: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command invokes exactly one corresponding workflow skill. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Claude settings and the hook helper remain separate retained outputs. -- Pi renderer consumes the four canonical workflow packages directly because their command and skill documents already carry Pi-compatible frontmatter. It emits exactly four prompts to `config/.pi/prompts/{slug}.md` and eight self-contained Agent Skills packages under `config/.pi/skills/{slug}/`, including nested `references/`; it emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). +- Pi renderer consumes the same shared workflow composition as Claude and emits four workflow-level packages rather than phase packages. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). - Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions, the phase-internalization substitution tables, the four output layouts, and the target-neutral command-to-workflow-skill slug mapping. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and its `allowed-tools` line for commands. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). -- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and re-exports the shared command-to-workflow-skill slug mapping from `workflow-composite.pkl`. Pi workflow documents own their supported frontmatter directly. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode/Pi's 21 multi-file skill documents, Claude's four two-file workflow packages, and two OpenCode agents—then verifies every Claude command's one-to-one workflow-skill route and forces every rendered document and target metadata lookup to evaluate. -- OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; Claude's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. -- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete phase-skill packages with nested references, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four workflow prompts, eight complete phase-skill packages with nested references, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. +- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and re-exports the shared command-to-workflow-skill slug mapping from `workflow-composite.pkl`. Pi has no metadata module because it adds no target-specific frontmatter. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode's 21 multi-file phase-skill documents, Claude's and Pi's four two-file workflow packages each, and two OpenCode agents—then verifies every Claude and Pi command's one-to-one workflow-skill route through one target-labelled route assertion, and forces every rendered document and target metadata lookup to evaluate. +- OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; the Claude and Pi flattened inventories contain only `SKILL.md` and `references/output.md` for each workflow slug. +- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete phase-skill packages with nested references, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four thin workflow prompts, four two-file workflow skill packages, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. - `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. @@ -186,6 +186,6 @@ Shared Context Plan and Shared Context Code remain separate architectural roles. - `/change-to-plan` and `/next-task` remain separate command entrypoints aligned to those roles. - Reuse is handled through shared canonical guidance blocks and skill-owned phase contracts, not by collapsing both roles into one agent. - OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole behavior owners. -- Canonical Pi/OpenCode `/change-to-plan` sequences `sce-context-load` and `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` and validated-only `sce-plan-context-sync`; `/commit` sequences around `sce-atomic-commit`. -- Claude embeds those same phase boundaries inside `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, so no Claude command or workflow skill invokes a phase or sibling SCE package. +- The canonical `/change-to-plan` workflow sequences `sce-context-load` and `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` and validated-only `sce-plan-context-sync`; `/commit` sequences around `sce-atomic-commit`. OpenCode still consumes those phase packages as its generated inventory. +- Claude and Pi embed those same phase boundaries inside `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, so no Claude or Pi command or workflow skill invokes a phase or sibling SCE package. - OpenCode, Claude, and Pi expose the generated `/commit` workflow but no generated `/handover` command; the automated OpenCode profile is removed. diff --git a/context/context-map.md b/context/context-map.md index e016185a..28f07396 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -22,12 +22,12 @@ Feature/domain context: - `context/cli/capability-traits.md` (current broad CLI capability seam in `cli/src/services/capabilities.rs`, including `FsOps`/`StdFsOps`, `GitOps`/`ProcessGitOps`, git root/hooks resolution behavior, compile-time-typed borrowed AppContext wiring with associated-type narrow capability accessors plus `ContextWithRepoRoot` repo-root-scoped context derivation, generic command execution bounds, and test-only unimplemented stubs; current service internals do not consume fs/git traits until later lifecycle migration tasks) - `context/cli/service-lifecycle.md` (current compile-safe lifecycle seam in `cli/src/services/lifecycle.rs`, including default no-op `ServiceLifecycle` diagnose/fix/setup methods against narrow `HasRepoRoot`, lifecycle-owned health/fix/setup result types with generic setup messages, doctor/setup adapter boundaries, the static `LifecycleProvider` enum catalog/dispatcher, hook/config/local_db/auth_db/agent_trace_db lifecycle providers including setup-time repository-scoped Agent Trace DB initialization plus checkout identity diagnostics, implemented doctor aggregation over diagnose/fix providers, and implemented setup aggregation over `setup` providers in order config → local_db → auth_db → agent_trace_db → hooks when requested) - `context/sce/cli-observability-contract.md` (implemented config-backed runtime observability contract for the flat logging config-file shape with env-over-config fallback, concrete logger/telemetry runtime behavior plus logger and object-safe telemetry trait boundaries, AppContext observability wiring, generic `RunOutcome` final rendering, runtime-classified repeated telemetry action protection, operator-facing `sce config show` observability reporting, and the trimmed `sce config validate` status-only validation surface) -- `context/sce/shared-context-code-workflow.md` (canonical `/next-task` and `/validate` lifecycles, including Pi/OpenCode phase ownership and Claude's single-skill `sce-next-task` / `sce-validate` composition) +- `context/sce/shared-context-code-workflow.md` (canonical `/next-task` and `/validate` lifecycles, including OpenCode phase ownership and the Claude/Pi single-skill `sce-next-task` / `sce-validate` composition) - `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, one-task/one-atomic-commit task slicing, and Claude's `sce-change-to-plan` ownership) - [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) - `context/sce/plan-code-overlap-map.md` (overlap matrix for thin OpenCode Plan/Code routing agents and workflow phase ownership; its original three-workflow inventory predates the generated `/commit` package) - `context/sce/dedup-ownership-table.md` (canonical owner-vs-consumer boundaries for workflow packages, phase skills, the shared sync skeleton, and thin OpenCode agents; its original three-workflow/seven-skill inventory predates generated `/commit` and `sce-atomic-commit`) -- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, staged-truth and plan-citation rules, canonical Pi/OpenCode `sce-atomic-commit` phase ownership, and Claude's composite `sce-commit` package) +- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, staged-truth and plan-citation rules, canonical OpenCode `sce-atomic-commit` phase ownership, and the Claude/Pi composite `sce-commit` package) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) @@ -83,8 +83,8 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` -- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (canonical workflow-oriented ownership and current Pi/OpenCode phase-package matrix; Claude inventory claims are superseded) -- `context/decisions/2026-07-29-claude-workflow-skill-packages.md` (Claude's four command-to-workflow-skill routes, two-file package rule, internal phase state, and Pi/OpenCode preservation) +- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (canonical workflow-oriented ownership and current OpenCode phase-package matrix; Claude and Pi inventory claims are superseded) +- `context/decisions/2026-07-29-claude-workflow-skill-packages.md` (Claude's four command-to-workflow-skill routes, two-file package rule, internal phase state, and its Pi/OpenCode preservation clause, whose Pi half is superseded) - `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes pre-Cargo generation, validated copying into Cargo `OUT_DIR`, and crates.io/Flatpak packaging fallbacks) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) diff --git a/context/glossary.md b/context/glossary.md index 51554144..c1185c61 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -8,11 +8,11 @@ - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. -- `Pi workflow package`: Generated Pi workflow surface consisting of one prompt in `config/.pi/prompts/` plus its self-contained Agent Skills packages under `config/.pi/skills/`, including package-local nested references. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. -- `Claude workflow skill package`: One of the four renderer-composed Claude packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`). Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Pi and OpenCode retain the canonical eight phase-skill packages and their YAML handoff contracts. +- `Pi workflow package`: Generated Pi workflow surface consisting of one thin prompt in `config/.pi/prompts/` plus the one workflow skill package under `config/.pi/skills/` that the prompt routes to, containing exactly `SKILL.md` and `references/output.md`. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. +- `workflow skill package`: One of the four renderer-composed packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`) emitted for Claude and Pi. Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Its only other file is `references/output.md`. OpenCode still retains the canonical eight phase-skill packages and their YAML handoff contracts. - `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite workflow definitions, the phase-internalization substitution tables, and the command-to-workflow-skill slug mapping. - `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. -- `Claude workflow output reference`: The required `references/output.md` in every Claude workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. +- `workflow output reference`: The required `references/output.md` in every workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. @@ -145,9 +145,9 @@ - `SCE dedup ownership table`: Context artifact at `context/sce/dedup-ownership-table.md` that assigns one canonical owner per shared behavior domain, lists reference-only consumers, and labels each overlap as `intentional/keep` or `dedup/remove`. - `shared context plan workflow`: Canonical workflow document at `context/sce/shared-context-plan-workflow.md` defining `/change-to-plan` planning flow, clarification gate semantics, readiness contract, and `/next-task` handoff format. - `SCE Plan/Code role separation`: Architecture decision recorded in `context/decisions/2026-03-03-plan-code-agent-separation.md` that keeps Shared Context Plan and Shared Context Code as separate OpenCode routing roles. The thin Plan agent routes to `/change-to-plan`; the thin Code agent routes to `/next-task` and `/validate`; canonical commands and skills own behavior. -- `next-task thin orchestration contract`: Canonical Pi/OpenCode `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; Claude embeds the same behavior in `sce-next-task` and routes its command directly to that one skill. -- `change-to-plan thin orchestration contract`: Canonical Pi/OpenCode `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`; Claude embeds the same behavior in `sce-change-to-plan` and routes its command directly to that one skill. -- `validate thin orchestration contract`: Canonical Pi/OpenCode `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`; Claude embeds the same behavior in `sce-validate` and routes its command directly to that one skill. +- `next-task thin orchestration contract`: Canonical `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-next-task` and route their command directly to that one skill. +- `change-to-plan thin orchestration contract`: Canonical `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-change-to-plan` and route their command directly to that one skill. +- `validate thin orchestration contract`: Canonical `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-validate` and route their command directly to that one skill. - `OpenCode command skill metadata`: Machine-readable frontmatter on the four generated OpenCode workflow commands, using `entry-skill` for the initial phase and `skills` for the complete ordered chain defined by `config/pkl/renderers/opencode-content.pkl`. - `one-task/one-atomic-commit planning contract`: `sce-plan-authoring` requirement that each executable plan task represents one coherent commit unit; broad multi-commit tasks must be split into sequential atomic tasks before execution handoff. - `agent trace historical reference docs`: Retained `context/sce/agent-trace-*.md` artifacts that describe the removed pre-v0.3 Agent Trace design and task slices; they are reference-only and do not describe the active local-hook runtime. diff --git a/context/overview.md b/context/overview.md index c47b42dc..156357e0 100644 --- a/context/overview.md +++ b/context/overview.md @@ -54,8 +54,8 @@ The current supported automated release target matrix is `x86_64-unknown-linux-m The downstream publish-stage implementation is now complete for both registries: `.github/workflows/publish-crates.yml` publishes the checked-in crate version after `.version`/tag/Cargo parity checks, and `.github/workflows/publish-npm.yml` publishes the checked-in npm package after `.version`/tag/npm parity checks plus verification of the canonical `sce-v-npm.tgz` GitHub release asset. The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. -Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four canonical commands and eight self-contained skill packages rather than in agent bodies. -The canonical Pi/OpenCode workflows remain phase-decomposed: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. +Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four canonical commands and OpenCode's eight self-contained phase-skill packages rather than in agent bodies. +The canonical workflow definitions remain phase-decomposed, and OpenCode still consumes them that way: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. Claude and Pi consume the same canonical definitions as authoring inputs but emit them composed into four workflow-level skill packages. Claude preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin Claude command invokes exactly one corresponding skill. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. Claude emits no phase-skill packages or inter-skill machine contracts. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. @@ -70,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Pi and OpenCode consume the canonical phase packages and result contracts directly, while Claude composes each full workflow into one target-specific skill and one `references/output.md` in the renderer layer. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. OpenCode consumes the canonical phase packages and result contracts directly, while Claude and Pi compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. @@ -102,7 +102,7 @@ Lightweight post-task verification baseline (required after each completed task) ## Cross-target parity -- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four prompts and eight self-contained phase-skill packages with no agent-role prompts. Manual OpenCode consumes the same phase packages as exactly four commands, eight skills, and two thin routing agents. Claude consumes exactly four thin commands and four workflow-level skill packages, each containing only `SKILL.md` and `references/output.md`, with no generated agents; its generated settings and hook helper remain. +- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four thin prompts and four workflow-level skill packages with no agent-role prompts. Manual OpenCode consumes the canonical phase packages as exactly four commands, eight skills, and two thin routing agents. Claude consumes exactly four thin commands and the same four workflow-level skill packages, with no generated agents; its generated settings and hook helper remain. Every workflow-level package contains only `SKILL.md` and `references/output.md`. - When capabilities differ, parity is implemented by supported target-specific behavior rather than forcing unsupported fields. ## Context navigation diff --git a/context/patterns.md b/context/patterns.md index 0658067a..f5a9adff 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -55,12 +55,12 @@ - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. - Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Duplicating the internalization substitution tables per target would guarantee drift between targets whose composed text is meant to be identical. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. -- Keep canonical Pi/OpenCode YAML phase-result contracts and eight multi-file phase-package inventories unchanged. For Claude only, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. +- Keep canonical OpenCode YAML phase-result contracts and its eight multi-file phase-package inventory unchanged. For Claude and Pi, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. -- Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi-compatible metadata remains in canonical workflow documents. +- Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi needs no metadata module because it adds no target-specific frontmatter. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. - Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path; run it whenever workflow documents or target metadata change. -- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Claude is the composition exception: its renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided Pi/OpenCode output remains byte-identical and every canonical gate, branch, write, and continuation retains one Claude owner. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Composition is the exception: a collapsed target's renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided every canonical gate, branch, write, and continuation retains exactly one owner in that skill and the targets that have not collapsed keep byte-identical output. - Claude commands must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. - A Claude workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. @@ -68,8 +68,8 @@ ## Thin command orchestration -- Keep OpenCode/Pi command bodies thin when phase skills define detailed contracts: `/change-to-plan` sequences context load then plan authoring; `/next-task` sequences review, execution, and task context sync; `/validate` sequences validation then validated-only plan context sync; `/commit` delegates staged-diff analysis to atomic commit. -- Keep Claude commands thinner still: parse nothing and invoke exactly one workflow-level skill. The composite skill owns input parsing, every phase, user waits, writes, verification, synchronization, and continuation rendering. +- Keep OpenCode command bodies thin when phase skills define detailed contracts: `/change-to-plan` sequences context load then plan authoring; `/next-task` sequences review, execution, and task context sync; `/validate` sequences validation then validated-only plan context sync; `/commit` delegates staged-diff analysis to atomic commit. +- Keep Claude commands and Pi prompts thinner still: parse nothing and invoke exactly one workflow-level skill. The composite skill owns input parsing, every phase, user waits, writes, verification, synchronization, and continuation rendering. - Preserve mandatory gates and authoritative internal state while removing duplicated behavior from agents, commands, or sibling packages. ## Multi-file generation entrypoint diff --git a/context/plans/pi-opencode-workflow-single-skill-packages.md b/context/plans/pi-opencode-workflow-single-skill-packages.md index 2af6bcfd..e1ab2524 100644 --- a/context/plans/pi-opencode-workflow-single-skill-packages.md +++ b/context/plans/pi-opencode-workflow-single-skill-packages.md @@ -155,7 +155,7 @@ workflow slugs. Claude's generated bytes must not change. adapter; `claude-metadata.pkl` re-exports the shared slug mapping so `metadata-coverage-check.pkl` needed no edit. -- [ ] T02: `Render Pi as four thin prompts and four workflow skill packages` (status:todo) +- [x] T02: `Render Pi as four thin prompts and four workflow skill packages` (status:done) - Task ID: T02 - Goal: Emit Pi's workflows as four prompts each routing to exactly one workflow skill, plus four packages containing only `SKILL.md` and @@ -174,6 +174,30 @@ workflow slugs. Claude's generated bytes must not change. config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-generate -- "$(mktemp -d)"` then list `config/.pi/skills` and `config/.pi/prompts`; `nix run .#pkl-check-generated`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/renderers/pi-content.pkl`, + `config/pkl/renderers/metadata-coverage-check.pkl`, + `context/plans/pi-opencode-workflow-single-skill-packages.md` + - Evidence: `pi-content.pkl` now renders through `workflow-composite.pkl`, + passing the empty extra-frontmatter string for both prompts and skills, so Pi + carries no target-specific frontmatter. In `metadata-coverage-check.pkl`, + `expectedClaudeSkillByCommand`/`expectedClaudeSkillDocumentPaths` became the + target-neutral `expectedWorkflowSkillByCommand`/`expectedWorkflowSkillDocumentPaths`, + `assertClaudeCommandRoute` became `assertCommandRoute(target, slug, document)`, + Pi's inventory expectation moved to the eight workflow-package paths, and + four Pi route checks were added. `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl` passed with all fifteen + inventory checks complete. Generation into a temp root produced exactly + `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit` under + `config/.pi/skills` with only `SKILL.md` and `references/output.md` each, and + exactly four files in `config/.pi/prompts`. `diff -r` against a pre-change + generation reported no differences for `config/.claude` or `config/.opencode`. + `nix run .#pkl-check-generated` passed with 59 files and inventory SHA-256 + `8036627716394f19e59b2fe7d8efca24f5d3dcd1bdf4d84556d7dd71cf580fd5`. + - Notes: `check-generated.sh` needed no edit; its required paths name the + `config/.pi/skills` and `config/.pi/prompts` directories, not per-package + paths. `expectedCanonicalSkillDocumentPaths` remains in use for OpenCode until + T03. - [ ] T03: `Render OpenCode as four thin commands and four workflow skill packages` (status:todo) - Task ID: T03 diff --git a/context/sce/atomic-commit-workflow.md b/context/sce/atomic-commit-workflow.md index 723eb70b..a8fcfbda 100644 --- a/context/sce/atomic-commit-workflow.md +++ b/context/sce/atomic-commit-workflow.md @@ -7,9 +7,9 @@ Behavior contract for the generated `/commit` workflow. Canonical behavior is authored in `config/pkl/base/workflow-commit.pkl` from the project-root `.pi/` baseline and generated for OpenCode, Claude, and Pi. -- Pi/OpenCode emit the canonical command plus the `sce-atomic-commit` phase +- OpenCode emits the canonical command plus the `sce-atomic-commit` phase package, its YAML result contract, and commit-message style reference. -- Claude emits one thin command invoking `sce-commit`. The composite package +- Claude and Pi emit one thin command invoking `sce-commit`. The composite package contains only `SKILL.md`, which owns mode routing, staged-diff analysis, proposal/commit behavior, and internal statuses, plus `references/output.md`, which owns all human-visible prompts and result layouts. @@ -109,7 +109,7 @@ staged explicitly; bypass mode omits the citation instead of stopping. ## Result contract -Pi/OpenCode's phase skill returns exactly one YAML result: +OpenCode's phase skill returns exactly one YAML result: - `proposal` — regular mode, one or more messages, optional split rationale and staged-scope classification. diff --git a/context/sce/plan-code-overlap-map.md b/context/sce/plan-code-overlap-map.md index 4e401649..ce984686 100644 --- a/context/sce/plan-code-overlap-map.md +++ b/context/sce/plan-code-overlap-map.md @@ -5,7 +5,7 @@ - Canonical packages: `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` - Shared synchronization skeleton: `config/pkl/base/workflow-context-sync.pkl` - Generated OpenCode routing agents and workflow commands under `config/.opencode/` -- Seven canonical phase skills rendered for OpenCode, Claude, and Pi +- Seven canonical phase skills, rendered as packages for OpenCode and composed into workflow skills for Claude and Pi ## Overlap matrix diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index 46bb18ef..f52dfa08 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -2,7 +2,7 @@ ## Purpose -The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. Pi/OpenCode retain phase-skill sequencing; Claude embeds each complete lifecycle in `sce-next-task` or `sce-validate`. +The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. OpenCode retains phase-skill sequencing; Claude and Pi embed each complete lifecycle in `sce-next-task` or `sce-validate`. ## `/next-task` entrypoint @@ -36,7 +36,7 @@ The implementation lifecycle executes at most one reviewed task per `/next-task` - Emits exactly one next-task command for the first unchecked task in plan order, or a `/validate` command when all implementation tasks are complete. - Never executes the continuation in the same invocation. -A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. On Claude, review, approval, execution, evidence recording, synchronization, and continuation are internal phases of one `sce-next-task` invocation rather than sibling skill calls. +A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. On Claude and Pi, review, approval, execution, evidence recording, synchronization, and continuation are internal phases of one `sce-next-task` invocation rather than sibling skill calls. ## `/validate` entrypoint @@ -46,7 +46,7 @@ A context-sync blocker does not undo successful implementation: the task remains 2. Failed or blocked validation ends the session without repair edits; retry uses `/validate {plan-path}`. 3. `sce-plan-context-sync` runs only from a successful `Status: validated` handoff and reconciles the completed plan with durable repository context. -On Claude, those validation and plan-sync phases execute inside one `sce-validate` skill; failed and blocked statuses stop before synchronization exactly as in the canonical flow. Final validation never runs from an individual implementation task. +On Claude and Pi, those validation and plan-sync phases execute inside one `sce-validate` skill; failed and blocked statuses stop before synchronization exactly as in the canonical flow. Final validation never runs from an individual implementation task. ## Flow @@ -70,13 +70,13 @@ flowchart TD ## Target ownership -- Pi/OpenCode: command sequencing plus the canonical review, execution, validation, and context-sync phase packages. -- Claude: thin commands invoking `sce-next-task` or `sce-validate`; each package contains only `SKILL.md` and `references/output.md`. +- OpenCode: command sequencing plus the canonical review, execution, validation, and context-sync phase packages. +- Claude and Pi: thin commands invoking `sce-next-task` or `sce-validate`; each package contains only `SKILL.md` and `references/output.md`. ## Canonical sources - `config/pkl/base/workflow-next-task.pkl` - `config/pkl/base/workflow-validate.pkl` - `config/pkl/base/workflow-context-sync.pkl` -- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude consumes it) +- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude and Pi consume it) - Behavioral baselines: `.pi/prompts/{next-task,validate}.md` diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index cdf12c35..6200fa3c 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -2,7 +2,7 @@ ## Purpose -`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface. Pi/OpenCode behavior is owned by the command and two canonical phase skills; Claude renders the same behavior into the single `sce-change-to-plan` workflow skill. +`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface. OpenCode behavior is owned by the command and two canonical phase skills; Claude and Pi render the same behavior into the single `sce-change-to-plan` workflow skill. ## Command entrypoint @@ -23,7 +23,7 @@ The request must be non-empty. The workflow does not accept approval or executio - Creates or updates one plan with stable task IDs, explicit scope, dependencies, done checks, and verification notes. - Returns `plan_ready`, `needs_clarification`, or `blocked`. -Pi/OpenCode forward each phase result as the authoritative handoff rather than reconstructing it. Claude keeps the equivalent status and data as internal state inside `sce-change-to-plan`; no sibling skill handoff exists. +OpenCode forwards each phase result as the authoritative handoff rather than reconstructing it. Claude and Pi keep the equivalent status and data as internal state inside `sce-change-to-plan`; no sibling skill handoff exists. ## Bootstrap boundary @@ -59,11 +59,11 @@ flowchart TD ## Target ownership -- Pi/OpenCode: command sequencing plus `sce-context-load` and `sce-plan-authoring` packages. -- Claude: one thin command invoking `sce-change-to-plan`; package files are `SKILL.md` and `references/output.md`. +- OpenCode: command sequencing plus `sce-context-load` and `sce-plan-authoring` packages. +- Claude and Pi: one thin command invoking `sce-change-to-plan`; package files are `SKILL.md` and `references/output.md`. ## Canonical sources - `config/pkl/base/workflow-change-to-plan.pkl` -- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude consumes it) +- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude and Pi consume it) - Behavioral baseline: `.pi/prompts/change-to-plan.md` From d0d569a3e4a86e41f4361235a7acabaeccf3119b Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 16:38:39 +0200 Subject: [PATCH 16/21] config: Render OpenCode as thin commands and workflow skill packages OpenCode was the last target still emitting the eight canonical phase packages and per-command phase chains, so its commands carried multi-step `skills` lists and its agents allowlisted every phase skill individually. That kept two divergent shapes alive across targets and made the phase packages a generated output surface rather than an authoring input. Route opencode-content.pkl through the shared workflow-composite module: each command now derives a one-entry `entry-skill`/`skills` pair from `workflowSkillSlugByCommand`, and skill documents render as four two-file packages with OpenCode metadata only on the entrypoint. The agent permission allowlists narrow to the four workflow skills. The coverage check switches OpenCode to `expectedWorkflowSkillDocumentPaths`, adds per-command route assertions, and drops the now-unused `expectedCanonicalSkillDocumentPaths` set. Co-authored-by: SCE --- .../pkl/renderers/metadata-coverage-check.pkl | 29 +------ config/pkl/renderers/opencode-content.pkl | 86 +++++-------------- config/pkl/renderers/opencode-metadata.pkl | 12 +-- context/glossary.md | 2 +- context/patterns.md | 12 +-- ...opencode-workflow-single-skill-packages.md | 34 +++++++- 6 files changed, 69 insertions(+), 106 deletions(-) diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index a553da55..bbc0c2a6 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -17,30 +17,6 @@ local expectedAgentSlugs = Set( local expectedWorkflowSkillByCommand = claudeMetadata.workflowSkillSlugByCommand -local expectedCanonicalSkillDocumentPaths = Set( - "sce-atomic-commit/SKILL.md", - "sce-atomic-commit/references/commit-contract.yaml", - "sce-atomic-commit/references/commit-message-style.md", - "sce-context-load/SKILL.md", - "sce-context-load/references/context-brief.yaml", - "sce-plan-authoring/SKILL.md", - "sce-plan-authoring/references/authoring-contract.yaml", - "sce-plan-authoring/references/plan-summary.md", - "sce-plan-authoring/references/plan-template.md", - "sce-plan-context-sync/SKILL.md", - "sce-plan-context-sync/references/sync-report.md", - "sce-plan-review/SKILL.md", - "sce-plan-review/references/readiness-contract.yaml", - "sce-task-context-sync/SKILL.md", - "sce-task-context-sync/references/sync-report.md", - "sce-task-execution/SKILL.md", - "sce-task-execution/references/execution-contract.yaml", - "sce-task-execution/references/implementation-gate.md", - "sce-validation/SKILL.md", - "sce-validation/references/validation-report.md", - "sce-validation/references/validation-result.md" -) - /// A collapsed target renders each workflow as one package with one entrypoint /// and one user-visible Markdown output reference. Exact coverage rejects stale /// phase packages and any additional package-local references. @@ -113,7 +89,10 @@ local assertCommandRoute = (target: String, slug: String, document: String) -> inventoryChecks { ["opencode-agents"] = assertExactKeys.apply(opencodeAgents, expectedAgentSlugs, "OpenCode agent") ["opencode-commands"] = assertExactKeys.apply(opencodeCommands, expectedCommandSlugs, "OpenCode command") - ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedCanonicalSkillDocumentPaths, "OpenCode skill document") + ["opencode-skill-documents"] = assertExactKeys.apply(opencodeSkillDocuments, expectedWorkflowSkillDocumentPaths, "OpenCode skill document") + for (slug, document in opencodeCommands) { + ["opencode-command-route-\(slug)"] = assertCommandRoute.apply("OpenCode", slug, document.text) + } ["claude-commands"] = assertExactKeys.apply(claudeCommands, expectedCommandSlugs, "Claude command") ["claude-skill-documents"] = assertExactKeys.apply(claudeSkillDocuments, expectedWorkflowSkillDocumentPaths, "Claude skill document") for (slug, document in claudeCommands) { diff --git a/config/pkl/renderers/opencode-content.pkl b/config/pkl/renderers/opencode-content.pkl index cbfd0299..5ebe5a10 100644 --- a/config/pkl/renderers/opencode-content.pkl +++ b/config/pkl/renderers/opencode-content.pkl @@ -1,20 +1,9 @@ -import "../base/workflow-change-to-plan.pkl" as changeToPlan -import "../base/workflow-next-task.pkl" as nextTask -import "../base/workflow-validate.pkl" as validate -import "../base/workflow-commit.pkl" as commit -import "../base/workflow-content.pkl" as model import "common.pkl" as common import "opencode-metadata.pkl" as metadata +import "workflow-composite.pkl" as workflowResults local generatedOpenCodePluginPathsJson = common.sceGeneratedOpenCodePluginPathsJson -local workflows = new Listing { - changeToPlan.workflow - nextTask.workflow - validate.workflow - commit.workflow -} - /// Commands routed by a thin agent declare it here. local commandAgentBySlug = new Mapping { ["change-to-plan"] = "Shared Context Plan" @@ -23,51 +12,15 @@ local commandAgentBySlug = new Mapping { ["commit"] = "Shared Context Code" } -local commandSkillMetadataBySlug = new Mapping { - ["change-to-plan"] = """ -entry-skill: "sce-context-load" -skills: - - "sce-context-load" - - "sce-plan-authoring" -""" - ["next-task"] = """ -entry-skill: "sce-plan-review" -skills: - - "sce-plan-review" - - "sce-task-execution" - - "sce-task-context-sync" -""" - ["validate"] = """ -entry-skill: "sce-validation" -skills: - - "sce-validation" - - "sce-plan-context-sync" -""" - ["commit"] = """ -entry-skill: "sce-atomic-commit" -skills: - - "sce-atomic-commit" -""" -} - local commandAgentLine = (slug: String) -> if (commandAgentBySlug.containsKey(slug)) "agent: \"\(commandAgentBySlug[slug])\"\n" else "" -local renderCommand = (command: model.WorkflowCommand) -> new model.WorkflowDocument { - path = command.document.path - text = command.document.text.replaceFirst( - "\n---\n", - "\n\(commandAgentLine.apply(command.slug))\(commandSkillMetadataBySlug[command.slug])\n---\n" - ) -} - -local renderSkillDocument = (document: model.WorkflowDocument) -> new model.WorkflowDocument { - path = document.path - text = if (document.path == "SKILL.md") document.text.replaceFirst( - "\n---\n", - "\ncompatibility: opencode\n---\n" - ) else document.text -} +/// One command declares one workflow skill as both its entry skill and its whole +/// skill chain. The skill owns every phase, so there is no sibling package to +/// hand off to. +local commandSkillLines = (slug: String) -> + let (skillSlug = workflowResults.workflowSkillSlugByCommand[slug]) + "entry-skill: \"\(skillSlug)\"\nskills:\n - \"\(skillSlug)\"\n" local agentFrontmatterBySlug = new Mapping { for (unitSlug, _ in metadata.agentDisplayNames) { @@ -103,22 +56,25 @@ agents { } } +/// OpenCode commands are intentionally thin. Each routes to exactly one composite +/// workflow skill, which owns all phases, waits, and final response rendering. commands { - for (workflow in workflows) { - [workflow.command.slug] = renderCommand.apply(workflow.command) + for (slug, workflow in workflowResults.workflows) { + [slug] = workflowResults.renderCommand.apply( + workflow, + commandAgentLine.apply(slug) + commandSkillLines.apply(slug) + ) } } -/// Flatten package-relative document paths while retaining each skill's -/// self-contained directory layout and adding only OpenCode-supported metadata -/// to the package entrypoint. +/// OpenCode has four workflow packages, each with exactly SKILL.md and one +/// references/output.md presentation contract. Package-relative document paths +/// stay flattened for deterministic generation while retaining each skill's +/// self-contained directory layout, and only the entrypoint carries +/// OpenCode-supported metadata. skillDocuments { - for (workflow in workflows) { - for (skillSlug, skillPackage in workflow.skills) { - for (documentPath, document in skillPackage.documents) { - ["\(skillSlug)/\(documentPath)"] = renderSkillDocument.apply(document) - } - } + for (path, document in workflowResults.skillDocuments.apply("compatibility: \(metadata.skillCompatibility)\n")) { + [path] = document } } diff --git a/config/pkl/renderers/opencode-metadata.pkl b/config/pkl/renderers/opencode-metadata.pkl index 3a1b1ccf..16cbf3f1 100644 --- a/config/pkl/renderers/opencode-metadata.pkl +++ b/config/pkl/renderers/opencode-metadata.pkl @@ -40,8 +40,7 @@ permission: doom_loop: ask skill: "*": ask - "sce-context-load": allow - "sce-plan-authoring": allow + "sce-change-to-plan": allow """ ["shared-context-code"] = """ permission: @@ -64,12 +63,9 @@ permission: doom_loop: ask skill: "*": ask - "sce-plan-review": allow - "sce-task-execution": allow - "sce-task-context-sync": allow - "sce-validation": allow - "sce-plan-context-sync": allow - "sce-atomic-commit": allow + "sce-next-task": allow + "sce-validate": allow + "sce-commit": allow """ } diff --git a/context/glossary.md b/context/glossary.md index c1185c61..db5a1213 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -148,7 +148,7 @@ - `next-task thin orchestration contract`: Canonical `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-next-task` and route their command directly to that one skill. - `change-to-plan thin orchestration contract`: Canonical `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-change-to-plan` and route their command directly to that one skill. - `validate thin orchestration contract`: Canonical `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-validate` and route their command directly to that one skill. -- `OpenCode command skill metadata`: Machine-readable frontmatter on the four generated OpenCode workflow commands, using `entry-skill` for the initial phase and `skills` for the complete ordered chain defined by `config/pkl/renderers/opencode-content.pkl`. +- `OpenCode command skill metadata`: Machine-readable frontmatter on the four generated OpenCode workflow commands, defined by `config/pkl/renderers/opencode-content.pkl`. `entry-skill` and the one-entry `skills` list both name that command's single workflow skill, which owns every phase internally. - `one-task/one-atomic-commit planning contract`: `sce-plan-authoring` requirement that each executable plan task represents one coherent commit unit; broad multi-commit tasks must be split into sequential atomic tasks before execution handoff. - `agent trace historical reference docs`: Retained `context/sce/agent-trace-*.md` artifacts that describe the removed pre-v0.3 Agent Trace design and task slices; they are reference-only and do not describe the active local-hook runtime. - `agent trace commit-msg co-author policy`: Current contract in `cli/src/services/hooks/mod.rs` (`apply_commit_msg_coauthor_policy`) that applies exactly one canonical trailer (`Co-authored-by: SCE `) only when attribution hooks are enabled, SCE is not disabled, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); `NoOverlap` and `Error` both suppress the trailer, with `Error` logged via `sce.hooks.commit_msg.ai_overlap_error`; duplicate canonical trailers are deduped idempotently. diff --git a/context/patterns.md b/context/patterns.md index f5a9adff..ae83f079 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -55,14 +55,14 @@ - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. - Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Duplicating the internalization substitution tables per target would guarantee drift between targets whose composed text is meant to be identical. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. -- Keep canonical OpenCode YAML phase-result contracts and its eight multi-file phase-package inventory unchanged. For Claude and Pi, compose each canonical workflow into one workflow-level skill package; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. +- Compose each canonical workflow into one workflow-level skill package for every generated target; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. The canonical phase packages under `config/pkl/base/` remain authoring inputs to that composition, not a generated output surface for any target. - Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi needs no metadata module because it adds no target-specific frontmatter. -- Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent`, `entry-skill`, and the complete ordered `skills` chain must match the canonical workflow phases. -- Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path; run it whenever workflow documents or target metadata change. -- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Composition is the exception: a collapsed target's renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided every canonical gate, branch, write, and continuation retains exactly one owner in that skill and the targets that have not collapsed keep byte-identical output. -- Claude commands must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. -- A Claude workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. +- Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent` plus `entry-skill` and a `skills` chain, both naming that command's single workflow skill. Derive the slug from the shared `workflowSkillSlugByCommand` mapping rather than restating it per command. +- Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path, plus a per-target one-to-one command-to-workflow-skill route assertion; run it whenever workflow documents or target metadata change. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Composition is the exception: a collapsed target's renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided every canonical gate, branch, write, and continuation retains exactly one owner in that skill. When a change collapses one target, the targets already collapsed must keep byte-identical output; verify by generating into temp roots before and after and diffing their subtrees. +- Every target's commands (Pi: prompts) must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. +- A workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. - Validate each renderer module directly with `nix develop -c pkl eval ` before wiring output emission. diff --git a/context/plans/pi-opencode-workflow-single-skill-packages.md b/context/plans/pi-opencode-workflow-single-skill-packages.md index e1ab2524..0dc1f1ea 100644 --- a/context/plans/pi-opencode-workflow-single-skill-packages.md +++ b/context/plans/pi-opencode-workflow-single-skill-packages.md @@ -199,7 +199,7 @@ workflow slugs. Claude's generated bytes must not change. paths. `expectedCanonicalSkillDocumentPaths` remains in use for OpenCode until T03. -- [ ] T03: `Render OpenCode as four thin commands and four workflow skill packages` (status:todo) +- [x] T03: `Render OpenCode as four thin commands and four workflow skill packages` (status:done) - Task ID: T03 - Goal: Emit OpenCode's workflows as four commands whose frontmatter declares one entry skill and a one-entry skill chain, plus four two-file packages @@ -221,6 +221,38 @@ workflow slugs. Claude's generated bytes must not change. config/pkl/renderers/metadata-coverage-check.pkl`; `nix run .#pkl-generate -- "$(mktemp -d)"` then inspect `config/.opencode/{skills,command,agent}`; `nix run .#pkl-check-generated`; `nix flake check`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/renderers/opencode-content.pkl`, + `config/pkl/renderers/opencode-metadata.pkl`, + `config/pkl/renderers/metadata-coverage-check.pkl`, + `context/plans/pi-opencode-workflow-single-skill-packages.md` + - Evidence: `opencode-content.pkl` now renders through `workflow-composite.pkl`. + The four-entry `commandSkillMetadataBySlug` phase chains were replaced by + `commandSkillLines`, which derives a one-entry `entry-skill`/`skills` pair from + the shared `workflowSkillSlugByCommand`; the existing `agent:` line is prepended + so command frontmatter order stays `description`, `argument-hint`, `agent`, + `entry-skill`, `skills`. `renderSkillDocument` and the canonical + `workflow-*.pkl` imports were dropped in favour of + `skillDocuments.apply("compatibility: \(metadata.skillCompatibility)\n")`, so + only the package entrypoint carries OpenCode metadata. In + `opencode-metadata.pkl` the Plan agent's `permission.skill` allowlist is now + exactly `sce-change-to-plan` and the Code agent's is exactly `sce-next-task`, + `sce-validate`, `sce-commit`. In `metadata-coverage-check.pkl` the OpenCode + inventory check moved to `expectedWorkflowSkillDocumentPaths`, four OpenCode + `assertCommandRoute` checks were added, and the now-unused + `expectedCanonicalSkillDocumentPaths` set was deleted. `pkl eval + config/pkl/renderers/metadata-coverage-check.pkl` passed with all nineteen + inventory checks complete. Generation into a temp root produced exactly the + eight workflow-package paths under `config/.opencode/skills`, four commands, + and the two unchanged agents; `diff -r` against a pre-change generation + reported no differences for `config/.claude` or `config/.pi`. + `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 + `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`. + `nix flake check` passed all five flake checks. + - Notes: `check-generated.sh` needed no edit; its required paths name the + `config/.opencode/{agent,command,skills}` directories, not per-package paths. + The generated file count dropped from 59 to 46 as OpenCode's eight phase + packages collapsed to four two-file packages. - [ ] T04: `Record the cross-target single-skill decision and realign durable context` (status:todo) - Task ID: T04 From 406efe56ea7ae4f89f5963686335d6623553ded8 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 17:14:18 +0200 Subject: [PATCH 17/21] context: Record cross-target single-skill workflow packages Durable context still described Pi and OpenCode as consuming eight self-contained phase-skill packages with YAML phase-result contracts, and scoped the composed single-skill model to Claude alone. That stopped being true once all three targets began rendering through the shared workflow composite renderer, leaving the decision records, overview, architecture, glossary, context map, and the five context/sce workflow documents contradicting the generated output. Add a decision record establishing four thin entrypoints plus four two-file workflow packages for every target, one shared composition path, and no phase package or phase-result transport anywhere. Mark the superseded scope inline in the 2026-07-27 and 2026-07-29 Claude records and in the plan/code agent-separation record, and rewrite the durable files so the eight phase names denote canonical authoring modules and internal phases rather than an installed surface. Also narrow the described OpenCode routing-agent skill allowlists to the four workflow slugs. Co-authored-by: SCE --- context/architecture.md | 16 ++-- context/context-map.md | 13 +-- .../2026-03-03-plan-code-agent-separation.md | 2 +- ...-07-27-workflow-oriented-pkl-generation.md | 10 +- ...26-07-29-claude-workflow-skill-packages.md | 12 ++- ...29-cross-target-workflow-skill-packages.md | 42 +++++++++ context/glossary.md | 11 ++- context/overview.md | 10 +- context/patterns.md | 4 +- ...opencode-workflow-single-skill-packages.md | 92 +++++++++++++++++-- context/sce/atomic-commit-workflow.md | 29 +++--- context/sce/dedup-ownership-table.md | 28 +++--- context/sce/plan-code-overlap-map.md | 23 ++--- context/sce/shared-context-code-workflow.md | 22 +++-- context/sce/shared-context-plan-workflow.md | 21 +++-- 15 files changed, 233 insertions(+), 102 deletions(-) create mode 100644 context/decisions/2026-07-29-cross-target-workflow-skill-packages.md diff --git a/context/architecture.md b/context/architecture.md index d5930cd1..77cb5dfa 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -36,16 +36,16 @@ The scaffold provides stable canonical content-unit identifiers and reusable tar Renderer modules apply target-specific metadata/frontmatter rules while reusing canonical content bodies: -- The manual OpenCode renderer consumes the four canonical workflow packages directly, extends their supported frontmatter with `agent`, `entry-skill`, ordered `skills`, and `compatibility: opencode` metadata, flattens nested package documents, and emits two thin routing agents with OpenCode permission frontmatter. -- Claude renderer consumes the four canonical workflow packages as behavior sources but emits four target-specific workflow packages without generated agents: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command invokes exactly one corresponding workflow skill. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Claude settings and the hook helper remain separate retained outputs. -- Pi renderer consumes the same shared workflow composition as Claude and emits four workflow-level packages rather than phase packages. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). +- All three renderers consume the four canonical workflow packages as behavior sources and emit the same four workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Each thin command or prompt invokes exactly one corresponding workflow skill. +- Per-target differences are confined to frontmatter and the surrounding non-workflow outputs. The manual OpenCode renderer adds `agent`, `entry-skill`, and a one-entry `skills` list to command frontmatter, adds `compatibility: opencode` to each package entrypoint, and emits two thin routing agents whose `skill:` permission allowlists name only the four workflow slugs. The Claude renderer adds `compatibility: claude` plus `allowed-tools:` and emits no agents; Claude settings and the hook helper remain separate retained outputs. The Pi renderer adds no frontmatter to either prompts or skills. +- Pi renderer consumes the same shared workflow composition as OpenCode and Claude. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). - Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions, the phase-internalization substitution tables, the four output layouts, and the target-neutral command-to-workflow-skill slug mapping. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and its `allowed-tools` line for commands. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). - Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and re-exports the shared command-to-workflow-skill slug mapping from `workflow-composite.pkl`. Pi has no metadata module because it adds no target-specific frontmatter. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands, OpenCode's 21 multi-file phase-skill documents, Claude's and Pi's four two-file workflow packages each, and two OpenCode agents—then verifies every Claude and Pi command's one-to-one workflow-skill route through one target-labelled route assertion, and forces every rendered document and target metadata lookup to evaluate. -- OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; the Claude and Pi flattened inventories contain only `SKILL.md` and `references/output.md` for each workflow slug. -- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, eight complete phase-skill packages with nested references, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four thin workflow prompts, four two-file workflow skill packages, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands (Pi: prompts), four two-file workflow packages per target, and two OpenCode agents—through the target-neutral `expectedWorkflowSkillDocumentPaths`, then verifies every command's one-to-one workflow-skill route for all three targets through the target-labelled `assertCommandRoute(target, slug, document)`, and forces every rendered document and target metadata lookup to evaluate. +- OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; every target's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. +- `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, four two-file workflow skill packages, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four thin workflow prompts, four two-file workflow skill packages, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. - `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. @@ -186,6 +186,6 @@ Shared Context Plan and Shared Context Code remain separate architectural roles. - `/change-to-plan` and `/next-task` remain separate command entrypoints aligned to those roles. - Reuse is handled through shared canonical guidance blocks and skill-owned phase contracts, not by collapsing both roles into one agent. - OpenCode agents are thin routing surfaces rather than behavior owners: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi have no generated agents. Workflow commands and self-contained skill packages are the sole behavior owners. -- The canonical `/change-to-plan` workflow sequences `sce-context-load` and `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` and validated-only `sce-plan-context-sync`; `/commit` sequences around `sce-atomic-commit`. OpenCode still consumes those phase packages as its generated inventory. -- Claude and Pi embed those same phase boundaries inside `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, so no Claude or Pi command or workflow skill invokes a phase or sibling SCE package. +- The canonical `/change-to-plan` workflow sequences `sce-context-load` and `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` and validated-only `sce-plan-context-sync`; `/commit` sequences around `sce-atomic-commit`. Those phase modules are canonical authoring source; no target generates them as packages. +- Every target embeds those same phase boundaries inside `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, so no generated command, prompt, or workflow skill invokes a phase or sibling SCE package. - OpenCode, Claude, and Pi expose the generated `/commit` workflow but no generated `/handover` command; the automated OpenCode profile is removed. diff --git a/context/context-map.md b/context/context-map.md index 28f07396..14d2c967 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -22,12 +22,12 @@ Feature/domain context: - `context/cli/capability-traits.md` (current broad CLI capability seam in `cli/src/services/capabilities.rs`, including `FsOps`/`StdFsOps`, `GitOps`/`ProcessGitOps`, git root/hooks resolution behavior, compile-time-typed borrowed AppContext wiring with associated-type narrow capability accessors plus `ContextWithRepoRoot` repo-root-scoped context derivation, generic command execution bounds, and test-only unimplemented stubs; current service internals do not consume fs/git traits until later lifecycle migration tasks) - `context/cli/service-lifecycle.md` (current compile-safe lifecycle seam in `cli/src/services/lifecycle.rs`, including default no-op `ServiceLifecycle` diagnose/fix/setup methods against narrow `HasRepoRoot`, lifecycle-owned health/fix/setup result types with generic setup messages, doctor/setup adapter boundaries, the static `LifecycleProvider` enum catalog/dispatcher, hook/config/local_db/auth_db/agent_trace_db lifecycle providers including setup-time repository-scoped Agent Trace DB initialization plus checkout identity diagnostics, implemented doctor aggregation over diagnose/fix providers, and implemented setup aggregation over `setup` providers in order config → local_db → auth_db → agent_trace_db → hooks when requested) - `context/sce/cli-observability-contract.md` (implemented config-backed runtime observability contract for the flat logging config-file shape with env-over-config fallback, concrete logger/telemetry runtime behavior plus logger and object-safe telemetry trait boundaries, AppContext observability wiring, generic `RunOutcome` final rendering, runtime-classified repeated telemetry action protection, operator-facing `sce config show` observability reporting, and the trimmed `sce config validate` status-only validation surface) -- `context/sce/shared-context-code-workflow.md` (canonical `/next-task` and `/validate` lifecycles, including OpenCode phase ownership and the Claude/Pi single-skill `sce-next-task` / `sce-validate` composition) -- `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, one-task/one-atomic-commit task slicing, and Claude's `sce-change-to-plan` ownership) +- `context/sce/shared-context-code-workflow.md` (canonical `/next-task` and `/validate` lifecycles, their internal phase ownership, and the cross-target single-skill `sce-next-task` / `sce-validate` composition) +- `context/sce/shared-context-plan-workflow.md` (canonical `/change-to-plan` workflow, clarification/readiness gate contract, one-task/one-atomic-commit task slicing, and cross-target `sce-change-to-plan` ownership) - [Context workflow rules](sce/context-workflow-rules.md) (canonical bootstrap, ongoing context maintenance, task synchronization, plan synchronization, hygiene, discoverability, and feature-existence rules) - `context/sce/plan-code-overlap-map.md` (overlap matrix for thin OpenCode Plan/Code routing agents and workflow phase ownership; its original three-workflow inventory predates the generated `/commit` package) -- `context/sce/dedup-ownership-table.md` (canonical owner-vs-consumer boundaries for workflow packages, phase skills, the shared sync skeleton, and thin OpenCode agents; its original three-workflow/seven-skill inventory predates generated `/commit` and `sce-atomic-commit`) -- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, staged-truth and plan-citation rules, canonical OpenCode `sce-atomic-commit` phase ownership, and the Claude/Pi composite `sce-commit` package) +- `context/sce/dedup-ownership-table.md` (canonical owner-vs-consumer boundaries for workflow packages, canonical phase modules, the shared sync skeleton, and thin OpenCode agents; its original three-workflow/seven-skill inventory predates generated `/commit` and `sce-atomic-commit`) +- [Atomic commit workflow](sce/atomic-commit-workflow.md) (`/commit` regular proposal-only mode vs `oneshot`/`skip` bypass mode, staged-truth and plan-citation rules, canonical `sce-atomic-commit` phase ownership, and the cross-target composite `sce-commit` package) - `context/sce/agent-trace-implementation-contract.md` (historical no-git-wrapper Agent Trace design contract; not active runtime behavior) - `context/sce/agent-trace-embedded-schema-validation.md` (implemented internal Agent Trace JSON schema-validation seam in `cli/src/services/agent_trace.rs`, embedding `config/schema/agent-trace.schema.json` at compile time, caching the compiled validator, validating string or parsed-JSON inputs, and returning deterministic invalid-JSON vs schema-validation errors without changing the current minimal generator output) @@ -83,8 +83,9 @@ Recent decision records: - `context/decisions/2026-02-28-pkl-generation-architecture.md` - `context/decisions/2026-03-03-plan-code-agent-separation.md` -- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (canonical workflow-oriented ownership and current OpenCode phase-package matrix; Claude and Pi inventory claims are superseded) -- `context/decisions/2026-07-29-claude-workflow-skill-packages.md` (Claude's four command-to-workflow-skill routes, two-file package rule, internal phase state, and its Pi/OpenCode preservation clause, whose Pi half is superseded) +- `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md` (canonical workflow-oriented ownership, the `.pi/` behavioral baseline, the shared sync skeleton, and routing-only agents; its per-target phase-package inventory and phase-result transport claims are superseded) +- `context/decisions/2026-07-29-claude-workflow-skill-packages.md` (the four command-to-workflow-skill routes, two-file package rule, and internal phase state, first established for Claude; its Claude-only scoping and Pi/OpenCode preservation clauses are superseded) +- `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md` (current cross-target model: OpenCode, Claude, and Pi each render four thin entrypoints plus four two-file workflow packages through one shared composite renderer; canonical phase modules are authoring inputs only, and OpenCode's routing agents allow exactly the four workflow slugs) - `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` (removes committed generated targets; establishes pre-Cargo generation, validated copying into Cargo `OUT_DIR`, and crates.io/Flatpak packaging fallbacks) - `context/decisions/2026-03-09-migrate-lexopt-to-clap.md` (CLI argument parsing migration from lexopt to clap derive macros) - `context/decisions/2026-03-25-first-install-channels.md` (approved first-wave install/distribution scope for `sce`, canonical naming, and Nix-owned build policy) diff --git a/context/decisions/2026-03-03-plan-code-agent-separation.md b/context/decisions/2026-03-03-plan-code-agent-separation.md index b75dc382..43f9d4a7 100644 --- a/context/decisions/2026-03-03-plan-code-agent-separation.md +++ b/context/decisions/2026-03-03-plan-code-agent-separation.md @@ -27,7 +27,7 @@ Task: `T05` - Keep one canonical shared baseline block for cross-agent principles (`human owns decisions`, `context as durable memory`, `code truth wins`, and `context/` authority rules). - Keep role-specific mission, hard boundaries, and procedures local to each agent and phase-owning skills. -- Keep `/next-task` concise and orchestration-focused, delegating detailed contracts to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. +- Keep `/next-task` concise and orchestration-focused, delegating detailed contracts to `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. (Those are now internal phases of `sce-next-task` rather than sibling skills; the command is thinner still, routing to that one skill. See `2026-07-29-cross-target-workflow-skill-packages.md`. The role separation this decision establishes is unaffected.) ## Consequences for follow-up tasks diff --git a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md index 7d057689..b8a26888 100644 --- a/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md +++ b/context/decisions/2026-07-27-workflow-oriented-pkl-generation.md @@ -1,15 +1,15 @@ # Decision: Use Workflow-Oriented Pkl Generation Date: 2026-07-27 -Status: Accepted (Claude inventory and transport superseded 2026-07-29) +Status: Accepted (all-target phase-package inventory and phase-result transport superseded 2026-07-29) Plan: `context/plans/rebuild-pkl-workflow-markdown.md` ## Decision - Model generated SCE Markdown as four canonical workflow packages: `/change-to-plan`, `/next-task`, `/validate`, and `/commit`. - Use the project-root `.pi/` prompts, skills, and package-local references as the behavioral baseline. -- Generate the same eight self-contained skill packages for Pi, OpenCode, and Claude. A generated skill may share Pkl source with another skill, but it must not depend on a sibling generated package. -- Preserve canonical YAML phase-result contracts for Pi and OpenCode, while Claude renders target-specific Markdown contracts for the five structured phase skills; fixed statuses and labeled sections preserve command handoff semantics. +- Generate the same eight self-contained skill packages for Pi, OpenCode, and Claude. A generated skill may share Pkl source with another skill, but it must not depend on a sibling generated package. (Superseded 2026-07-29: every target now generates four workflow-level packages instead.) +- Preserve canonical YAML phase-result contracts for Pi and OpenCode, while Claude renders target-specific Markdown contracts for the five structured phase skills; fixed statuses and labeled sections preserve command handoff semantics. (Superseded 2026-07-29: no target transports a phase result between packages.) - Instantiate `sce-task-context-sync` and `sce-plan-context-sync` from one role-parameterized Pkl skeleton while preserving their distinct handoff gates, lifecycle boundaries, and reports. - Keep only two generated agents, both for OpenCode and both routing-only: Plan routes to `/change-to-plan`; Code routes to `/next-task`, `/validate`, and `/commit`. Claude and Pi receive no generated agents. - Remove the automated OpenCode profile and obsolete generated commit, handover, bootstrap, atomic-commit, and legacy context-sync Markdown surfaces. @@ -24,7 +24,7 @@ The automated profile and obsolete Markdown catalog represented a second behavio ## Consequences - Canonical workflow content lives in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with shared types in `workflow-content.pkl` and synchronization policy in `workflow-context-sync.pkl`; Claude phase-result overrides live in `config/pkl/renderers/claude-workflow-results.pkl` (since promoted to the target-neutral `config/pkl/renderers/workflow-composite.pkl`). -- Generated inventory is four commands and eight skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. +- Generated inventory is four commands and eight skill packages for each target, plus two OpenCode agents. Pi also retains its extension; Claude retains settings and hooks. (Superseded 2026-07-29: four commands and four two-file workflow packages per target.) - `config/pkl/renderers/metadata-coverage-check.pkl`, `config/pkl/check-generated.sh`, and the root flake parity check enforce exact inventories, nested package references, and forbidden removed trees. - `config/automated/.opencode` and `config/.claude/agents` are forbidden outputs rather than compatibility surfaces. @@ -32,6 +32,6 @@ The automated profile and obsolete Markdown catalog represented a second behavio This decision supersedes the generated path matrix, paired-output counts, and target inventory in `2026-02-28-pkl-generation-architecture.md`. That decision's canonical-Pkl-source, deterministic-rendering, and generated-vs-runtime ownership principles remain in force. -`2026-07-29-claude-workflow-skill-packages.md` supersedes this decision's claims that Claude receives the same eight phase packages and transports Markdown phase results. Pi/OpenCode decomposition and all other ownership decisions here remain in force. +`2026-07-29-claude-workflow-skill-packages.md` supersedes this decision's claims that Claude receives the same eight phase packages and transports Markdown phase results. `2026-07-29-cross-target-workflow-skill-packages.md` extends that to Pi and OpenCode: no target renders the phase modules as packages or transports phase-result contracts between packages. The phase modules remain canonical authoring inputs. All other ownership decisions here remain in force. The separate Plan/Code role decision in `2026-03-03-plan-code-agent-separation.md` remains in force, with agents now explicitly limited to routing. diff --git a/context/decisions/2026-07-29-claude-workflow-skill-packages.md b/context/decisions/2026-07-29-claude-workflow-skill-packages.md index be6899f3..e785a2a5 100644 --- a/context/decisions/2026-07-29-claude-workflow-skill-packages.md +++ b/context/decisions/2026-07-29-claude-workflow-skill-packages.md @@ -1,25 +1,25 @@ # Decision: Collapse Claude Workflows into Single-Skill Packages Date: 2026-07-29 -Status: Accepted +Status: Accepted (Claude-only scope superseded 2026-07-29) Plan: `context/plans/claude-workflow-single-skill-packages.md` Supersedes in part: `2026-07-27-workflow-oriented-pkl-generation.md` ## Decision -- Keep the four canonical workflow definitions and eight phase-skill packages as the behavioral source for Pi and OpenCode. +- Keep the four canonical workflow definitions and their phase modules as the behavioral source. (This decision rendered them as eight packages for Pi and OpenCode; `2026-07-29-cross-target-workflow-skill-packages.md` collapsed those targets too, so the phase modules are now authoring inputs only.) - Render Claude as exactly four thin commands and four workflow-level skills: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. - Route each Claude command to exactly one corresponding workflow skill. Claude commands do not sequence phase skills. - Compose each Claude workflow skill from the canonical command, phase behavior, and context-sync policy in `config/pkl/renderers/claude-workflow-results.pkl` (since promoted to the target-neutral `config/pkl/renderers/workflow-composite.pkl`). - Keep phase statuses and phase-to-phase data as internal workflow state. A Claude workflow skill never invokes another SCE skill or sibling package. - Emit exactly two files per Claude package: `SKILL.md` and `references/output.md`. The latter is the sole package reference and owns all human-visible gates, reports, and terminal Markdown layouts. -- Preserve Pi and OpenCode generated command behavior, eight-skill inventories, and phase contracts byte-for-byte. +- Preserve Pi and OpenCode generated command behavior, eight-skill inventories, and phase contracts byte-for-byte. (Superseded: those targets were collapsed the same way on 2026-07-29.) ## Rationale Claude executes a skill as the durable unit of control flow. Returning a phase result through one skill and asking a command to resume another phase creates an unreliable turn boundary: the intermediate result can become the apparent deliverable and terminate the workflow. Putting the complete lifecycle in one skill removes that transport seam while retaining the canonical gates, waits, writes, verification, synchronization, and continuation rules. -The target-specific collapse belongs in the renderer rather than the canonical base because Pi and OpenCode support the existing decomposed workflow and rely on its explicit phase contracts. +The collapse belongs in the renderer rather than the canonical base, so the phase modules remain the reviewable behavioral source. At the time of this decision that also let Pi and OpenCode keep the decomposed workflow and its explicit phase contracts; they were subsequently collapsed for cross-target uniformity. ## Consequences @@ -31,4 +31,6 @@ The target-specific collapse belongs in the renderer rather than the canonical b ## Superseded scope -This decision supersedes only the Claude inventory and Claude phase-result transport claims in `2026-07-27-workflow-oriented-pkl-generation.md`. That decision remains authoritative for canonical workflow ownership, Pi/OpenCode's eight phase packages, the shared context-sync skeleton, thin OpenCode agents, removed automated profiles, and retained non-Markdown outputs. +This decision supersedes only the Claude inventory and Claude phase-result transport claims in `2026-07-27-workflow-oriented-pkl-generation.md`. That decision remains authoritative for canonical workflow ownership, the shared context-sync skeleton, thin OpenCode agents, removed automated profiles, and retained non-Markdown outputs. + +`2026-07-29-cross-target-workflow-skill-packages.md` supersedes this decision's Claude-only scoping: the clauses preserving Pi/OpenCode phase packages, eight-skill inventories, and phase-result contracts no longer hold. Everything stated here about the composed package shape, the two-file package rule, single-skill command routing, and internal phase statuses now applies to all three targets. diff --git a/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md b/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md new file mode 100644 index 00000000..52062cc3 --- /dev/null +++ b/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md @@ -0,0 +1,42 @@ +# Decision: Render Every Target's Workflows as Single-Skill Packages + +Date: 2026-07-29 +Status: Accepted +Plan: `context/plans/pi-opencode-workflow-single-skill-packages.md` +Supersedes in part: `2026-07-27-workflow-oriented-pkl-generation.md`, `2026-07-29-claude-workflow-skill-packages.md` + +## Decision + +- Render OpenCode, Claude, and Pi identically: four thin workflow entrypoints (Pi: prompts; OpenCode and Claude: commands) plus four workflow-level skill packages — `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. +- Emit exactly two files per package for every target: `SKILL.md` and `references/output.md`. The latter is the sole package reference and owns all human-visible gates, reports, and terminal Markdown layouts. +- Route each entrypoint to exactly its one corresponding workflow skill. No entrypoint sequences phase skills, and no workflow skill invokes a sibling SCE package. +- Keep the four canonical workflow definitions in `config/pkl/base/workflow-*.pkl` and their phase modules as the single behavioral source. They remain authoring inputs to composition; they are no longer a generated output surface for any target. +- Own composition in the target-neutral `config/pkl/renderers/workflow-composite.pkl`, parameterized only by the extra skill and command frontmatter each target supports. Claude passes `compatibility: claude` plus `allowed-tools:`, OpenCode passes `compatibility: opencode`, and Pi passes none. +- Keep phase statuses and phase-to-phase data as internal workflow state on every target. No target transports a YAML or Markdown phase-result contract between packages. +- Keep OpenCode's two thin routing agents and narrow their `skill:` permission allowlists to the four workflow slugs: `sce-change-to-plan` for Plan; `sce-next-task`, `sce-validate`, and `sce-commit` for Code. + +## Rationale + +The transport failure that motivated the Claude collapse was observed on Claude: a phase result returned through one skill can become the apparent deliverable and end the turn, so a command sequencing sibling skills is an unreliable carrier of workflow state. Pi and OpenCode were not observed failing that way. They are collapsed for cross-target uniformity and a single composition path — one renderer producing the same eight workflow documents for all three targets, rather than one composite renderer for Claude and a separate decomposed rendering path for the other two. + +The trade-off is explicit: three targets now share one composition path and identical generated behavior, at the cost of OpenCode's explicit per-phase contracts and independently loadable phase packages. Those contracts survive as canonical Pkl authoring structure and as the internal phase boundaries composed into each `SKILL.md`; they simply stop being an installed surface. + +Keeping the collapse in the renderer rather than the canonical base preserves the phase modules as the reviewable behavioral source and keeps the four workflows' gates, waits, writes, verification, synchronization, and continuation rules stated exactly once. + +## Consequences + +- No target emits `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, or `sce-atomic-commit` as a package. Those names now denote canonical authoring modules and internal phases only. +- Per-target generated workflow inventory is four entrypoints plus eight skill Markdown files across four packages. OpenCode adds its two routing agents; Pi retains its extension; Claude retains settings and hooks. +- `config/pkl/renderers/workflow-composite.pkl` owns `workflowSkillSlugByCommand` for all targets; `claude-metadata.pkl` re-exports it. +- `config/pkl/renderers/metadata-coverage-check.pkl` asserts the workflow-package inventory and single-skill command route for all three targets through the target-neutral `expectedWorkflowSkillByCommand`, `expectedWorkflowSkillDocumentPaths`, and `assertCommandRoute(target, slug, document)`. +- OpenCode command frontmatter still carries `entry-skill` and `skills`, now naming one skill in both. +- Claude's generated output is unchanged by this decision; its byte-identity was verified across the change. +- Stale installed phase-skill directories in existing checkouts are handled by the existing setup remove-and-replace policy for the whole target directory (`context/sce/setup-no-backup-policy-seam.md`). No migration code exists. + +## Superseded scope + +This decision supersedes the Pi/OpenCode phase-package inventory and phase-result transport claims in `2026-07-27-workflow-oriented-pkl-generation.md` — specifically that all three targets receive the same eight self-contained phase packages, and that Pi and OpenCode preserve canonical YAML phase-result contracts. That decision remains authoritative for the four-workflow model, the `.pi/` behavioral baseline, the shared context-sync skeleton, routing-only agents, removed automated profiles, and retained non-Markdown outputs. + +It also supersedes the clauses in `2026-07-29-claude-workflow-skill-packages.md` that scope the collapse to Claude alone: that phase packages remain the rendered form for Pi and OpenCode, and that Pi/OpenCode command behavior, eight-skill inventories, and phase contracts are preserved byte-for-byte. Everything that decision states about the composed package shape, the two-file package rule, and internal phase statuses now applies to all three targets. + +`2026-03-03-plan-code-agent-separation.md` remains in force. OpenCode keeps its two routing agents; only their skill allowlists changed. diff --git a/context/glossary.md b/context/glossary.md index db5a1213..4ffda693 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -9,8 +9,9 @@ - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one thin prompt in `config/.pi/prompts/` plus the one workflow skill package under `config/.pi/skills/` that the prompt routes to, containing exactly `SKILL.md` and `references/output.md`. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. -- `workflow skill package`: One of the four renderer-composed packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`) emitted for Claude and Pi. Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Its only other file is `references/output.md`. OpenCode still retains the canonical eight phase-skill packages and their YAML handoff contracts. -- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite workflow definitions, the phase-internalization substitution tables, and the command-to-workflow-skill slug mapping. +- `workflow skill package`: One of the four renderer-composed packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`) emitted for every target. Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Its only other file is `references/output.md`. The canonical phase modules remain authoring inputs to composition and are not generated as packages for any target. +- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite workflow definitions, the phase-internalization substitution tables, and the command-to-workflow-skill slug mapping. All three targets render through it, parameterized only by the extra frontmatter each supports. +- `canonical phase module`: One of the eight phase definitions in `config/pkl/base/workflow-*.pkl` (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, `sce-atomic-commit`). Each is the single behavioral source for its phase and an authoring input to the composite renderer. Since 2026-07-29 no target generates them as installable skill packages; the names denote canonical source and the internal phases inside a composed `SKILL.md`. - `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. - `workflow output reference`: The required `references/output.md` in every workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. @@ -145,9 +146,9 @@ - `SCE dedup ownership table`: Context artifact at `context/sce/dedup-ownership-table.md` that assigns one canonical owner per shared behavior domain, lists reference-only consumers, and labels each overlap as `intentional/keep` or `dedup/remove`. - `shared context plan workflow`: Canonical workflow document at `context/sce/shared-context-plan-workflow.md` defining `/change-to-plan` planning flow, clarification gate semantics, readiness contract, and `/next-task` handoff format. - `SCE Plan/Code role separation`: Architecture decision recorded in `context/decisions/2026-03-03-plan-code-agent-separation.md` that keeps Shared Context Plan and Shared Context Code as separate OpenCode routing roles. The thin Plan agent routes to `/change-to-plan`; the thin Code agent routes to `/next-task` and `/validate`; canonical commands and skills own behavior. -- `next-task thin orchestration contract`: Canonical `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-next-task` and route their command directly to that one skill. -- `change-to-plan thin orchestration contract`: Canonical `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-change-to-plan` and route their command directly to that one skill. -- `validate thin orchestration contract`: Canonical `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`, consumed as separate phase skills by OpenCode; Claude and Pi embed the same behavior in `sce-validate` and route their command directly to that one skill. +- `next-task thin orchestration contract`: Canonical `/next-task` sequencing across `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`. Every target embeds that sequence in `sce-next-task` as internal phases and routes its command or prompt directly to that one skill. +- `change-to-plan thin orchestration contract`: Canonical `/change-to-plan` sequencing from `sce-context-load` to `sce-plan-authoring`. Every target embeds that sequence in `sce-change-to-plan` as internal phases and routes its command or prompt directly to that one skill. +- `validate thin orchestration contract`: Canonical `/validate` sequencing from `sce-validation` to validated-only `sce-plan-context-sync`. Every target embeds that sequence in `sce-validate` as internal phases and routes its command or prompt directly to that one skill. - `OpenCode command skill metadata`: Machine-readable frontmatter on the four generated OpenCode workflow commands, defined by `config/pkl/renderers/opencode-content.pkl`. `entry-skill` and the one-entry `skills` list both name that command's single workflow skill, which owns every phase internally. - `one-task/one-atomic-commit planning contract`: `sce-plan-authoring` requirement that each executable plan task represents one coherent commit unit; broad multi-commit tasks must be split into sequential atomic tasks before execution handoff. - `agent trace historical reference docs`: Retained `context/sce/agent-trace-*.md` artifacts that describe the removed pre-v0.3 Agent Trace design and task slices; they are reference-only and do not describe the active local-hook runtime. diff --git a/context/overview.md b/context/overview.md index 156357e0..8437ba97 100644 --- a/context/overview.md +++ b/context/overview.md @@ -54,9 +54,9 @@ The current supported automated release target matrix is `x86_64-unknown-linux-m The downstream publish-stage implementation is now complete for both registries: `.github/workflows/publish-crates.yml` publishes the checked-in crate version after `.version`/tag/Cargo parity checks, and `.github/workflows/publish-npm.yml` publishes the checked-in npm package after `.version`/tag/npm parity checks plus verification of the canonical `sce-v-npm.tgz` GitHub release asset. The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. -Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four canonical commands and OpenCode's eight self-contained phase-skill packages rather than in agent bodies. -The canonical workflow definitions remain phase-decomposed, and OpenCode still consumes them that way: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. Manual OpenCode command frontmatter records each entry skill and ordered skill chain. Claude and Pi consume the same canonical definitions as authoring inputs but emit them composed into four workflow-level skill packages. -Claude preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin Claude command invokes exactly one corresponding skill. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. Claude emits no phase-skill packages or inter-skill machine contracts. +Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four workflow entrypoints and their four skill packages rather than in agent bodies. Each agent's `skill:` permission allowlist names exactly the workflow slugs for its role: `sce-change-to-plan` for Plan; `sce-next-task`, `sce-validate`, and `sce-commit` for Code. +The canonical workflow definitions remain phase-decomposed as authoring source: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. No target generates those phase modules as packages. All three consume them as inputs to the shared `workflow-composite.pkl` renderer, which composes each workflow into one skill package. +Every target preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command or Pi prompt invokes exactly one corresponding skill, and OpenCode command frontmatter names that single skill as both `entry-skill` and the whole `skills` chain. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. No target emits phase-skill packages or inter-skill machine contracts; phase statuses stay internal to one skill invocation. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. The prior no-git-wrapper Agent Trace design artifacts under `context/sce/agent-trace-*.md` are retained only as historical reference; the current CLI runtime no longer wires the removed Agent Trace schema adaptation, payload building, retry replay, or rewrite handling paths into local hook execution. @@ -70,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. OpenCode consumes the canonical phase packages and result contracts directly, while Claude and Pi compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. OpenCode, Claude, and Pi all compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer, which is parameterized only by the extra frontmatter each target supports. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. @@ -102,7 +102,7 @@ Lightweight post-task verification baseline (required after each completed task) ## Cross-target parity -- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping. Pi consumes exactly four thin prompts and four workflow-level skill packages with no agent-role prompts. Manual OpenCode consumes the canonical phase packages as exactly four commands, eight skills, and two thin routing agents. Claude consumes exactly four thin commands and the same four workflow-level skill packages, with no generated agents; its generated settings and hook helper remain. Every workflow-level package contains only `SKILL.md` and `references/output.md`. +- OpenCode, Claude, and Pi are generated from canonical Pkl content with per-target capability mapping, and all three receive the same four workflow-level skill packages. Pi consumes exactly four thin prompts with no agent-role prompts and no added frontmatter. Manual OpenCode consumes exactly four commands plus two thin routing agents, and its package entrypoints carry `compatibility: opencode`. Claude consumes exactly four thin commands with no generated agents; its generated settings and hook helper remain. Every workflow-level package contains only `SKILL.md` and `references/output.md`, so each target's generated workflow inventory is four entrypoints plus eight skill Markdown files. - When capabilities differ, parity is implemented by supported target-specific behavior rather than forcing unsupported fields. ## Context navigation diff --git a/context/patterns.md b/context/patterns.md index ae83f079..c86786ba 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -68,8 +68,8 @@ ## Thin command orchestration -- Keep OpenCode command bodies thin when phase skills define detailed contracts: `/change-to-plan` sequences context load then plan authoring; `/next-task` sequences review, execution, and task context sync; `/validate` sequences validation then validated-only plan context sync; `/commit` delegates staged-diff analysis to atomic commit. -- Keep Claude commands and Pi prompts thinner still: parse nothing and invoke exactly one workflow-level skill. The composite skill owns input parsing, every phase, user waits, writes, verification, synchronization, and continuation rendering. +- Keep every target's commands and Pi prompts equally thin: parse nothing and invoke exactly one workflow-level skill. The composite skill owns input parsing, every phase, user waits, writes, verification, synchronization, and continuation rendering. No command sequences phases. +- Keep the canonical phase sequence in the workflow modules, not in command bodies: `/change-to-plan` runs context load then plan authoring; `/next-task` runs review, execution, and task context sync; `/validate` runs validation then validated-only plan context sync; `/commit` runs staged-diff analysis and message authoring. Each sequence executes inside its one composed skill. - Preserve mandatory gates and authoritative internal state while removing duplicated behavior from agents, commands, or sibling packages. ## Multi-file generation entrypoint diff --git a/context/plans/pi-opencode-workflow-single-skill-packages.md b/context/plans/pi-opencode-workflow-single-skill-packages.md index 0dc1f1ea..437e20a0 100644 --- a/context/plans/pi-opencode-workflow-single-skill-packages.md +++ b/context/plans/pi-opencode-workflow-single-skill-packages.md @@ -28,34 +28,34 @@ workflow slugs. Claude's generated bytes must not change. ## Acceptance criteria -- [ ] AC1: Pi generates exactly four prompts and eight skill Markdown files — +- [x] AC1: Pi generates exactly four prompts and eight skill Markdown files — `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`, each with exactly `SKILL.md` and `references/output.md` — and no phase-skill package. - Validate: `nix run .#pkl-generate -- "$(mktemp -d)"` then inspect `config/.pi/skills` for exactly those eight paths and `config/.pi/prompts` for exactly four files. -- [ ] AC2: OpenCode generates exactly four commands and the same eight skill +- [x] AC2: OpenCode generates exactly four commands and the same eight skill Markdown files under four packages, plus its two unchanged routing agents. - Validate: same generation root; inspect `config/.opencode/skills`, `config/.opencode/command`, and `config/.opencode/agent`. -- [ ] AC3: Each Pi prompt and OpenCode command routes to exactly its one +- [x] AC3: Each Pi prompt and OpenCode command routes to exactly its one corresponding workflow skill and names no other workflow skill; OpenCode command frontmatter declares that single skill as both entry skill and the whole skill chain. - Validate: `pkl eval config/pkl/renderers/metadata-coverage-check.pkl` — the route assertion covers Pi and OpenCode, not only Claude. -- [ ] AC4: Claude's generated output is byte-identical to the pre-change output. +- [x] AC4: Claude's generated output is byte-identical to the pre-change output. - Validate: generate into a temp root before the first commit of this plan and after the last, then `diff -r /config/.claude /config/.claude` reports no differences. -- [ ] AC5: OpenCode routing agents allow exactly the four workflow skills and no +- [x] AC5: OpenCode routing agents allow exactly the four workflow skills and no phase skill. - Validate: inspect the generated `config/.opencode/agent/*.md` `permission.skill` blocks for `sce-change-to-plan` (Plan) and `sce-next-task` / `sce-validate` / `sce-commit` (Code), with no `sce-context-load`-style entries. -- [ ] AC6: Durable context describes the single-skill package model for all three +- [x] AC6: Durable context describes the single-skill package model for all three targets, and a decision record supersedes the Pi/OpenCode decomposition claims in `2026-07-27-workflow-oriented-pkl-generation.md` and the Pi/OpenCode preservation clause in `2026-07-29-claude-workflow-skill-packages.md`. @@ -254,7 +254,7 @@ workflow slugs. Claude's generated bytes must not change. The generated file count dropped from 59 to 46 as OpenCode's eight phase packages collapsed to four two-file packages. -- [ ] T04: `Record the cross-target single-skill decision and realign durable context` (status:todo) +- [x] T04: `Record the cross-target single-skill decision and realign durable context` (status:done) - Task ID: T04 - Goal: Add a decision record establishing single-skill workflow packages for all three targets, mark the superseded scope in the two prior records, and @@ -274,6 +274,47 @@ workflow slugs. Claude's generated bytes must not change. "sce-context-load\|sce-plan-review\|sce-atomic-commit" context/ --include=*.md` and confirm every remaining hit is a plan file, a historical record, or an explicit superseded/authoring-source reference; `nix flake check`. + - Completed: 2026-07-29 + - Files changed: + `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md` (new), + `context/decisions/2026-07-29-claude-workflow-skill-packages.md`, + `context/decisions/2026-07-27-workflow-oriented-pkl-generation.md`, + `context/decisions/2026-03-03-plan-code-agent-separation.md`, + `context/overview.md`, `context/architecture.md`, `context/glossary.md`, + `context/context-map.md`, `context/sce/shared-context-plan-workflow.md`, + `context/sce/shared-context-code-workflow.md`, + `context/sce/atomic-commit-workflow.md`, + `context/sce/dedup-ownership-table.md`, + `context/sce/plan-code-overlap-map.md`, + `context/plans/pi-opencode-workflow-single-skill-packages.md` + - Evidence: The new record establishes four thin entrypoints plus four two-file + workflow packages for all three targets, one shared composite renderer, no + phase package or phase-result transport on any target, and OpenCode's two + routing agents with allowlists narrowed to the four workflow slugs. Its + rationale states the transport failure was observed on Claude only and that Pi + and OpenCode were collapsed for cross-target uniformity, naming the lost + explicit phase contracts as the trade-off. Both prior records carry a status + line, inline supersession notes on each now-false clause, and a Superseded + scope paragraph naming the new record. Durable files were rewritten so phase + names denote canonical authoring modules and internal phases: `overview.md` + (phase-decomposition-as-authoring-source, cross-target package model, + parity inventory, repository model), `architecture.md` (renderer bullets split + into shared composition plus per-target frontmatter, coverage-check and + `generate.pkl` inventories, plan/code role boundary), `glossary.md` (three + orchestration-contract entries, `workflow skill package`, `workflow composite + renderer`, plus a new `canonical phase module` entry), `context-map.md` + (decision index and three workflow-file descriptions), and the five + `context/sce/` workflow files including their Mermaid node labels. The + `2026-03-03` record's one stale `/next-task` delegation bullet got the same + inline note. Verification grep returns only canonical-source references, + explicit superseded notes, phase-name headings, and plan files — no durable + file states any target consumes eight phase packages. `nix flake check` + passed. Every changed file is at or below 250 lines. + - Notes: `context/sce/context-workflow-rules.md` needed no edit; its phase + references describe canonical synchronization behavior, not a generated + package surface. `2026-03-03-plan-code-agent-separation.md` was outside the + task's listed files but received a one-line supersession note to avoid leaving + a live contradiction with the new record. ## Open questions @@ -289,3 +330,40 @@ workflow slugs. Claude's generated bytes must not change. of "similar to Claude" extends to Claude's no-generated-agents posture, say so and T03 grows to remove `config/.opencode/agent` and retire `2026-03-03-plan-code-agent-separation.md`. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-29 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral generation passed: 46 files, inventory sha256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`) +- `nix flake check` -> exit 0 (all checks passed) +- `nix develop -c pkl eval config/pkl/renderers/metadata-coverage-check.pkl` -> exit 0 (19 inventory checks complete, covering Claude, Pi, and OpenCode inventories and all twelve command routes) +- `nix run .#pkl-generate -- ` -> exit 0 (post-change generation for inspection) +- `nix run .#pkl-generate -- ` from a detached worktree at `4133819` -> exit 0 (pre-change baseline) +- `diff -r /config/.claude /config/.claude` -> exit 0 (no differences) + +### Scaffolding removed + +- Detached Git worktree at the pre-change baseline commit — created only to generate the AC4 comparison baseline; removed with `git worktree remove --force`. +- Temp generation roots under the session scratchpad — ephemeral generation output outside the repository. + +### Success-criteria verification + +- [x] AC1: Pi emits four prompts and eight workflow-skill files -> `config/.pi/skills` contains exactly `sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`, each with only `SKILL.md` and `references/output.md`; `config/.pi/prompts` contains exactly `change-to-plan.md`, `commit.md`, `next-task.md`, `validate.md`. No phase package present. +- [x] AC2: OpenCode emits four commands, the same eight skill files, and two agents -> `config/.opencode/skills` has the same eight paths, `config/.opencode/command` has four files, `config/.opencode/agent` has `Shared Context Plan.md` and `Shared Context Code.md`. +- [x] AC3: Each entrypoint routes to exactly one workflow skill -> coverage check reports `pi-command-route-*` and `opencode-command-route-*` complete alongside Claude's; generated OpenCode command frontmatter declares `entry-skill` and a one-entry `skills` list naming the same slug; grep over prompts and commands shows each file names only its own slug. +- [x] AC4: Claude output byte-identical -> `diff -r` between generation from the pre-plan commit `4133819` and current HEAD+worktree reported no differences for `config/.claude`. +- [x] AC5: OpenCode agent allowlists -> Plan agent `permission.skill` is `"*": ask` plus `sce-change-to-plan`; Code agent is `"*": ask` plus `sce-next-task`, `sce-validate`, `sce-commit`. No phase-skill entry. +- [x] AC6: Durable context realigned -> `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md` exists with rationale, consequences, and a Superseded scope section; the 2026-07-27 and 2026-07-29 Claude records carry status lines, inline superseded notes, and pointers to it. Grep for the eight phase slugs across `context/` outside `context/plans/` returns only canonical-authoring-module references, explicit superseded notes, and internal-phase descriptions. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- Pi and OpenCode were collapsed for uniformity, not because either was observed exhibiting Claude's phase-result transport failure. The lost explicit phase contracts are recorded as a deliberate trade-off in the new decision record; the runtime behavior of the composed `SKILL.md` files on those two targets has not been exercised end to end here. +- `context/patterns.md` is modified in the working tree but was not listed among T04's changed files. It is consistent with the finished implementation but its edit is unattributed in task evidence. diff --git a/context/sce/atomic-commit-workflow.md b/context/sce/atomic-commit-workflow.md index a8fcfbda..f108a1fe 100644 --- a/context/sce/atomic-commit-workflow.md +++ b/context/sce/atomic-commit-workflow.md @@ -7,15 +7,16 @@ Behavior contract for the generated `/commit` workflow. Canonical behavior is authored in `config/pkl/base/workflow-commit.pkl` from the project-root `.pi/` baseline and generated for OpenCode, Claude, and Pi. -- OpenCode emits the canonical command plus the `sce-atomic-commit` phase - package, its YAML result contract, and commit-message style reference. -- Claude and Pi emit one thin command invoking `sce-commit`. The composite package - contains only `SKILL.md`, which owns mode routing, staged-diff analysis, - proposal/commit behavior, and internal statuses, plus `references/output.md`, - which owns all human-visible prompts and result layouts. +Every target emits one thin command (Pi: prompt) invoking `sce-commit`. The +composite package contains only `SKILL.md`, which owns mode routing, staged-diff +analysis, proposal/commit behavior, and internal statuses, plus +`references/output.md`, which owns all human-visible prompts and result layouts. +The commit-message style reference is composed into those two files rather than +emitted separately. -Claude's package invokes no `sce-atomic-commit` sibling skill; it embeds the -canonical phase behavior directly. +No target emits an `sce-atomic-commit` package or invokes it as a sibling skill; +each `sce-commit` package embeds the canonical phase behavior directly. +`sce-atomic-commit` names the canonical authoring module and that internal phase. ## Modes @@ -36,13 +37,13 @@ flowchart TD B -- yes --> D[Bypass mode] C --> C1[Stop and prompt for staging confirmation] - C1 --> C2[sce-atomic-commit mode: regular] + C1 --> C2[Phase: atomic commit, mode: regular] C2 --> C3[Present proposals + split guidance] C3 --> C4([Stop — never commits]) D --> D1{git diff --cached
non-empty?} D1 -- no --> D2([Stop: No staged changes.
Stage changes before commit.]) - D1 -- yes --> D3[sce-atomic-commit mode: bypass] + D1 -- yes --> D3[Phase: atomic commit, mode: bypass] D3 --> D4[Exactly one git commit] D4 --> D5([Report hash, or report failure
with no retry or amend]) ``` @@ -109,7 +110,7 @@ staged explicitly; bypass mode omits the citation instead of stopping. ## Result contract -OpenCode's phase skill returns exactly one YAML result: +The canonical analysis phase reaches exactly one of three results: - `proposal` — regular mode, one or more messages, optional split rationale and staged-scope classification. @@ -119,9 +120,9 @@ OpenCode's phase skill returns exactly one YAML result: `no_staged_changes`, `plan_citation_ambiguity`, `unreadable_diff`, and `contradictory_context`. -Claude keeps the equivalent status as internal `sce-commit` state and renders -only the applicable layout from `references/output.md`. Every staged file still -belongs to exactly one commit message. The analysis phase never reports a hash; +Every target keeps that status as internal `sce-commit` state and renders only +the applicable layout from `references/output.md`; no result is serialized +between packages. Every staged file still belongs to exactly one commit message. The analysis phase never reports a hash; only successful bypass-mode `git commit` produces one. ## Related context diff --git a/context/sce/dedup-ownership-table.md b/context/sce/dedup-ownership-table.md index e45cf3e6..aaef0780 100644 --- a/context/sce/dedup-ownership-table.md +++ b/context/sce/dedup-ownership-table.md @@ -2,29 +2,31 @@ ## Scope and method -- Canonical workflow sources: `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl`. +- Canonical workflow sources: `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`. - Shared package model: `config/pkl/base/workflow-content.pkl`. - Shared synchronization source: `config/pkl/base/workflow-context-sync.pkl`. - Generated consumers: `config/.opencode/**`, `config/.claude/**`, and `config/.pi/**`. -- Assignment rule: each workflow phase has one canonical skill owner; commands and agents only orchestrate or route. +- Assignment rule: each workflow phase has one canonical module owner; commands and agents only orchestrate or route. +- Canonical phase modules are authoring inputs to `config/pkl/renderers/workflow-composite.pkl`. No target generates them as packages; each is composed into the workflow skill named in the consumer column. ## Ownership matrix | Behavior domain | Canonical owner | Reference-only consumers | Label | | --- | --- | --- | --- | -| Context discovery before planning | `sce-context-load` in `workflow-change-to-plan.pkl` | `/change-to-plan`; generated target packages | intentional/keep | -| Plan authoring, clarification, and task slicing | `sce-plan-authoring` in `workflow-change-to-plan.pkl` | `/change-to-plan`; thin OpenCode Plan agent | intentional/keep | -| Task resolution and readiness | `sce-plan-review` in `workflow-next-task.pkl` | `/next-task`; thin OpenCode Code agent | intentional/keep | -| Approval-gated one-task implementation | `sce-task-execution` in `workflow-next-task.pkl` | `/next-task`; thin OpenCode Code agent | intentional/keep | -| Post-task durable context synchronization | Task instance from `workflow-context-sync.pkl` | `/next-task`; generated `sce-task-context-sync` packages | dedup/shared skeleton | -| Final validation and validation report | `sce-validation` in `workflow-validate.pkl` | `/validate`; thin OpenCode Code agent | intentional/keep | -| Validated-plan durable context synchronization | Plan instance from `workflow-context-sync.pkl` | `/validate`; generated `sce-plan-context-sync` packages | dedup/shared skeleton | -| Workflow routing | Three command documents in the workflow modules | Thin OpenCode Plan/Code agents | intentional/keep | +| Context discovery before planning | `sce-context-load` in `workflow-change-to-plan.pkl` | `/change-to-plan`; composed into `sce-change-to-plan` | intentional/keep | +| Plan authoring, clarification, and task slicing | `sce-plan-authoring` in `workflow-change-to-plan.pkl` | `/change-to-plan`; composed into `sce-change-to-plan`; thin OpenCode Plan agent | intentional/keep | +| Task resolution and readiness | `sce-plan-review` in `workflow-next-task.pkl` | `/next-task`; composed into `sce-next-task`; thin OpenCode Code agent | intentional/keep | +| Approval-gated one-task implementation | `sce-task-execution` in `workflow-next-task.pkl` | `/next-task`; composed into `sce-next-task`; thin OpenCode Code agent | intentional/keep | +| Post-task durable context synchronization | Task instance from `workflow-context-sync.pkl` | `/next-task`; composed into `sce-next-task` | dedup/shared skeleton | +| Final validation and validation report | `sce-validation` in `workflow-validate.pkl` | `/validate`; composed into `sce-validate`; thin OpenCode Code agent | intentional/keep | +| Validated-plan durable context synchronization | Plan instance from `workflow-context-sync.pkl` | `/validate`; composed into `sce-validate` | dedup/shared skeleton | +| Staged-diff analysis and commit-message authoring | `sce-atomic-commit` in `workflow-commit.pkl` | `/commit`; composed into `sce-commit`; thin OpenCode Code agent | intentional/keep | +| Workflow routing | Four command documents in the workflow modules | Thin OpenCode Plan/Code agents | intentional/keep | ## Guardrails - Keep Plan and Code routing roles separate without placing workflow doctrine in agent bodies. -- Keep commands at sequencing, branching, and handoff scope; phase behavior remains skill-owned. -- Keep task and plan synchronization packages self-contained even though one Pkl skeleton owns their shared policy. +- Keep commands thin: each routes to exactly one workflow skill and owns no phase behavior. +- Keep task and plan synchronization policy in the one shared Pkl skeleton even though each workflow skill composes its own instance. - Do not reintroduce removed `/handover`, legacy context-sync, or automated-profile Markdown ownership. -- `/commit` is being restored as a fourth workflow. Its behavioral baseline exists in the project-root `.pi/` package (see [Atomic commit workflow](atomic-commit-workflow.md)); canonical Pkl ownership and generated target inventories still carry only the three workflows above. +- Do not reintroduce phase skills as a generated surface. Behavior belongs in the canonical modules; installation belongs to the four workflow packages (see [Atomic commit workflow](atomic-commit-workflow.md) for `/commit`). diff --git a/context/sce/plan-code-overlap-map.md b/context/sce/plan-code-overlap-map.md index ce984686..32329157 100644 --- a/context/sce/plan-code-overlap-map.md +++ b/context/sce/plan-code-overlap-map.md @@ -2,27 +2,28 @@ ## Scope reviewed -- Canonical packages: `config/pkl/base/workflow-{change-to-plan,next-task,validate}.pkl` +- Canonical packages: `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` - Shared synchronization skeleton: `config/pkl/base/workflow-context-sync.pkl` - Generated OpenCode routing agents and workflow commands under `config/.opencode/` -- Seven canonical phase skills, rendered as packages for OpenCode and composed into workflow skills for Claude and Pi +- Eight canonical phase modules, composed into four workflow skills for every target and rendered as packages for none ## Overlap matrix | Surface | Shared reusable content | Surface-specific content | Ownership rule | | --- | --- | --- | --- | | Shared Context Plan agent | References the planning workflow | Routes Plan work to `/change-to-plan` | Keep routing-only; command and skills own behavior | -| Shared Context Code agent | References implementation lifecycle | Routes Code work to `/next-task` and `/validate` | Keep routing-only; command and skills own behavior | -| `/change-to-plan` | Structured handoffs and result branching | Sequences `sce-context-load` then `sce-plan-authoring` | Skills own context loading and plan authoring | -| `/next-task` | Structured handoffs and result branching | Sequences review, one-task execution, task sync, and continuation | `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync` own phases | -| `/validate` | Structured handoffs and result branching | Sequences final validation then validated-only plan sync | `sce-validation` and `sce-plan-context-sync` own phases | -| Task/plan context sync | Root-pass, context hygiene, and synchronization policy | Distinct handoff gates and report lifecycle | One parameterized Pkl skeleton emits two self-contained packages | +| Shared Context Code agent | References implementation lifecycle | Routes Code work to `/next-task`, `/validate`, and `/commit` | Keep routing-only; command and skills own behavior | +| `/change-to-plan` | Thin routing to one workflow skill | Routes to `sce-change-to-plan` | The skill runs the context-load and plan-authoring phases internally | +| `/next-task` | Thin routing to one workflow skill | Routes to `sce-next-task` | The skill runs review, one-task execution, task sync, and continuation internally | +| `/validate` | Thin routing to one workflow skill | Routes to `sce-validate` | The skill runs final validation then validated-only plan sync internally | +| `/commit` | Thin routing to one workflow skill | Routes to `sce-commit` | The skill runs mode routing, staged-diff analysis, and message authoring internally | +| Task/plan context sync | Root-pass, context hygiene, and synchronization policy | Distinct entry gates and report lifecycle | One parameterized Pkl skeleton composes into `sce-next-task` and `sce-validate` | ## Current dedup boundary -- Workflow commands own phase ordering, result branching, and authoritative handoff forwarding. -- Skills own detailed phase policy, gates, edits, verification, and result/report formats. -- Thin OpenCode agents own only role-to-command routing and target permissions. +- Workflow commands own only routing to one workflow skill. +- Workflow skills own phase ordering, status branching, gates, edits, verification, and result/report formats. +- Thin OpenCode agents own only role-to-command routing and target permissions; their skill allowlists name exactly the four workflow slugs. - Claude and Pi do not receive generated agents. -- Package-local reference files are duplicated in generated targets by design so every skill package remains self-contained. +- Each workflow package carries exactly one reference file, `references/output.md`, so it remains self-contained without cross-package dependencies. - The removed grouped shared-content catalog and automated OpenCode profile have no current owner or consumer. diff --git a/context/sce/shared-context-code-workflow.md b/context/sce/shared-context-code-workflow.md index f52dfa08..dcc03dca 100644 --- a/context/sce/shared-context-code-workflow.md +++ b/context/sce/shared-context-code-workflow.md @@ -2,7 +2,7 @@ ## Purpose -The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. OpenCode retains phase-skill sequencing; Claude and Pi embed each complete lifecycle in `sce-next-task` or `sce-validate`. +The implementation lifecycle executes at most one reviewed task per `/next-task` invocation, synchronizes durable context only after successful task execution, and runs final plan validation separately through `/validate`. The generated OpenCode Code agent only routes to these commands. Every target embeds each complete lifecycle in `sce-next-task` or `sce-validate`; the phases below are canonical authoring source and internal phases of those skills, not separate generated packages. ## `/next-task` entrypoint @@ -15,6 +15,8 @@ The implementation lifecycle executes at most one reviewed task per `/next-task` ## `/next-task` phase ownership +Phase names below identify canonical modules in `config/pkl/base/workflow-next-task.pkl` and `workflow-context-sync.pkl`, and the internal phases they compose into. + 1. `sce-plan-review` - Resolves exactly one plan and at most one task. - Selects the requested task or the first incomplete task whose declared dependencies are complete. @@ -36,7 +38,7 @@ The implementation lifecycle executes at most one reviewed task per `/next-task` - Emits exactly one next-task command for the first unchecked task in plan order, or a `/validate` command when all implementation tasks are complete. - Never executes the continuation in the same invocation. -A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. On Claude and Pi, review, approval, execution, evidence recording, synchronization, and continuation are internal phases of one `sce-next-task` invocation rather than sibling skill calls. +A context-sync blocker does not undo successful implementation: the task remains complete in the plan, but the workflow stops because durable context is stale. On every target, review, approval, execution, evidence recording, synchronization, and continuation are internal phases of one `sce-next-task` invocation rather than sibling skill calls. ## `/validate` entrypoint @@ -46,32 +48,32 @@ A context-sync blocker does not undo successful implementation: the task remains 2. Failed or blocked validation ends the session without repair edits; retry uses `/validate {plan-path}`. 3. `sce-plan-context-sync` runs only from a successful `Status: validated` handoff and reconciles the completed plan with durable repository context. -On Claude and Pi, those validation and plan-sync phases execute inside one `sce-validate` skill; failed and blocked statuses stop before synchronization exactly as in the canonical flow. Final validation never runs from an individual implementation task. +On every target, those validation and plan-sync phases execute inside one `sce-validate` skill; failed and blocked statuses stop before synchronization exactly as in the canonical flow. Final validation never runs from an individual implementation task. ## Flow ```mermaid flowchart TD - A["/next-task {plan} {task?} {approved?}"] --> B["sce-plan-review"] + A["/next-task {plan} {task?} {approved?}"] --> B["Phase: plan review"] B --> C{"ready?"} C -- "No" --> D["Report blocked or plan_complete"] - C -- "Yes" --> E["sce-task-execution gate"] + C -- "Yes" --> E["Phase: task execution gate"] E --> F{"complete?"} F -- "No" --> G["Report declined, blocked, or incomplete"] - F -- "Yes" --> H["sce-task-context-sync"] + F -- "Yes" --> H["Phase: task context sync"] H --> I{"More tasks?"} I -- "Yes" --> J["Emit next /next-task command"] I -- "No" --> K["Emit /validate command"] - K --> L["sce-validation"] + K --> L["Phase: validation"] L --> M{"validated?"} - M -- "Yes" --> N["sce-plan-context-sync"] + M -- "Yes" --> N["Phase: plan context sync"] M -- "No" --> O["Stop and retry /validate later"] ``` ## Target ownership -- OpenCode: command sequencing plus the canonical review, execution, validation, and context-sync phase packages. -- Claude and Pi: thin commands invoking `sce-next-task` or `sce-validate`; each package contains only `SKILL.md` and `references/output.md`. +- OpenCode, Claude, and Pi: thin commands (Pi: prompts) invoking `sce-next-task` or `sce-validate`; each package contains only `SKILL.md` and `references/output.md`. +- OpenCode adds `entry-skill` and a one-entry `skills` list naming that skill, and its Code routing agent allows exactly `sce-next-task`, `sce-validate`, and `sce-commit`. ## Canonical sources diff --git a/context/sce/shared-context-plan-workflow.md b/context/sce/shared-context-plan-workflow.md index 6200fa3c..4e7d6ddb 100644 --- a/context/sce/shared-context-plan-workflow.md +++ b/context/sce/shared-context-plan-workflow.md @@ -2,7 +2,7 @@ ## Purpose -`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface. OpenCode behavior is owned by the command and two canonical phase skills; Claude and Pi render the same behavior into the single `sce-change-to-plan` workflow skill. +`/change-to-plan` turns one change request into one scoped implementation plan under `context/plans/`. The generated OpenCode Plan agent is only a routing surface. Every target renders the same behavior into the single `sce-change-to-plan` workflow skill; the two phases below are canonical authoring source and internal phases of that skill, not separate generated packages. ## Command entrypoint @@ -12,6 +12,8 @@ The request must be non-empty. The workflow does not accept approval or executio ## Phase ownership +Phase names below identify canonical modules in `config/pkl/base/workflow-change-to-plan.pkl` and the internal phases they compose into. + 1. `sce-context-load` - Confirms whether `context/` exists. - Loads only durable context relevant to the requested focus. @@ -23,7 +25,7 @@ The request must be non-empty. The workflow does not accept approval or executio - Creates or updates one plan with stable task IDs, explicit scope, dependencies, done checks, and verification notes. - Returns `plan_ready`, `needs_clarification`, or `blocked`. -OpenCode forwards each phase result as the authoritative handoff rather than reconstructing it. Claude and Pi keep the equivalent status and data as internal state inside `sce-change-to-plan`; no sibling skill handoff exists. +Every target keeps those statuses and their data as internal state inside `sce-change-to-plan` and continues immediately across the phase boundary. No sibling skill handoff and no serialized phase-result contract exists on any target. ## Bootstrap boundary @@ -31,9 +33,8 @@ When context loading returns `bootstrap_required`, the workflow stops without cr `sce setup --bootstrap-context` -After the user reports that bootstrap completed, the waiting workflow invokes -`sce-context-load` again and continues with the original request in the same -session. +After the user reports that bootstrap completed, the waiting workflow re-runs the +context-load phase and continues with the original request in the same session. ## Planning boundary @@ -47,10 +48,10 @@ session. ```mermaid flowchart TD - A["/change-to-plan {request}"] --> B["sce-context-load"] + A["/change-to-plan {request}"] --> B["Phase: context load"] B --> C{"Context available?"} C -- "No" --> D["Stop: sce setup --bootstrap-context"] - C -- "Yes" --> E["sce-plan-authoring"] + C -- "Yes" --> E["Phase: plan authoring"] E --> F{"Authoring result"} F -- "needs_clarification" --> G["Ask only the reported questions"] F -- "blocked" --> H["Report blocker and required action"] @@ -59,11 +60,11 @@ flowchart TD ## Target ownership -- OpenCode: command sequencing plus `sce-context-load` and `sce-plan-authoring` packages. -- Claude and Pi: one thin command invoking `sce-change-to-plan`; package files are `SKILL.md` and `references/output.md`. +- OpenCode, Claude, and Pi: one thin command (Pi: prompt) invoking `sce-change-to-plan`; package files are `SKILL.md` and `references/output.md`. +- OpenCode adds `entry-skill` and a one-entry `skills` list naming that skill, and its Plan routing agent allows exactly `sce-change-to-plan`. ## Canonical sources - `config/pkl/base/workflow-change-to-plan.pkl` -- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared; Claude and Pi consume it) +- Workflow composition: `config/pkl/renderers/workflow-composite.pkl` (shared by all three targets) - Behavioral baseline: `.pi/prompts/change-to-plan.md` From bc09266803d22f823f89a663dd76239d2f896065 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 17:19:12 +0200 Subject: [PATCH 18/21] config: Regenerate Pi and OpenCode targets as single-skill workflow packages Co-authored-by: SCE --- .opencode/agent/Shared Context Code.md | 9 +- .opencode/agent/Shared Context Plan.md | 3 +- .opencode/command/change-to-plan.md | 180 +--- .opencode/command/commit.md | 134 +-- .opencode/command/next-task.md | 197 +--- .opencode/command/validate.md | 149 +-- .opencode/skills/sce-atomic-commit/SKILL.md | 167 ---- .../references/commit-contract.yaml | 205 ---- .opencode/skills/sce-change-to-plan/SKILL.md | 804 +++++++++++++++ .../sce-change-to-plan/references/output.md | 59 ++ .opencode/skills/sce-commit/SKILL.md | 334 +++++++ .../references/output.md} | 41 +- .opencode/skills/sce-context-load/SKILL.md | 129 --- .../references/context-brief.yaml | 153 --- .opencode/skills/sce-next-task/SKILL.md | 939 ++++++++++++++++++ .../references/output.md} | 141 +++ .opencode/skills/sce-plan-authoring/SKILL.md | 290 ------ .../references/authoring-contract.yaml | 256 ----- .../references/plan-template.md | 170 ---- .../skills/sce-plan-context-sync/SKILL.md | 309 ------ .../references/sync-report.md | 142 --- .opencode/skills/sce-plan-review/SKILL.md | 149 --- .../references/readiness-contract.yaml | 246 ----- .../skills/sce-task-context-sync/SKILL.md | 311 ------ .opencode/skills/sce-task-execution/SKILL.md | 247 ----- .../references/execution-contract.yaml | 306 ------ .../references/implementation-gate.md | 69 -- .opencode/skills/sce-validate/SKILL.md | 767 ++++++++++++++ .../skills/sce-validate/references/output.md | 429 ++++++++ .opencode/skills/sce-validation/SKILL.md | 190 ---- .../references/validation-report.md | 84 -- .../references/validation-result.md | 186 ---- .pi/prompts/change-to-plan.md | 175 +--- .pi/prompts/commit.md | 130 +-- .pi/prompts/next-task.md | 191 +--- .pi/prompts/validate.md | 144 +-- .pi/skills/sce-atomic-commit/SKILL.md | 166 ---- .../references/commit-contract.yaml | 205 ---- .pi/skills/sce-change-to-plan/SKILL.md | 803 +++++++++++++++ .../sce-change-to-plan/references/output.md | 59 ++ .pi/skills/sce-commit/SKILL.md | 333 +++++++ .../references/output.md} | 41 +- .pi/skills/sce-context-load/SKILL.md | 128 --- .../references/context-brief.yaml | 153 --- .pi/skills/sce-next-task/SKILL.md | 938 +++++++++++++++++ .../references/output.md} | 141 +++ .pi/skills/sce-plan-authoring/SKILL.md | 289 ------ .../references/authoring-contract.yaml | 256 ----- .../references/plan-template.md | 170 ---- .pi/skills/sce-plan-context-sync/SKILL.md | 308 ------ .../references/sync-report.md | 142 --- .pi/skills/sce-plan-review/SKILL.md | 148 --- .../references/readiness-contract.yaml | 246 ----- .pi/skills/sce-task-context-sync/SKILL.md | 310 ------ .pi/skills/sce-task-execution/SKILL.md | 246 ----- .../references/execution-contract.yaml | 306 ------ .../references/implementation-gate.md | 69 -- .pi/skills/sce-validate/SKILL.md | 766 ++++++++++++++ .pi/skills/sce-validate/references/output.md | 429 ++++++++ .pi/skills/sce-validation/SKILL.md | 189 ---- .../references/validation-report.md | 84 -- .../references/validation-result.md | 186 ---- 62 files changed, 7066 insertions(+), 8480 deletions(-) delete mode 100644 .opencode/skills/sce-atomic-commit/SKILL.md delete mode 100644 .opencode/skills/sce-atomic-commit/references/commit-contract.yaml create mode 100644 .opencode/skills/sce-change-to-plan/SKILL.md rename .pi/skills/sce-plan-authoring/references/plan-summary.md => .opencode/skills/sce-change-to-plan/references/output.md (69%) create mode 100644 .opencode/skills/sce-commit/SKILL.md rename .opencode/skills/{sce-atomic-commit/references/commit-message-style.md => sce-commit/references/output.md} (69%) delete mode 100644 .opencode/skills/sce-context-load/SKILL.md delete mode 100644 .opencode/skills/sce-context-load/references/context-brief.yaml create mode 100644 .opencode/skills/sce-next-task/SKILL.md rename .opencode/skills/{sce-task-context-sync/references/sync-report.md => sce-next-task/references/output.md} (50%) delete mode 100644 .opencode/skills/sce-plan-authoring/SKILL.md delete mode 100644 .opencode/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 .opencode/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 .opencode/skills/sce-plan-context-sync/SKILL.md delete mode 100644 .opencode/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 .opencode/skills/sce-plan-review/SKILL.md delete mode 100644 .opencode/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 .opencode/skills/sce-task-context-sync/SKILL.md delete mode 100644 .opencode/skills/sce-task-execution/SKILL.md delete mode 100644 .opencode/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 .opencode/skills/sce-task-execution/references/implementation-gate.md create mode 100644 .opencode/skills/sce-validate/SKILL.md create mode 100644 .opencode/skills/sce-validate/references/output.md delete mode 100644 .opencode/skills/sce-validation/SKILL.md delete mode 100644 .opencode/skills/sce-validation/references/validation-report.md delete mode 100644 .opencode/skills/sce-validation/references/validation-result.md delete mode 100644 .pi/skills/sce-atomic-commit/SKILL.md delete mode 100644 .pi/skills/sce-atomic-commit/references/commit-contract.yaml create mode 100644 .pi/skills/sce-change-to-plan/SKILL.md rename .opencode/skills/sce-plan-authoring/references/plan-summary.md => .pi/skills/sce-change-to-plan/references/output.md (69%) create mode 100644 .pi/skills/sce-commit/SKILL.md rename .pi/skills/{sce-atomic-commit/references/commit-message-style.md => sce-commit/references/output.md} (69%) delete mode 100644 .pi/skills/sce-context-load/SKILL.md delete mode 100644 .pi/skills/sce-context-load/references/context-brief.yaml create mode 100644 .pi/skills/sce-next-task/SKILL.md rename .pi/skills/{sce-task-context-sync/references/sync-report.md => sce-next-task/references/output.md} (50%) delete mode 100644 .pi/skills/sce-plan-authoring/SKILL.md delete mode 100644 .pi/skills/sce-plan-authoring/references/authoring-contract.yaml delete mode 100644 .pi/skills/sce-plan-authoring/references/plan-template.md delete mode 100644 .pi/skills/sce-plan-context-sync/SKILL.md delete mode 100644 .pi/skills/sce-plan-context-sync/references/sync-report.md delete mode 100644 .pi/skills/sce-plan-review/SKILL.md delete mode 100644 .pi/skills/sce-plan-review/references/readiness-contract.yaml delete mode 100644 .pi/skills/sce-task-context-sync/SKILL.md delete mode 100644 .pi/skills/sce-task-execution/SKILL.md delete mode 100644 .pi/skills/sce-task-execution/references/execution-contract.yaml delete mode 100644 .pi/skills/sce-task-execution/references/implementation-gate.md create mode 100644 .pi/skills/sce-validate/SKILL.md create mode 100644 .pi/skills/sce-validate/references/output.md delete mode 100644 .pi/skills/sce-validation/SKILL.md delete mode 100644 .pi/skills/sce-validation/references/validation-report.md delete mode 100644 .pi/skills/sce-validation/references/validation-result.md diff --git a/.opencode/agent/Shared Context Code.md b/.opencode/agent/Shared Context Code.md index 45e2debd..11c2dff9 100644 --- a/.opencode/agent/Shared Context Code.md +++ b/.opencode/agent/Shared Context Code.md @@ -23,12 +23,9 @@ permission: doom_loop: ask skill: "*": ask - "sce-plan-review": allow - "sce-task-execution": allow - "sce-task-context-sync": allow - "sce-validation": allow - "sce-plan-context-sync": allow - "sce-atomic-commit": allow + "sce-next-task": allow + "sce-validate": allow + "sce-commit": allow --- Route implementation work through `/next-task` and final plan validation through `/validate`. diff --git a/.opencode/agent/Shared Context Plan.md b/.opencode/agent/Shared Context Plan.md index 23425736..fa7abbcf 100644 --- a/.opencode/agent/Shared Context Plan.md +++ b/.opencode/agent/Shared Context Plan.md @@ -23,8 +23,7 @@ permission: doom_loop: ask skill: "*": ask - "sce-context-load": allow - "sce-plan-authoring": allow + "sce-change-to-plan": allow --- Route plan creation and revision through `/change-to-plan`. diff --git a/.opencode/command/change-to-plan.md b/.opencode/command/change-to-plan.md index 27cc07a2..caa890db 100644 --- a/.opencode/command/change-to-plan.md +++ b/.opencode/command/change-to-plan.md @@ -1,180 +1,12 @@ --- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Turn one change request into a scoped SCE plan in one self-contained workflow" argument-hint: "" agent: "Shared Context Plan" -entry-skill: "sce-context-load" +entry-skill: "sce-change-to-plan" skills: - - "sce-context-load" - - "sce-plan-authoring" + - "sce-change-to-plan" --- -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> Continue to the next step. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> Continue to the next step. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. +Invoke the `sce-change-to-plan` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.opencode/command/commit.md b/.opencode/command/commit.md index d1593d32..c17d71ce 100644 --- a/.opencode/command/commit.md +++ b/.opencode/command/commit.md @@ -1,134 +1,12 @@ --- -description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +description: "Analyze staged changes and run the regular or explicit bypass commit workflow" argument-hint: "[oneshot|skip] [commit context]" agent: "Shared Context Code" -entry-skill: "sce-atomic-commit" +entry-skill: "sce-commit" skills: - - "sce-atomic-commit" + - "sce-commit" --- -SCE COMMIT `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: - -`[mode-token] [commit context]` - -- `mode-token` is present only when the first whitespace-separated token is - exactly `oneshot` or `skip`, compared case-insensitively. Any other first - token is not a mode token. -- `commit context` is everything else: free-form prose that refines message - wording only. - -A `mode-token` selects the bypass path. Its absence selects the regular path. -Do not infer the bypass path from anything else — not from the commit context, -not from repository state, and not from the conversation. - -Empty `$ARGUMENTS` is valid. It selects the regular path with no commit -context, and commit intent is inferred from the staged changes alone. - -Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, -summarize, or pre-scope it. Never pass the `mode-token` as commit context. - -Staged changes are the source of truth for what is being committed. This -command never stages, unstages, or modifies files. - -## Workflow - -Follow exactly one path. - -### Bypass path (`oneshot` or `skip`) - -#### 1. Validate that staged content exists - -Run `git diff --cached --quiet`. A zero exit status means nothing is staged. - -When nothing is staged, stop with exactly: - -`No staged changes. Stage changes before commit.` - -Do not stage anything. Do not proceed to the skill. - -#### 2. Request one commit message - -Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. - -Bypass mode is the skill's contract for producing exactly one message. Do not -restate its overrides here; `sce-atomic-commit` owns them. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and stop. Do not commit. - -`bypass_message` -> Continue to the next step. - -The skill never returns `proposal` in bypass mode. Treat a `proposal` result as -a contract violation: report it and stop without committing. - -#### 3. Execute exactly one commit - -Run `git commit` once with the returned message. - -On success, report the resulting commit hash and stop. - -On failure, report the failure as returned by Git and stop. Do not retry, do -not amend, do not stage additional files, and do not invent a fallback commit. - -### Regular path (no mode token) - -#### 1. Confirm staging - -Before invoking the skill, stop and prompt the user: - -``` -Please run `git add ` for all changes you want included in this commit. -Atomic commits should only include intentionally staged changes. -Confirm once staging is complete. -``` - -Wait for the user's confirmation. Do not stage files on their behalf, and do -not skip this prompt because the working tree looks ready. - -#### 2. Propose commits - -After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the -commit context. - -`sce-atomic-commit` exclusively owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Classifying staged scope and applying context-file guidance gating. -- Writing every commit message subject and body. -- Applying the plan-citation body rule. - -Do not duplicate any of it. Do not write commit messages yourself. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and the decision it requires. Stop. - -`proposal` -> Present each proposed commit: its message, the files it covers, -and, when more than one commit is proposed, why the split is recommended. - -Then stop. The regular path is proposal-only. - -Do not run `git commit`. Do not offer to commit on the user's behalf. The user -runs the commits they accept. - -## Rules - -- Produce at most one commit per invocation, and only on the bypass path. -- Never commit on the regular path. -- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. - They are behaviorally identical. -- Do not duplicate the internal instructions of `sce-atomic-commit`. -- Do not stage, unstage, restore, or otherwise modify files. -- Do not amend, reset, revert, rebase, or push. -- Do not read unstaged or untracked changes as commit input. -- Do not infer success when `sce-atomic-commit` returns a non-success status. -- Do not proceed past a failed `git commit`. -- Do not run plan, task, or validation workflows from this command. +Invoke the `sce-commit` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.opencode/command/next-task.md b/.opencode/command/next-task.md index 9c2ff4e3..85373260 100644 --- a/.opencode/command/next-task.md +++ b/.opencode/command/next-task.md @@ -1,197 +1,12 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +description: "Review, approve, implement, verify, and synchronize one SCE plan task" argument-hint: " [T0X] [approved]" agent: "Shared Context Code" -entry-skill: "sce-plan-review" +entry-skill: "sce-next-task" skills: - - "sce-plan-review" - - "sce-task-execution" - - "sce-task-context-sync" + - "sce-next-task" --- -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> Pass the complete readiness result to `sce-task-execution`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> continue to the next step. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. +Invoke the `sce-next-task` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.opencode/command/validate.md b/.opencode/command/validate.md index 4b95c2ab..bdd82071 100644 --- a/.opencode/command/validate.md +++ b/.opencode/command/validate.md @@ -1,149 +1,12 @@ --- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +description: "Validate one completed SCE plan and synchronize its durable context" argument-hint: "" agent: "Shared Context Code" -entry-skill: "sce-validation" +entry-skill: "sce-validate" skills: - - "sce-validation" - - "sce-plan-context-sync" + - "sce-validate" --- -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. +Invoke the `sce-validate` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.opencode/skills/sce-atomic-commit/SKILL.md b/.opencode/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 98921e66..00000000 --- a/.opencode/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -name: sce-atomic-commit -description: > - Internal SCE workflow skill that analyzes the staged diff and returns atomic, - repository-style commit messages: coherent-unit detection, split guidance, - scope and subject wording, and the plan-citation body rule. Returns one YAML - result (proposal, bypass_message, or blocked). Use from /commit. Do not stage - files, create commits, or ask the user to confirm staging. -compatibility: opencode ---- - -# SCE Atomic Commit - -## Purpose - -Turn the current staged changes into atomic repository-style commit messages. - -This skill owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Choosing the scope and writing the subject and body of every message. -- Applying the plan-citation body rule. -- Classifying staged scope and applying context-file guidance gating. -- Returning one terminal YAML result. - -Write messages matching: - -`references/commit-message-style.md` - -Return a result matching: - -`references/commit-contract.yaml` - -Committing is not this skill's job. The invoking `/commit` workflow decides -whether a returned message is committed, and it is the only thing that runs -`git commit`. - -## Input - -The invoking workflow provides: - -- A mode: `regular` or `bypass`. -- Optional commit context, in free-form prose. - -The mode is supplied by the workflow from an explicit user-supplied token. -Never infer it, and never switch modes mid-analysis. - -Commit context refines wording only. The staged diff decides what the change -is; context never overrides staged truth, and never adds a claim the diff does -not support. - -Do not accept an unstaged diff, a working-tree summary, or a conversational -description as a substitute for the staged diff. - -## Workflow - -### 1. Read the staged diff - -Read the staged changes with `git diff --cached`, and the staged file list with -`git diff --cached --name-status`. - -Read staged file contents only when the diff alone does not explain the change. - -Return `blocked` when nothing is staged. - -### 2. Identify coherent units - -Infer the main reason for the staged change from the diff first. - -A coherent unit is one goal a reviewer would accept as a single commit. Group -staged files by that goal, not by directory. - -In `bypass` mode, stop grouping here: the result is exactly one message -covering all staged files, whether or not the diff is coherent. Do not propose -splits, and do not report split guidance. - -### 3. Choose a scope for each unit - -Use the smallest stable subsystem or module name recognizable in the repository. - -When no such name applies, use the primary directory or package of the unit's -changes. - -### 4. Write each message - -Follow `references/commit-message-style.md` for the subject pattern, the body -rules, issue references, the plan-citation rule, and the anti-patterns. - -### 5. Apply the plan-citation rule - -When the unit's staged files include `context/plans/*.md`, cite the affected -plan slug and updated task IDs in the body. - -When the staged plan diff does not expose the slug or task ID clearly enough to -cite faithfully: - -- In `regular` mode, return `blocked` and ask for the reference to be stated or - staged explicitly. -- In `bypass` mode, infer the citation when the diff supports it, and otherwise - omit it. Never stop, and never invent a slug or task ID. - -### 6. Apply context-file guidance gating - -This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do -not classify staged scope there. - -Classify the staged diff: - -- Context-only (`context/**`): context-file-focused guidance is allowed. -- Mixed (`context/**` plus non-`context/**`): suppress default context-file - commit reminders and give guidance that reflects the full staged scope. - -### 7. Propose split guidance - -This step applies in `regular` mode only. - -When the units found in step 2 pursue unrelated goals, return one message per -unit, and state why the split is recommended and which staged files belong to -each. - -When the staged changes form one unit, return one message and no split -guidance. Do not split coherent work to appear thorough. - -### 8. Validate the result - -Confirm before returning that: - -- Every message describes its unit faithfully and covers only that unit's files. -- Every staged file belongs to exactly one returned message. -- No plan slug or task ID appears that the staged diff does not support. -- The mode's own constraints hold. - -### 9. Return YAML - -Return exactly one YAML document matching `references/commit-contract.yaml`: - -- `proposal` in `regular` mode, with one or more messages. -- `bypass_message` in `bypass` mode, with exactly one message. -- `blocked` when messages cannot be written faithfully. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Run `git commit`, or any command that writes to the repository or its index. -- Stage, unstage, or modify files. -- Ask the user to stage or confirm staging. -- Analyze unstaged or untracked changes. -- Return more than one message in `bypass` mode. -- Return split guidance in `bypass` mode. -- Stop for plan-citation ambiguity in `bypass` mode. -- Invent plan slugs, task IDs, or issue references. -- Mention `context/` synchronization activity in a commit message. -- Claim a message was committed. -- Run plan, task, or validation workflows. - -## Completion - -The skill is complete after: - -- The staged diff was read, or reading it failed and was reported. -- Messages were written for every staged file, or a blocker prevented it. -- One valid terminal YAML result matching `references/commit-contract.yaml` was - returned. diff --git a/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml b/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml deleted file mode 100644 index 5ffdd9ff..00000000 --- a/.opencode/skills/sce-atomic-commit/references/commit-contract.yaml +++ /dev/null @@ -1,205 +0,0 @@ -version: 1 -name: sce-atomic-commit-result - -description: > - Output contract for sce-atomic-commit. The skill returns exactly one YAML - document representing proposal, bypass_message, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be proposal, bypass_message, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. - - Return proposal only in regular mode, and bypass_message only in bypass - mode. blocked is valid in both. - - Every staged file must appear under exactly one commit's files. - - Report file paths exactly as `git diff --cached --name-only` reports them. - - Carry the message body inside message, separated from the subject by one - blank line. Do not split it into a separate field. - - Do not include a commit hash. This skill never commits. - - Do not report guidance the mode forbids. - -variants: - - proposal: - meaning: > - The staged changes were analyzed in regular mode and one or more atomic - commit messages were written. Proposal-only: nothing was committed. - - required_fields: - - status - - mode - - commits - - optional_fields: - - split_rationale - - scope_classification - - notes - - field_rules: - - Include split_rationale only when commits holds more than one entry. - - scope_classification reports the context-file guidance gate as - context_only or mixed. - - shape: - status: proposal - mode: regular - - commits: - - id: string - message: string - files: - - string - cites_plan: boolean - - split_rationale: string - scope_classification: context_only | mixed - - notes: - - string - - example: - status: proposal - mode: regular - - commits: - - id: C01 - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full - re-login. Adds the refresh handler and reuses the existing token - issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - - id: C02 - - message: | - build: Pin the formatter to the toolchain version - - The formatter floated across environments and produced diff noise - unrelated to any change. - - files: - - flake.nix - - cites_plan: false - - split_rationale: > - The refresh endpoint and the formatter pin pursue unrelated goals and - share no files. Committing them together would hide the build change - behind a feature subject. - - scope_classification: mixed - - bypass_message: - meaning: > - The staged changes were analyzed in bypass mode and exactly one commit - message covering all staged files was written. The invoking workflow - executes the commit. - - required_fields: - - status - - mode - - message - - files - - optional_fields: - - cites_plan - - notes - - field_rules: - - files lists every staged file, because one message covers all of them. - - Never include commits, split_rationale, or scope_classification. - - shape: - status: bypass_message - mode: bypass - - message: string - - files: - - string - - cites_plan: boolean - - notes: - - string - - example: - status: bypass_message - mode: bypass - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full re-login. - Adds the refresh handler and reuses the existing token issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - blocked: - meaning: > - Faithful commit messages cannot be written from the staged changes. - - required_fields: - - status - - issues - - optional_fields: - - mode - - files - - field_rules: - - Include mode whenever the workflow supplied one. - - Include files when staged files were read before blocking. - - Plan-citation ambiguity blocks in regular mode only. In bypass mode the - citation is omitted instead. - - shape: - status: blocked - mode: regular | bypass - - files: - - string - - issues: - - id: string - category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context - problem: string - impact: string - decision_required: string - - example: - status: blocked - mode: regular - - files: - - context/plans/authentication.md - - issues: - - id: B01 - category: plan_citation_ambiguity - - problem: > - The staged plan diff changes two task checkboxes and does not - expose which task this commit completes. - - impact: > - The commit body would cite a task ID the staged diff does not - support. - - decision_required: > - State the completed task ID, or stage only that task's plan edit. diff --git a/.opencode/skills/sce-change-to-plan/SKILL.md b/.opencode/skills/sce-change-to-plan/SKILL.md new file mode 100644 index 00000000..92d48a4e --- /dev/null +++ b/.opencode/skills/sce-change-to-plan/SKILL.md @@ -0,0 +1,804 @@ +--- +name: sce-change-to-plan +description: > + Turn one change request into a scoped SCE plan in one self-contained workflow +compatibility: opencode +--- + +# SCE Change to Plan + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Context load phase** -> the **Plan authoring phase** to turn a change request into a scoped SCE plan" +argument-hint: "" + + +SCE CHANGE TO PLAN `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; the **Plan authoring phase** owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to the **Plan authoring phase** unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan authoring phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Run the **Context load phase** with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, run the **Context load phase** again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Run the **Plan authoring phase** with the change request and the complete `loaded` brief from the **Context load phase**. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +the **Plan authoring phase** exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by the **Plan authoring phase** in `references/output.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Run the **Plan authoring phase** with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. the **Plan authoring phase** owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of the **Plan authoring phase** against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to the **Plan authoring phase** as written. +- Do not duplicate the internal instructions of embedded phases. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when the **Plan authoring phase** returns a non-`plan_ready` status. + +## Embedded phase behavior + +## Internal phase: Context load phase + + +name: Context load phase +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one internal state: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. + + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Recording one structured context brief. + +Return a result matching: + +the internal context-load state described by this workflow + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, set internal status `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Set exactly one internal state: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching the internal context-load state described by this workflow was returned. + +## Internal phase: Plan authoring phase + + +name: Plan authoring phase +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + internal state: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. + + +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Recording one structured authoring result. + +Use the document format defined in: + +the **Plan template** section embedded in this file + +Return a result matching: + +the internal authoring state described by this workflow + +The invoking workflow renders that result as the summary defined in: + +`references/output.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from the **Context load phase**. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not set internal status `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Set internal status `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in the **Plan template** section embedded in this file. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, set internal status `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using the **Plan template** section embedded in this file. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Set exactly one internal state: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Set internal status `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Run task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Set internal status `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching the internal authoring state described by this workflow was returned. + +## Internal persisted-document format: Plan template + +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +the **Task execution phase** appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.pi/skills/sce-plan-authoring/references/plan-summary.md b/.opencode/skills/sce-change-to-plan/references/output.md similarity index 69% rename from .pi/skills/sce-plan-authoring/references/plan-summary.md rename to .opencode/skills/sce-change-to-plan/references/output.md index 0261808d..c2351217 100644 --- a/.pi/skills/sce-plan-authoring/references/plan-summary.md +++ b/.opencode/skills/sce-change-to-plan/references/output.md @@ -1,3 +1,62 @@ +# Change-to-plan output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Missing context bootstrap gate + +```markdown +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +## Clarification gate + +```markdown +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +## Blocked + +Present each issue's problem, impact, and required decision. For ambiguity, list +candidate plan paths and explain that naming one candidate resolves it. + +## Ready continuation + +```markdown +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} {task|tasks} planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +For revisions, replace `is ready` with `revised`. + # SCE Plan Summary The user-facing summary shown after a plan is written. The invoking workflow diff --git a/.opencode/skills/sce-commit/SKILL.md b/.opencode/skills/sce-commit/SKILL.md new file mode 100644 index 00000000..43670d17 --- /dev/null +++ b/.opencode/skills/sce-commit/SKILL.md @@ -0,0 +1,334 @@ +--- +name: sce-commit +description: > + Analyze staged changes and run the regular or explicit bypass commit workflow +compatibility: opencode +--- + +# SCE Commit + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Atomic commit phase** to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" + + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to the **Atomic commit phase** unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Run the **Atomic commit phase** with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; the **Atomic commit phase** owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, run the **Atomic commit phase** with `mode: regular` and the +commit context. + +the **Atomic commit phase** exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of the **Atomic commit phase**. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when the **Atomic commit phase** returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. + +## Embedded phase behavior + +## Internal phase: Atomic commit phase + + +name: Atomic commit phase +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one internal state + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. + + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Recording one terminal internal state. + +Write messages matching: + +`references/output.md` + +Return a result matching: + +the internal commit state described by this workflow + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Set internal status `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/output.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, set internal status `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return internal state + +Set exactly one internal state matching the internal commit state described by this workflow: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal internal state matching the internal commit state described by this workflow was + returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.opencode/skills/sce-atomic-commit/references/commit-message-style.md b/.opencode/skills/sce-commit/references/output.md similarity index 69% rename from .opencode/skills/sce-atomic-commit/references/commit-message-style.md rename to .opencode/skills/sce-commit/references/output.md index 7a1b5084..fb62021a 100644 --- a/.opencode/skills/sce-atomic-commit/references/commit-message-style.md +++ b/.opencode/skills/sce-commit/references/output.md @@ -1,6 +1,45 @@ +# Commit output layouts + +Use only the applicable layout. Values come from staged truth and internal +workflow state. + +## Regular-mode staging gate + +```markdown +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +## No staged changes + +```markdown +No staged changes. Stage changes before commit. +``` + +## Regular proposal + +For each proposal, present the complete commit message and covered files. When +more than one commit is proposed, also present the split rationale. Do not claim a +commit was created. + +## Blocked + +Present every issue's problem, impact, and required decision. Do not commit. + +## Bypass success + +```markdown +Committed {commit-hash} +``` + +## Bypass Git failure + +Present Git's failure unchanged and stop without retrying. + # Commit message style -The wording rules for every message `sce-atomic-commit` returns, in either +The wording rules for every message the **Atomic commit phase** returns, in either mode. This file is the only authority for message content and shape. Messages are carried in the result's `message` field, subject first, then one diff --git a/.opencode/skills/sce-context-load/SKILL.md b/.opencode/skills/sce-context-load/SKILL.md deleted file mode 100644 index 5e28b0ee..00000000 --- a/.opencode/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. -compatibility: opencode ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -`references/context-brief.yaml` - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching `references/context-brief.yaml` was returned. diff --git a/.opencode/skills/sce-context-load/references/context-brief.yaml b/.opencode/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/.opencode/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/.opencode/skills/sce-next-task/SKILL.md b/.opencode/skills/sce-next-task/SKILL.md new file mode 100644 index 00000000..68df5036 --- /dev/null +++ b/.opencode/skills/sce-next-task/SKILL.md @@ -0,0 +1,939 @@ +--- +name: sce-next-task +description: > + Review, approve, implement, verify, and synchronize one SCE plan task +compatibility: opencode +--- + +# SCE Next Task + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Plan review phase** -> the **Task execution phase** -> the **Task context synchronization phase** for one SCE plan task" +argument-hint: " [T0X] [approved]" + + +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan review phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Run the **Plan review phase** with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to the **Plan review phase**. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not run implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to the **Task execution phase**. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Run the **Task execution phase** with the complete `ready` result from the **Plan review phase**. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. the **Task execution phase** then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. the **Task execution phase** shows its implementation gate and waits for the user's decision. + +the **Task execution phase** exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not run context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not run context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not run context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Run the **Task context synchronization phase** with the complete `complete` result returned by the **Task execution phase**. + +Pass that result verbatim. It is the authoritative handoff, and the **Task context synchronization phase** owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report the **Task context synchronization phase** returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of embedded phases. +- Do not ask for implementation confirmation outside "Task execution phase". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve completed work and evidence when a later phase fails. + +## Embedded phase behavior + +## Internal phase: Plan review phase + + +name: Plan review phase +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. + + +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Recording one structured readiness result. + +Return a result matching: + +the internal readiness state described by this workflow + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Set internal status `plan_complete` when no incomplete tasks remain. + +Set internal status `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Set internal status `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Set exactly one internal state: + +- `ready` +- `blocked` +- `plan_complete` + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Run task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching the internal readiness state described by this workflow was + returned. + +## Internal phase: Task execution phase + + +name: Task execution phase +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one internal state: declined, + blocked, incomplete, or complete. Accepts a ready result from + Plan review phase. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. + + +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Recording one terminal internal state. + +Use the gate defined in: + +`references/output.md` + +Return a final result matching: + +the internal execution state described by this workflow + +## Input + +The invoking workflow provides: + +- The complete `ready` result from the **Plan review phase**. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, set internal status `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/output.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return internal state, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and set internal status `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise set internal status `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, set internal status `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Set internal status `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Set internal status `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Set internal status `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Set internal status `declined` when the user rejected implementation. + +Set internal status `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by the internal execution state described by this workflow. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return internal state + +After the skill reaches a terminal state, set exactly one internal state +matching the internal execution state described by this workflow. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal internal state matching the internal execution state described by this workflow + was returned. + +## Internal phase: Task context synchronization phase + + +name: Task context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from Task execution phase, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Run only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. + + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by the **Task execution phase**. + +The execution result must have: + +```text +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be run for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.opencode/skills/sce-task-context-sync/references/sync-report.md b/.opencode/skills/sce-next-task/references/output.md similarity index 50% rename from .opencode/skills/sce-task-context-sync/references/sync-report.md rename to .opencode/skills/sce-next-task/references/output.md index 581177da..791f8f21 100644 --- a/.opencode/skills/sce-task-context-sync/references/sync-report.md +++ b/.opencode/skills/sce-next-task/references/output.md @@ -1,3 +1,144 @@ +# Next-task output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Review blocked + +Present the selected task, then each issue's problem, impact, and required +decision. If plan resolution is ambiguous, list candidate paths and +`/next-task {candidate-path}`. State whether another task remains executable. + +## Plan already complete + +```markdown +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +## Declined + +```markdown +You have declined to proceed with this task +``` + +## Execution blocked or incomplete + +For `blocked`, present the blocker, work completed before it, and the required +decision or action. For `incomplete`, present completed work, verification +evidence, remaining work, and the reason it remains incomplete. + +## Context synchronization blocked + +State that task `{completed-task-id}` was implemented, verified, and recorded; +report the contradiction or synchronization failure, preserved edits, required +action, and retry condition. State that durable context is out of date and must +be synchronized before continuing. + +## More tasks remain + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +## All tasks complete + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +# Implementation gate + +Always show this gate at the start of the **Task execution phase**, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. + # Context Sync Report Return only one completed Markdown report using the applicable variant below. diff --git a/.opencode/skills/sce-plan-authoring/SKILL.md b/.opencode/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index fdc754a9..00000000 --- a/.opencode/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -name: sce-plan-authoring -description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. -compatibility: opencode ---- - -# SCE Plan Authoring - -## Purpose - -Turn exactly one change request into `context/plans/{plan_name}.md` without -inventing material requirements. - -This skill owns: - -- Resolving whether the request targets a new or an existing plan. -- Judging whether the change is worth making, and recording the doubt when it - is not clear that it is. -- Deciding whether the request can be planned safely. -- Normalizing the change summary, acceptance criteria, constraints, and - non-goals. -- Slicing the work into atomic implementation tasks. -- Writing the plan file. -- Returning one structured authoring result. - -Use the document format defined in: - -`references/plan-template.md` - -Return a result matching: - -`references/authoring-contract.yaml` - -The invoking workflow renders that result as the summary defined in: - -`references/plan-summary.md` - -## Input - -The invoking workflow provides: - -- One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. - -The change request may name a plan, describe a change to an existing plan, or -describe entirely new work. Resolving which applies is this skill's -responsibility. - -The context brief is the durable memory this plan starts from. Treat its -`key_facts` as recorded current state, its `gaps` as areas with no durable -context, and its `drift` as context the code has already outrun. - -When no brief is supplied, load the context named by the change request before -authoring, and follow the selection discipline in *Inspect relevant context*. - -Answers the user gave to earlier clarification questions arrive as part of the -change request. Incorporate them into the plan. - -A revision of a plan authored earlier in the session also arrives as the change -request, and it is usually terse: a task boundary the user disagrees with, an -ordering they want changed, work they want added or dropped. Read it against the -existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the -plan already carries; ask only when the revision itself is genuinely undecidable. - -## Workflow - -### 1. Resolve the plan target - -Determine whether the request targets a new plan or an existing plan in -`context/plans/`. - -When it targets an existing plan, read that plan before authoring. Preserve its -completed tasks, their recorded evidence, its structure, and its terminology. - -When multiple existing plans match and none can be selected safely, return -`blocked` with the matching candidates. - -When the request targets a new plan, derive `plan_name` as a short kebab-case -slug of the change, and confirm it does not collide with an existing plan. - -Resolve exactly one plan target per invocation. - -### 2. Challenge the change - -Before planning how to build the change, work out whether it is worth building. -A plan is a commitment of someone's time; authoring one for work that should not -happen is worse than authoring none. - -Interrogate the request: - -- What breaks, or stays broken, if this is never built? If the answer is - nothing concrete, say so. -- What problem is it actually solving, as opposed to what it proposes to do? A - request that names only a solution has not stated a problem. -- Does the repository already do this, or most of it? The brief's `key_facts` - are the first place to check. -- Is there a materially smaller version that gets most of the value? Name it. -- What does this cost beyond the tasks: new dependency, new concept in the - glossary, a boundary crossed, a surface that now needs maintaining forever? -- Does the stated justification survive contact with the code, or does the code - show the premise is already false? - -Doubt that survives this is not an implementation detail to be tidied away. It -belongs in the plan's `Open questions` and in `open_questions`, in the plain -words you would use to a colleague. "Is this worth doing at all, given X?" is a -legitimate open question. So is "this looks like it duplicates Y". - -Weigh honestly in both directions. A request that is obviously worth building -gets no manufactured doubt: inventing questions to look rigorous is its own -failure, and it teaches the user to ignore the section. Most changes are fine. -Say nothing when there is nothing to say. - -Keep going regardless. Skepticism shapes the plan and the open questions; it -does not withhold the plan. The only value judgment that stops authoring is -`no_actionable_work`, when the change is already implemented. - -### 3. Run the clarification gate - -Before writing or updating any plan file, check the request for critical -unresolved detail: - -- Scope boundaries and out-of-scope items. -- Acceptance criteria and the checks that prove them. -- Constraints and non-goals. -- Dependency choices, including new libraries or services, versions, and the - integration approach. -- Domain ambiguity, including unclear business rules, terminology, or ownership. -- Architecture concerns, including patterns, interfaces, data flow, migration - strategy, and risk tradeoffs. -- Task ordering assumptions and prerequisite sequencing. - -Return `needs_clarification` with one to three targeted questions when any of -these would materially change the plan. Write no plan file in that case. - -Use repository conventions for ordinary local choices. Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change scope, acceptance criteria, or task ordering. - -Record those choices under `assumptions`. - -Do not silently invent missing requirements. When the user has explicitly -allowed assumptions, record them in the plan's `Assumptions` section instead of -asking. - -A justification that does not survive inspection is itself a critical unresolved -detail. "For consistency", "to make it cleaner", "we will need it later" name no -outcome and prove nothing; ask what the change is actually for before planning -around it. Do not treat confident phrasing as evidence. - -### 4. Inspect relevant context - -Start from the context brief. Read code only where the brief leaves the change -underspecified: - -- Existing behavior the change affects. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests and available verification commands. -- Decisions or specifications connected to the change. - -Where the brief reports `drift`, the code is the source of truth. Plan against -the code, and schedule the context repair as part of the change when it falls -inside scope. - -Where the brief reports `gaps`, the plan may need to establish durable context -the repository does not yet have. - -Do not explore the entire repository by default. - -### 5. Author the acceptance criteria - -State how the finished plan is proven, before slicing tasks. - -Each criterion describes observable behavior of the finished system and names -the check that proves it. Record repository-wide checks once under -`Full validation`, and the durable context the change must be reflected in -under `Context sync`. - -`/validate` runs this section after the last task completes. It is the only -place a plan says how it is validated. - -### 6. Author the task stack - -Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. - -Every executable task must be completable and landable as one coherent commit. -Split any task that would require multiple independent commits. Convert broad -wrappers such as `polish` or `finalize` into specific outcomes with concrete -acceptance checks. - -Order tasks so each one's declared dependencies precede it. - -The last task is an ordinary implementation task. Do not author a trailing -validation-and-cleanup task, or any task whose only purpose is running the full -check suite, verifying durable context, or removing scaffolding. - -Confirm every acceptance criterion is satisfied by at least one task. When one -is not, the task stack is incomplete. - -A finished stack always leaves at least one incomplete task, so the invoking -workflow can always hand off to `/next-task`. When the request resolves to a -plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category -`no_actionable_work` instead of writing the plan. - -### 7. Write the plan - -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. - -When updating an existing plan, keep completed tasks and their evidence intact, -and append or renumber new tasks without disturbing recorded history. - -### 8. Return the result - -Return exactly one structured result: - -- `plan_ready` -- `needs_clarification` -- `blocked` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Tone - -Every question and open question this skill writes is read by the user. Write -them the way a senior engineer talks in review: direct, specific, and unbothered -by the possibility of being unwelcome. - -- Ask about the thing that actually worries you, not a safer neighbouring thing. - A question you would not bother asking a colleague is not worth the user's - attention either. -- State a doubt as a doubt. "I do not think this is worth the two tasks it - costs, because X" is useful. "It may be worth considering whether this aligns - with broader goals" is noise. -- Name the alternative you have in mind. A challenge with no proposal behind it - is just friction. -- Do not open with praise, do not close with reassurance, and do not apologize - for asking. Do not pad a doubt with hedges to make it land more gently. -- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not - restate the same doubt in three shapes to give it more weight. -- Being disagreeable is not the goal. Being easy to agree with is the failure - mode. A plan the user waves through without reading has cost them nothing and - bought them nothing. - -When the user overrules a doubt, record it and move on. Do not relitigate a -decision the user has made, and do not smuggle the objection back in as a -constraint, a non-goal, or a task. - -## Boundaries - -Do not: - -- Ask the user questions directly. Return `needs_clarification` and let the - invoking workflow present the questions. -- Answer your own clarification questions. -- Write a plan file when returning `needs_clarification` or `blocked`. -- Implement any task in the plan. -- Modify application code or tests. -- Modify any file under `context/` outside `context/plans/`. Plan the context - repair instead of performing it. -- Mark any task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Author a validation, cleanup, or context-verification task. `/validate` owns - that phase. -- Return `plan_ready` for a plan with no incomplete task. -- Create a Git commit. -- Author more than one plan. - -## Completion - -The skill is complete after: - -- One plan target was resolved, or resolution failed and was reported. -- The plan file was written, or no file was written because the result is - `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml b/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/.opencode/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/.opencode/skills/sce-plan-authoring/references/plan-template.md b/.opencode/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/.opencode/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/.opencode/skills/sce-plan-context-sync/SKILL.md b/.opencode/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index a59c57f8..00000000 --- a/.opencode/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. -compatibility: opencode ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.opencode/skills/sce-plan-context-sync/references/sync-report.md b/.opencode/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/.opencode/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/.opencode/skills/sce-plan-review/SKILL.md b/.opencode/skills/sce-plan-review/SKILL.md deleted file mode 100644 index cb98f485..00000000 --- a/.opencode/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. -compatibility: opencode ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -`references/readiness-contract.yaml` - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was - returned. diff --git a/.opencode/skills/sce-plan-review/references/readiness-contract.yaml b/.opencode/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/.opencode/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/.opencode/skills/sce-task-context-sync/SKILL.md b/.opencode/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index 3b3b5d80..00000000 --- a/.opencode/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. -compatibility: opencode ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.opencode/skills/sce-task-execution/SKILL.md b/.opencode/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 267f608c..00000000 --- a/.opencode/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,247 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. -compatibility: opencode ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal YAML result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -`references/execution-contract.yaml` - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. -- Relevant files and context. -- Review assumptions. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task has not materially changed since review. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return YAML, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by `references/execution-contract.yaml`. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return YAML - -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` - was returned. diff --git a/.opencode/skills/sce-task-execution/references/execution-contract.yaml b/.opencode/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/.opencode/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.opencode/skills/sce-task-execution/references/implementation-gate.md b/.opencode/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index d4ad836c..00000000 --- a/.opencode/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,69 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a YAML result. This -file is the only authority for the gate's content and order. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/.opencode/skills/sce-validate/SKILL.md b/.opencode/skills/sce-validate/SKILL.md new file mode 100644 index 00000000..0d96b1df --- /dev/null +++ b/.opencode/skills/sce-validate/SKILL.md @@ -0,0 +1,767 @@ +--- +name: sce-validate +description: > + Validate one completed SCE plan and synchronize its durable context +compatibility: opencode +--- + +# SCE Validate + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Validation phase** -> the **Plan context synchronization phase** to finish an SCE plan" +argument-hint: "" + + +SCE VALIDATE `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to the **Validation phase** unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by the **Validation phase** in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Run the **Validation phase** with the plan name or path. + +the **Validation phase** exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not run context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not run context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +the **Plan context synchronization phase**. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Run the **Plan context synchronization phase** only with a `Status: validated` Markdown result +from the **Validation phase**. + +Do not run the **Plan context synchronization phase** for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +the **Plan context synchronization phase** owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +the **Plan context synchronization phase** returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of embedded phases. +- Do not run final validation when implementation tasks remain; the **Validation phase** + returns `blocked`, and this workflow stops. +- Run the **Plan context synchronization phase** only when the **Validation phase** returned + `Status: validated`. Do not run it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. + +## Embedded phase behavior + +## Internal phase: Validation phase + + +name: Validation phase +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one internal state (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. + + +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Recording one Markdown validation result. + +Return a result matching: + +`references/output.md` + +Write plan-file evidence matching: + +the **Plan-file validation report** section embedded in this file + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs the **Plan context synchronization phase** only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Set internal status `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Set internal status `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + the **Plan-file validation report** section embedded in this file. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so the **Plan context synchronization phase** can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the internal state + +Set exactly one internal state: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/output.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. Do not return internal state. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a internal state. +- Run plan context synchronization. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid internal state matching `references/output.md` was + returned. + +## Internal phase: Plan context synchronization phase + + +name: Plan context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful Status: validated + internal state from Validation phase, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Run only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. + + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete internal state returned by the **Validation phase**. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be run for `failed` or `blocked` validation results. +Those are not success states. Same rule as the **Task context synchronization phase**: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated internal state: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + +## Internal persisted-document format: Plan-file validation report + +# Plan-file Validation Report + +The Markdown section the **Validation phase** appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +the **Validation phase** writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.opencode/skills/sce-validate/references/output.md b/.opencode/skills/sce-validate/references/output.md new file mode 100644 index 00000000..3e4c5519 --- /dev/null +++ b/.opencode/skills/sce-validate/references/output.md @@ -0,0 +1,429 @@ +# Validate output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Validation blocked + +```markdown +# Validation blocked + +**Status:** blocked +**Plan:** `{plan-path when resolved}` +**Name:** `{plan-name when resolved}` + +## Issues + +- **{issue-id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision-or-action} + +## Incomplete tasks + +- `{task-id}` — {title} + +## Candidates + +- `{candidate-plan-path}` + +## Next step + +{one continuation matching the blocker} +``` + +Omit inapplicable optional sections. + +## Validation failed handoff + +```markdown +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan-path}` +**Name:** `{plan-name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan-path}` + +## Goal for the next session + +{repair goal} + +## What failed + +- `{check-or-AC}`: {problem} + - Evidence: {evidence} + - Required action: {action} + +## Acceptance criteria + +- [{x-or-space}] {criterion}: {evidence} + +## Commands run + +- `{command}` -> {passed|failed|not_run} — {summary} + +## Constraints + +{canonical validation constraints} + +## Residual risks + +- {risk-or-none} + +## Recommended work + +1. {repair} +2. Rerun final validation after repairs: + +`/validate {plan-path}` +``` + +## Context synchronization blocked + +State that validation passed and its report is recorded, then report the context +failure, preserved edits, required action, and retry condition. State that durable +context remains out of date and synchronization must finish before closure. + +## Completion + +```markdown +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not run for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs the **Plan context synchronization phase** only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. + +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not run for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.opencode/skills/sce-validation/SKILL.md b/.opencode/skills/sce-validation/SKILL.md deleted file mode 100644 index a2dc559d..00000000 --- a/.opencode/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. -compatibility: opencode ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -`references/validation-result.md` - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was - returned. diff --git a/.opencode/skills/sce-validation/references/validation-report.md b/.opencode/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/.opencode/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/.opencode/skills/sce-validation/references/validation-result.md b/.opencode/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/.opencode/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. diff --git a/.pi/prompts/change-to-plan.md b/.pi/prompts/change-to-plan.md index 9ee4f81f..e9c3ed76 100644 --- a/.pi/prompts/change-to-plan.md +++ b/.pi/prompts/change-to-plan.md @@ -1,175 +1,8 @@ --- -description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" +description: "Turn one change request into a scoped SCE plan in one self-contained workflow" argument-hint: "" --- -SCE CHANGE TO PLAN `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the change request, in free-form prose. - -- The change request is required. -- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. - -When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - -Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Load durable context - -Invoke `sce-context-load` with the change request as the focus. - -`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. - -The skill must return a result matching its context brief contract. - -Branch on `status`: - -`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: - -``` - -------------------------------------- - -# This repository has no durable context. - -Bootstrap it, then continue in this session: - -`sce setup --bootstrap-context` -``` - -Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. - -`loaded` -> Continue to the next step. - -Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. - -### 2. Author the plan - -Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. - -Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - -`sce-plan-authoring` exclusively owns: - -- Resolving whether the request targets a new or an existing plan. -- The clarification gate. -- Normalizing the change summary, acceptance criteria, constraints, and non-goals. -- Slicing the task stack into one-task/one-atomic-commit units. -- Writing `context/plans/{plan_name}.md`. - -Do not duplicate any of it. Do not write or edit the plan file yourself. - -The skill must return a result matching its authoring contract. - -Branch on `status`: - -`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: - -``` - -------------------------------------- - -# Clarification needed. - -No plan was written. - -Answer each question below. - -## {question-id} · {category} - -{question} - -Why this blocks planning: {why_blocking} -``` - -Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. - -Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. - -`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: - -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. - -Stop. - -`plan_ready` -> Continue to the next step. - -### 3. Determine the continuation - -Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. - -Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. - -Write `task` rather than `tasks` when `total_tasks` is 1. - -Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. - -Return: - -``` - -------------------------------------- - -# Plan {plan-name} is ready. - -{total-tasks} tasks planned. - -This plan is a draft. State a correction and it will be updated. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -Then stop and wait. Do not implement, and do not run the handoff yourself. - -### 4. Revise the plan on request - -When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - -Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. - -An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - -Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. - -Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. - -On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - -Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. - -When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. - -Stop. - -## Rules - -- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. -- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. -- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. -- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. -- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. -- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. -- Do not duplicate the internal instructions of invoked skills. -- Do not plan before durable context is loaded. -- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. -- Do not modify any file under `context/` outside `context/plans/`. -- Do not implement any part of the plan. -- Do not ask for implementation confirmation. -- Do not run task execution, context synchronization, or full-plan validation. -- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. -- Do not answer the skill's clarification questions on the user's behalf. -- Do not execute the continuation returned at the end. -- Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. +Invoke the `sce-change-to-plan` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.pi/prompts/commit.md b/.pi/prompts/commit.md index 85ece4bd..477d4f68 100644 --- a/.pi/prompts/commit.md +++ b/.pi/prompts/commit.md @@ -1,130 +1,8 @@ --- -description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" +description: "Analyze staged changes and run the regular or explicit bypass commit workflow" argument-hint: "[oneshot|skip] [commit context]" --- -SCE COMMIT `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: - -`[mode-token] [commit context]` - -- `mode-token` is present only when the first whitespace-separated token is - exactly `oneshot` or `skip`, compared case-insensitively. Any other first - token is not a mode token. -- `commit context` is everything else: free-form prose that refines message - wording only. - -A `mode-token` selects the bypass path. Its absence selects the regular path. -Do not infer the bypass path from anything else — not from the commit context, -not from repository state, and not from the conversation. - -Empty `$ARGUMENTS` is valid. It selects the regular path with no commit -context, and commit intent is inferred from the staged changes alone. - -Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, -summarize, or pre-scope it. Never pass the `mode-token` as commit context. - -Staged changes are the source of truth for what is being committed. This -command never stages, unstages, or modifies files. - -## Workflow - -Follow exactly one path. - -### Bypass path (`oneshot` or `skip`) - -#### 1. Validate that staged content exists - -Run `git diff --cached --quiet`. A zero exit status means nothing is staged. - -When nothing is staged, stop with exactly: - -`No staged changes. Stage changes before commit.` - -Do not stage anything. Do not proceed to the skill. - -#### 2. Request one commit message - -Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. - -Bypass mode is the skill's contract for producing exactly one message. Do not -restate its overrides here; `sce-atomic-commit` owns them. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and stop. Do not commit. - -`bypass_message` -> Continue to the next step. - -The skill never returns `proposal` in bypass mode. Treat a `proposal` result as -a contract violation: report it and stop without committing. - -#### 3. Execute exactly one commit - -Run `git commit` once with the returned message. - -On success, report the resulting commit hash and stop. - -On failure, report the failure as returned by Git and stop. Do not retry, do -not amend, do not stage additional files, and do not invent a fallback commit. - -### Regular path (no mode token) - -#### 1. Confirm staging - -Before invoking the skill, stop and prompt the user: - -``` -Please run `git add ` for all changes you want included in this commit. -Atomic commits should only include intentionally staged changes. -Confirm once staging is complete. -``` - -Wait for the user's confirmation. Do not stage files on their behalf, and do -not skip this prompt because the working tree looks ready. - -#### 2. Propose commits - -After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the -commit context. - -`sce-atomic-commit` exclusively owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Classifying staged scope and applying context-file guidance gating. -- Writing every commit message subject and body. -- Applying the plan-citation body rule. - -Do not duplicate any of it. Do not write commit messages yourself. - -The skill must return a result matching its commit contract. Branch on -`status`: - -`blocked` -> Present the issue and the decision it requires. Stop. - -`proposal` -> Present each proposed commit: its message, the files it covers, -and, when more than one commit is proposed, why the split is recommended. - -Then stop. The regular path is proposal-only. - -Do not run `git commit`. Do not offer to commit on the user's behalf. The user -runs the commits they accept. - -## Rules - -- Produce at most one commit per invocation, and only on the bypass path. -- Never commit on the regular path. -- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. - They are behaviorally identical. -- Do not duplicate the internal instructions of `sce-atomic-commit`. -- Do not stage, unstage, restore, or otherwise modify files. -- Do not amend, reset, revert, rebase, or push. -- Do not read unstaged or untracked changes as commit input. -- Do not infer success when `sce-atomic-commit` returns a non-success status. -- Do not proceed past a failed `git commit`. -- Do not run plan, task, or validation workflows from this command. +Invoke the `sce-commit` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.pi/prompts/next-task.md b/.pi/prompts/next-task.md index 6859e4d4..b020970d 100644 --- a/.pi/prompts/next-task.md +++ b/.pi/prompts/next-task.md @@ -1,191 +1,8 @@ --- -description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" +description: "Review, approve, implement, verify, and synchronize one SCE plan task" argument-hint: " [T0X] [approved]" --- -SCE NEXT TASK `$ARGUMENTS` - -## Input - -Parse `$ARGUMENTS` into three positional parts before invoking any skill: - - [task-id] [auto-approve] - -- `plan-name-or-path` is required. -- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). -- `auto-approve` is optional. It is present only when the token is exactly `approved`. - -Resolve `auto-approve` even when `task-id` is absent. - -A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. - -Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. - -## Workflow - -### 1. Review the task - -Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - -Do not pass the `auto-approve` token to `sce-plan-review`. - -The skill must return a result matching its readiness contract. - -Branch on `status`: - -`blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. - -When `candidates` is present, the plan could not be resolved. Present: - -- The problem reported by the review. -- The candidate plan paths. -- `/next-task {candidate-path}` for the intended plan. - -Otherwise one plan and task were resolved. Present: - -- The task ID and title. -- Each issue in `issues`: its problem, its impact, and the decision it requires. -- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. -- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. - -`plan_complete` -> Return: - -``` - -------------------------------------- - -# Implementation tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -`ready` -> Pass the complete readiness result to `sce-task-execution`. - -Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. - -### 2. Execute the task - -Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. - -Branch on `auto-approve`: - -`approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. - -else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. - -`sce-task-execution` exclusively owns: - -- Presenting the implementation summary. -- Requesting implementation confirmation. -- Implementing the task. -- Running task-level verification. -- Updating the task status and evidence. - -Do not present an additional implementation confirmation. - -Branch on the execution result. - -`declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. - -`blocked` -> Present: - -- The blocker. -- Work completed before the blocker. -- The decision or action required. - -Do not invoke context synchronization. Stop. - -`incomplete` -> Present: - -- Work completed. -- Verification evidence. -- Remaining work. -- The reason the task is incomplete. - -Do not invoke context synchronization. Do not select another task. Stop. - -`complete` -> continue to the next step. - -### 3. Synchronize context - -Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. - -Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the execution result. - -Branch on the synchronization result. - -`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: - -- That task {completed-task-id} was implemented, verified, and recorded in the plan. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. - -Do not select another task. Stop. - -`synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. - -### 4. Determine the continuation - -Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. - -Do not execute another task. Return exactly one continuation. - -If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. - -Return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -{completed-tasks} of {total-tasks} tasks complete. - -Next up: - -{next-task-id} — {next-task-title} - -`/next-task {plan-path} {next-task-id}` -``` - -If all tasks are completed return: - -``` - -------------------------------------- - -# Task {completed-task-id} completed. - -All tasks are complete. - -Run the final validation: - -`/validate {plan-path}` -``` - -Stop. - -## Rules - -- Execute at most one plan task per invocation. -- Review at most one task. -- Do not duplicate the internal instructions of invoked skills. -- Do not ask for implementation confirmation outside "sce-task-execution". -- Do not run full-plan validation. -- Do not mark the plan complete. -- Do not execute the continuation returned at the end. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve completed work and evidence when a later phase fails. +Invoke the `sce-next-task` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.pi/prompts/validate.md b/.pi/prompts/validate.md index d35fb89c..543484be 100644 --- a/.pi/prompts/validate.md +++ b/.pi/prompts/validate.md @@ -1,144 +1,8 @@ --- -description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" +description: "Validate one completed SCE plan and synchronize its durable context" argument-hint: "" --- -SCE VALIDATE `$ARGUMENTS` - -## Input - -`$ARGUMENTS` is the plan name or plan path. - -- The plan name or path is required. -- Resolve exactly one plan. Do not invent a plan from the conversation or from - incomplete nearby work. - -When `$ARGUMENTS` is empty, report that a plan name or path is required, state -the expected argument, and stop. Do not infer the plan from repository state or -the conversation. - -Pass the plan name or path to `sce-validation` unmodified. Do not restate, -summarize, or pre-scope it. - -Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is -the path carried by `sce-validation` in its Markdown result (`Plan:`, or a -candidate path), so every emitted command is directly runnable. - -## Workflow - -### 1. Validate the plan - -Invoke `sce-validation` with the plan name or path. - -`sce-validation` exclusively owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running full validation and acceptance-criteria checks. -- Removing temporary scaffolding. -- Writing the Validation Report into the plan. -- Returning one Markdown validation result. - -Do not duplicate any of it. Do not write the Validation Report yourself. - -The skill must return a Markdown result matching its validation-result contract. -Branch on the report's `Status:`. - -`blocked` -> Do not invoke context synchronization. Print the blocked Markdown -report as returned. Do not rephrase it into a different layout. Stop. - -`failed` -> Do not invoke context synchronization. Print the failed Markdown -report as returned. It is already a session handoff: self-contained, actionable, -and ending with `/validate {plan-path}` after repairs. - -Do not rewrite it into a shorter summary. Do not drop the retry command. Do not -add an alternate continuation that replaces `/validate`. - -Stop. Do not mark the plan finished. Do not continue to context synchronization. -Do not start the repair work in this workflow unless the user explicitly asks -to continue here; the default is that the handoff can leave this session. - -`validated` -> Pass the complete validated Markdown result to -`sce-plan-context-sync`. - -Do not reconstruct, summarize, or reinterpret the validation result before -passing it. - -### 2. Synchronize plan context - -Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result -from `sce-validation`. - -Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not -success states. - -Pass the validated result verbatim. It is the authoritative handoff, and -`sce-plan-context-sync` owns reading the plan path, required context paths, -validation evidence, and reported context impact out of it. - -Do not restate, summarize, or reconstruct any part of the validation result. - -Branch on the synchronization result. - -`blocked` -> Validation itself succeeded and is already recorded in the plan. -Present: - -- That plan `{plan-path}` passed final validation and its Validation Report is - written. -- The context contradiction or synchronization failure. -- Any context edits the report says were preserved. -- The action required to resolve the problem. -- The retry condition stated by the report. - -State that durable context is now out of date relative to the validated -implementation, and that plan context synchronization must be resolved before -treating the plan as fully closed. Nothing records the skipped synchronization, -so it is lost once this session ends. - -Stop. - -`synced` | `no_context_change` -> Print out the report -`sce-plan-context-sync` returned. Continue to the next step. - -### 3. Report completion - -Return exactly one completion block. Do not start another workflow. - -``` - -------------------------------------- - -# Plan {plan-name} validated. - -All implementation tasks were already complete. -Final validation passed. -Durable context is synchronized. - -Validation report: {plan-path} -``` - -When the synchronization status was `no_context_change`, keep the same -completion block. "Synchronized" here means the final context pass finished -successfully, including the case where no edit was warranted. - -Stop. - -## Rules - -- Validate at most one plan per invocation. -- Do not duplicate the internal instructions of invoked skills. -- Do not run final validation when implementation tasks remain; `sce-validation` - returns `blocked`, and this workflow stops. -- Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. -- On `failed`, print the handoff Markdown as returned and stop. Preserve the - retry `/validate {plan-path}` instruction. Do not synchronize context. -- Do not implement remaining plan tasks from this workflow unless the user - explicitly continues in-session after a failed handoff. -- Do not create a Git commit or push changes. -- Do not mark the plan archived or delete the plan. -- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` - yourself. -- Do not infer success when an invoked skill returns a non-success status. -- Preserve validation evidence already written to the plan when context - synchronization fails. +Invoke the `sce-validate` skill exactly once with `$ARGUMENTS`. +The skill owns the complete workflow, including all waits and same-session resume +behavior. Do not invoke any phase skill or sequence workflow steps in this command. diff --git a/.pi/skills/sce-atomic-commit/SKILL.md b/.pi/skills/sce-atomic-commit/SKILL.md deleted file mode 100644 index 1ddda9e5..00000000 --- a/.pi/skills/sce-atomic-commit/SKILL.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -name: sce-atomic-commit -description: > - Internal SCE workflow skill that analyzes the staged diff and returns atomic, - repository-style commit messages: coherent-unit detection, split guidance, - scope and subject wording, and the plan-citation body rule. Returns one YAML - result (proposal, bypass_message, or blocked). Use from /commit. Do not stage - files, create commits, or ask the user to confirm staging. ---- - -# SCE Atomic Commit - -## Purpose - -Turn the current staged changes into atomic repository-style commit messages. - -This skill owns: - -- Reading and analyzing the staged diff. -- Deciding whether staged changes form one coherent unit or several. -- Choosing the scope and writing the subject and body of every message. -- Applying the plan-citation body rule. -- Classifying staged scope and applying context-file guidance gating. -- Returning one terminal YAML result. - -Write messages matching: - -`references/commit-message-style.md` - -Return a result matching: - -`references/commit-contract.yaml` - -Committing is not this skill's job. The invoking `/commit` workflow decides -whether a returned message is committed, and it is the only thing that runs -`git commit`. - -## Input - -The invoking workflow provides: - -- A mode: `regular` or `bypass`. -- Optional commit context, in free-form prose. - -The mode is supplied by the workflow from an explicit user-supplied token. -Never infer it, and never switch modes mid-analysis. - -Commit context refines wording only. The staged diff decides what the change -is; context never overrides staged truth, and never adds a claim the diff does -not support. - -Do not accept an unstaged diff, a working-tree summary, or a conversational -description as a substitute for the staged diff. - -## Workflow - -### 1. Read the staged diff - -Read the staged changes with `git diff --cached`, and the staged file list with -`git diff --cached --name-status`. - -Read staged file contents only when the diff alone does not explain the change. - -Return `blocked` when nothing is staged. - -### 2. Identify coherent units - -Infer the main reason for the staged change from the diff first. - -A coherent unit is one goal a reviewer would accept as a single commit. Group -staged files by that goal, not by directory. - -In `bypass` mode, stop grouping here: the result is exactly one message -covering all staged files, whether or not the diff is coherent. Do not propose -splits, and do not report split guidance. - -### 3. Choose a scope for each unit - -Use the smallest stable subsystem or module name recognizable in the repository. - -When no such name applies, use the primary directory or package of the unit's -changes. - -### 4. Write each message - -Follow `references/commit-message-style.md` for the subject pattern, the body -rules, issue references, the plan-citation rule, and the anti-patterns. - -### 5. Apply the plan-citation rule - -When the unit's staged files include `context/plans/*.md`, cite the affected -plan slug and updated task IDs in the body. - -When the staged plan diff does not expose the slug or task ID clearly enough to -cite faithfully: - -- In `regular` mode, return `blocked` and ask for the reference to be stated or - staged explicitly. -- In `bypass` mode, infer the citation when the diff supports it, and otherwise - omit it. Never stop, and never invent a slug or task ID. - -### 6. Apply context-file guidance gating - -This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do -not classify staged scope there. - -Classify the staged diff: - -- Context-only (`context/**`): context-file-focused guidance is allowed. -- Mixed (`context/**` plus non-`context/**`): suppress default context-file - commit reminders and give guidance that reflects the full staged scope. - -### 7. Propose split guidance - -This step applies in `regular` mode only. - -When the units found in step 2 pursue unrelated goals, return one message per -unit, and state why the split is recommended and which staged files belong to -each. - -When the staged changes form one unit, return one message and no split -guidance. Do not split coherent work to appear thorough. - -### 8. Validate the result - -Confirm before returning that: - -- Every message describes its unit faithfully and covers only that unit's files. -- Every staged file belongs to exactly one returned message. -- No plan slug or task ID appears that the staged diff does not support. -- The mode's own constraints hold. - -### 9. Return YAML - -Return exactly one YAML document matching `references/commit-contract.yaml`: - -- `proposal` in `regular` mode, with one or more messages. -- `bypass_message` in `bypass` mode, with exactly one message. -- `blocked` when messages cannot be written faithfully. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Run `git commit`, or any command that writes to the repository or its index. -- Stage, unstage, or modify files. -- Ask the user to stage or confirm staging. -- Analyze unstaged or untracked changes. -- Return more than one message in `bypass` mode. -- Return split guidance in `bypass` mode. -- Stop for plan-citation ambiguity in `bypass` mode. -- Invent plan slugs, task IDs, or issue references. -- Mention `context/` synchronization activity in a commit message. -- Claim a message was committed. -- Run plan, task, or validation workflows. - -## Completion - -The skill is complete after: - -- The staged diff was read, or reading it failed and was reported. -- Messages were written for every staged file, or a blocker prevented it. -- One valid terminal YAML result matching `references/commit-contract.yaml` was - returned. diff --git a/.pi/skills/sce-atomic-commit/references/commit-contract.yaml b/.pi/skills/sce-atomic-commit/references/commit-contract.yaml deleted file mode 100644 index 5ffdd9ff..00000000 --- a/.pi/skills/sce-atomic-commit/references/commit-contract.yaml +++ /dev/null @@ -1,205 +0,0 @@ -version: 1 -name: sce-atomic-commit-result - -description: > - Output contract for sce-atomic-commit. The skill returns exactly one YAML - document representing proposal, bypass_message, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be proposal, bypass_message, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. - - Return proposal only in regular mode, and bypass_message only in bypass - mode. blocked is valid in both. - - Every staged file must appear under exactly one commit's files. - - Report file paths exactly as `git diff --cached --name-only` reports them. - - Carry the message body inside message, separated from the subject by one - blank line. Do not split it into a separate field. - - Do not include a commit hash. This skill never commits. - - Do not report guidance the mode forbids. - -variants: - - proposal: - meaning: > - The staged changes were analyzed in regular mode and one or more atomic - commit messages were written. Proposal-only: nothing was committed. - - required_fields: - - status - - mode - - commits - - optional_fields: - - split_rationale - - scope_classification - - notes - - field_rules: - - Include split_rationale only when commits holds more than one entry. - - scope_classification reports the context-file guidance gate as - context_only or mixed. - - shape: - status: proposal - mode: regular - - commits: - - id: string - message: string - files: - - string - cites_plan: boolean - - split_rationale: string - scope_classification: context_only | mixed - - notes: - - string - - example: - status: proposal - mode: regular - - commits: - - id: C01 - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full - re-login. Adds the refresh handler and reuses the existing token - issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - - id: C02 - - message: | - build: Pin the formatter to the toolchain version - - The formatter floated across environments and produced diff noise - unrelated to any change. - - files: - - flake.nix - - cites_plan: false - - split_rationale: > - The refresh endpoint and the formatter pin pursue unrelated goals and - share no files. Committing them together would hide the build change - behind a feature subject. - - scope_classification: mixed - - bypass_message: - meaning: > - The staged changes were analyzed in bypass mode and exactly one commit - message covering all staged files was written. The invoking workflow - executes the commit. - - required_fields: - - status - - mode - - message - - files - - optional_fields: - - cites_plan - - notes - - field_rules: - - files lists every staged file, because one message covers all of them. - - Never include commits, split_rationale, or scope_classification. - - shape: - status: bypass_message - mode: bypass - - message: string - - files: - - string - - cites_plan: boolean - - notes: - - string - - example: - status: bypass_message - mode: bypass - - message: | - auth: Add token refresh endpoint - - Sessions expired without a way to renew them, forcing a full re-login. - Adds the refresh handler and reuses the existing token issuer. - - files: - - src/auth/refresh.ts - - tests/auth/refresh.test.ts - - cites_plan: false - - blocked: - meaning: > - Faithful commit messages cannot be written from the staged changes. - - required_fields: - - status - - issues - - optional_fields: - - mode - - files - - field_rules: - - Include mode whenever the workflow supplied one. - - Include files when staged files were read before blocking. - - Plan-citation ambiguity blocks in regular mode only. In bypass mode the - citation is omitted instead. - - shape: - status: blocked - mode: regular | bypass - - files: - - string - - issues: - - id: string - category: no_staged_changes | plan_citation_ambiguity | unreadable_diff | contradictory_context - problem: string - impact: string - decision_required: string - - example: - status: blocked - mode: regular - - files: - - context/plans/authentication.md - - issues: - - id: B01 - category: plan_citation_ambiguity - - problem: > - The staged plan diff changes two task checkboxes and does not - expose which task this commit completes. - - impact: > - The commit body would cite a task ID the staged diff does not - support. - - decision_required: > - State the completed task ID, or stage only that task's plan edit. diff --git a/.pi/skills/sce-change-to-plan/SKILL.md b/.pi/skills/sce-change-to-plan/SKILL.md new file mode 100644 index 00000000..a03d3b98 --- /dev/null +++ b/.pi/skills/sce-change-to-plan/SKILL.md @@ -0,0 +1,803 @@ +--- +name: sce-change-to-plan +description: > + Turn one change request into a scoped SCE plan in one self-contained workflow +--- + +# SCE Change to Plan + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Context load phase** -> the **Plan authoring phase** to turn a change request into a scoped SCE plan" +argument-hint: "" + + +SCE CHANGE TO PLAN `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the change request, in free-form prose. + +- The change request is required. +- It may describe a new plan or a change to an existing plan. Do not resolve which one applies; the **Plan authoring phase** owns that decision. + +When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. + +Pass the change request to the **Plan authoring phase** unmodified. Do not restate, summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan authoring phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Load durable context + +Run the **Context load phase** with the change request as the focus. + +`context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. + +The skill must return a result matching its context brief contract. + +Branch on `status`: + +`bootstrap_required` -> `context/` does not exist. Do not create it, and do not plan without it. Return: + +``` + +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +Wait for the user. When they report the command ran, run the **Context load phase** again and continue in this session. Do not restart planning, and do not ask for the change request again. + +`loaded` -> Continue to the next step. + +Do not read `context/` yourself. Do not repair drift or stale context; the brief reports it and the plan may schedule the repair. + +### 2. Author the plan + +Run the **Plan authoring phase** with the change request and the complete `loaded` brief from the **Context load phase**. + +Pass the brief verbatim. Do not restate, summarize, or reinterpret it. + +the **Plan authoring phase** exclusively owns: + +- Resolving whether the request targets a new or an existing plan. +- The clarification gate. +- Normalizing the change summary, acceptance criteria, constraints, and non-goals. +- Slicing the task stack into one-task/one-atomic-commit units. +- Writing `context/plans/{plan_name}.md`. + +Do not duplicate any of it. Do not write or edit the plan file yourself. + +The skill must return a result matching its authoring contract. + +Branch on `status`: + +`needs_clarification` -> No plan was written. Present the result as prose. Do not print the raw result. Return: + +``` + +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +Render one `##` block per entry in `questions`, in result order. Use the question's `id`, `category`, `question`, and `why_blocking` fields exactly as returned. + +Do not answer the questions. Do not assume answers. Do not write a plan. Stop and wait. + +`blocked` -> No plan was written. Present the result as prose. Do not print the raw result. Present: + +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `candidates` is present, the candidate plan paths, and that naming the intended `{candidate-path}` in the change request resolves the ambiguity. + +Stop. + +`plan_ready` -> Continue to the next step. + +### 3. Determine the continuation + +Render the `plan_ready` result as the summary defined by the **Plan authoring phase** in `references/output.md`. Follow that layout exactly. Do not print the raw result. + +Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. + +Write `task` rather than `tasks` when `total_tasks` is 1. + +Offer revision, but do not gate the handoff on it, do not manufacture concerns, and do not ask the user to confirm the plan. When the summary lists open questions, leave them in the summary only — do not restate them in the continuation, do not answer them, and do not block the handoff on them. Blocking questions belong in `needs_clarification` (step 2), not here. + +Return: + +``` + +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} tasks planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +Then stop and wait. Do not implement, and do not run the handoff yourself. + +### 4. Revise the plan on request + +When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. + +Run the **Plan authoring phase** with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + +An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. + +Pass the correction as written. Do not restate, soften, or pre-scope it. the **Plan authoring phase** owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + +Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. + +On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. + +Revise as many times as the user asks. Each revision is one invocation of the **Plan authoring phase** against the same plan. + +When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. + +Stop. + +## Rules + +- Plan at most one change request per invocation. Revisions to the plan that request produced are part of the same invocation, not a second request. +- Always tell the user the plan can be revised, and always name its assumptions as the first thing worth checking. +- Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. +- Do not suppress, soften, or answer an open question or clarification question on the user's behalf. +- Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. +- Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to the **Plan authoring phase** as written. +- Do not duplicate the internal instructions of embedded phases. +- Do not plan before durable context is loaded. +- Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. +- Do not modify any file under `context/` outside `context/plans/`. +- Do not implement any part of the plan. +- Do not ask for implementation confirmation. +- Do not run task execution, context synchronization, or full-plan validation. +- Do not emit a `/validate` command. This workflow always hands off to `/next-task`. +- Do not answer the skill's clarification questions on the user's behalf. +- Do not execute the continuation returned at the end. +- Do not infer success when the **Plan authoring phase** returns a non-`plan_ready` status. + +## Embedded phase behavior + +## Internal phase: Context load phase + + +name: Context load phase +description: > + Internal SCE workflow skill that loads the durable context in `context/` + relevant to one focus, reports gaps and context-versus-code drift, and returns + one internal state: loaded or bootstrap_required. Use from /change-to-plan and + any workflow that needs durable context before acting. Do not modify context, + repair drift, plan, or implement. + + +# SCE Context Load + +## Purpose + +Load the durable context needed to reason about one focus, and no more. + +`context/` is AI-first memory describing current state. This skill turns it into +a scoped brief so later phases start from recorded truth instead of rediscovering +the repository. + +This skill owns: + +- Confirming `context/` exists. +- Reading the context entry points. +- Selecting the domain context relevant to the focus. +- Reporting focus areas with no durable context. +- Reporting context that contradicts the code. +- Recording one structured context brief. + +Return a result matching: + +the internal context-load state described by this workflow + +## Input + +The invoking workflow provides: + +- One focus: a change request, a task, or a named area. +- Optionally, paths or areas already known to be relevant. + +## Workflow + +### 1. Confirm the context root + +When `context/` does not exist, set internal status `bootstrap_required` immediately. Read +nothing further. + +Bootstrapping is the invoking workflow's decision, not this skill's. + +### 2. Read the entry points + +Read, when present: + +- `context/context-map.md` +- `context/overview.md` +- `context/glossary.md` + +Read `context/architecture.md` when the focus touches structure, boundaries, or +data flow. Read `context/patterns.md` when it touches conventions the change +must follow. + +A missing entry point is a gap, not a failure. Record it and continue. + +### 3. Select the relevant domain context + +Consult `context/context-map.md` before any broad exploration. The map's +annotations name what each domain file owns; use them to select files, rather +than globbing or searching `context/`. + +Select only files whose subject overlaps the focus. Follow at most one level of +links out of a selected file, and only when the link is needed to understand the +focus. + +Do not read every domain file. A brief that includes everything has selected +nothing. + +Record focus areas with no matching context file under `gaps`. + +### 4. Check recorded context against the code + +For each selected file, spot-check its central claims against the code it +describes. + +When context and code diverge, the code is the source of truth. Record the +divergence under `drift` with what context says, what the code shows, and the +repair the context needs. + +Do not repair it here. Later phases decide whether repair belongs in the current +work. + +Keep this proportional: check the claims the focus depends on, not every +sentence. + +### 5. Return the brief + +Set exactly one internal state: + +- `loaded` +- `bootstrap_required` + +Report facts the invoking workflow can act on. A brief that only lists file +paths has moved no knowledge. + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Create, update, move, or delete any file under `context/`. +- Bootstrap `context/`. +- Repair drift or stale context. +- Modify application code or tests. +- Read the entire `context/` tree by default. +- Explore the repository beyond what the focus and the selected context require. +- Ask the user questions. Report gaps and drift, and let the invoking workflow + decide. +- Author a plan, select a task, or implement anything. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or `bootstrap_required` was returned. +- The entry points were read, and the relevant domain context was selected and + read. +- One valid result matching the internal context-load state described by this workflow was returned. + +## Internal phase: Plan authoring phase + + +name: Plan authoring phase +description: > + Internal SCE workflow skill that turns one change request into a scoped plan + in `context/plans/`, sliced into atomic implementation tasks, and returns one + internal state: plan_ready, needs_clarification, or blocked. Use from + /change-to-plan. Do not implement plan tasks, request implementation approval, + synchronize context, or run final validation. + + +# SCE Plan Authoring + +## Purpose + +Turn exactly one change request into `context/plans/{plan_name}.md` without +inventing material requirements. + +This skill owns: + +- Resolving whether the request targets a new or an existing plan. +- Judging whether the change is worth making, and recording the doubt when it + is not clear that it is. +- Deciding whether the request can be planned safely. +- Normalizing the change summary, acceptance criteria, constraints, and + non-goals. +- Slicing the work into atomic implementation tasks. +- Writing the plan file. +- Recording one structured authoring result. + +Use the document format defined in: + +the **Plan template** section embedded in this file + +Return a result matching: + +the internal authoring state described by this workflow + +The invoking workflow renders that result as the summary defined in: + +`references/output.md` + +## Input + +The invoking workflow provides: + +- One change request, in free-form prose. +- The `loaded` context brief from the **Context load phase**. + +The change request may name a plan, describe a change to an existing plan, or +describe entirely new work. Resolving which applies is this skill's +responsibility. + +The context brief is the durable memory this plan starts from. Treat its +`key_facts` as recorded current state, its `gaps` as areas with no durable +context, and its `drift` as context the code has already outrun. + +When no brief is supplied, load the context named by the change request before +authoring, and follow the selection discipline in *Inspect relevant context*. + +Answers the user gave to earlier clarification questions arrive as part of the +change request. Incorporate them into the plan. + +A revision of a plan authored earlier in the session also arrives as the change +request, and it is usually terse: a task boundary the user disagrees with, an +ordering they want changed, work they want added or dropped. Read it against the +existing plan, which supplies the scope, criteria, and terminology it omits. +Terseness is not ambiguity. Do not set internal status `needs_clarification` for detail the +plan already carries; ask only when the revision itself is genuinely undecidable. + +## Workflow + +### 1. Resolve the plan target + +Determine whether the request targets a new plan or an existing plan in +`context/plans/`. + +When it targets an existing plan, read that plan before authoring. Preserve its +completed tasks, their recorded evidence, its structure, and its terminology. + +When multiple existing plans match and none can be selected safely, return +`blocked` with the matching candidates. + +When the request targets a new plan, derive `plan_name` as a short kebab-case +slug of the change, and confirm it does not collide with an existing plan. + +Resolve exactly one plan target per invocation. + +### 2. Challenge the change + +Before planning how to build the change, work out whether it is worth building. +A plan is a commitment of someone's time; authoring one for work that should not +happen is worse than authoring none. + +Interrogate the request: + +- What breaks, or stays broken, if this is never built? If the answer is + nothing concrete, say so. +- What problem is it actually solving, as opposed to what it proposes to do? A + request that names only a solution has not stated a problem. +- Does the repository already do this, or most of it? The brief's `key_facts` + are the first place to check. +- Is there a materially smaller version that gets most of the value? Name it. +- What does this cost beyond the tasks: new dependency, new concept in the + glossary, a boundary crossed, a surface that now needs maintaining forever? +- Does the stated justification survive contact with the code, or does the code + show the premise is already false? + +Doubt that survives this is not an implementation detail to be tidied away. It +belongs in the plan's `Open questions` and in `open_questions`, in the plain +words you would use to a colleague. "Is this worth doing at all, given X?" is a +legitimate open question. So is "this looks like it duplicates Y". + +Weigh honestly in both directions. A request that is obviously worth building +gets no manufactured doubt: inventing questions to look rigorous is its own +failure, and it teaches the user to ignore the section. Most changes are fine. +Say nothing when there is nothing to say. + +Keep going regardless. Skepticism shapes the plan and the open questions; it +does not withhold the plan. The only value judgment that stops authoring is +`no_actionable_work`, when the change is already implemented. + +### 3. Run the clarification gate + +Before writing or updating any plan file, check the request for critical +unresolved detail: + +- Scope boundaries and out-of-scope items. +- Acceptance criteria and the checks that prove them. +- Constraints and non-goals. +- Dependency choices, including new libraries or services, versions, and the + integration approach. +- Domain ambiguity, including unclear business rules, terminology, or ownership. +- Architecture concerns, including patterns, interfaces, data flow, migration + strategy, and risk tradeoffs. +- Task ordering assumptions and prerequisite sequencing. + +Set internal status `needs_clarification` with one to three targeted questions when any of +these would materially change the plan. Write no plan file in that case. + +Use repository conventions for ordinary local choices. Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change scope, acceptance criteria, or task ordering. + +Record those choices under `assumptions`. + +Do not silently invent missing requirements. When the user has explicitly +allowed assumptions, record them in the plan's `Assumptions` section instead of +asking. + +A justification that does not survive inspection is itself a critical unresolved +detail. "For consistency", "to make it cleaner", "we will need it later" name no +outcome and prove nothing; ask what the change is actually for before planning +around it. Do not treat confident phrasing as evidence. + +### 4. Inspect relevant context + +Start from the context brief. Read code only where the brief leaves the change +underspecified: + +- Existing behavior the change affects. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests and available verification commands. +- Decisions or specifications connected to the change. + +Where the brief reports `drift`, the code is the source of truth. Plan against +the code, and schedule the context repair as part of the change when it falls +inside scope. + +Where the brief reports `gaps`, the plan may need to establish durable context +the repository does not yet have. + +Do not explore the entire repository by default. + +### 5. Author the acceptance criteria + +State how the finished plan is proven, before slicing tasks. + +Each criterion describes observable behavior of the finished system and names +the check that proves it. Record repository-wide checks once under +`Full validation`, and the durable context the change must be reflected in +under `Context sync`. + +`/validate` runs this section after the last task completes. It is the only +place a plan says how it is validated. + +### 6. Author the task stack + +Slice the work into sequential tasks `T01..T0N` using the task format and the +atomic slicing contract in the **Plan template** section embedded in this file. + +Every executable task must be completable and landable as one coherent commit. +Split any task that would require multiple independent commits. Convert broad +wrappers such as `polish` or `finalize` into specific outcomes with concrete +acceptance checks. + +Order tasks so each one's declared dependencies precede it. + +The last task is an ordinary implementation task. Do not author a trailing +validation-and-cleanup task, or any task whose only purpose is running the full +check suite, verifying durable context, or removing scaffolding. + +Confirm every acceptance criterion is satisfied by at least one task. When one +is not, the task stack is incomplete. + +A finished stack always leaves at least one incomplete task, so the invoking +workflow can always hand off to `/next-task`. When the request resolves to a +plan but produces no incomplete task, because the change is already implemented +or already covered by completed tasks, set internal status `blocked` with category +`no_actionable_work` instead of writing the plan. + +### 7. Write the plan + +Write `context/plans/{plan_name}.md` using the **Plan template** section embedded in this file. + +When updating an existing plan, keep completed tasks and their evidence intact, +and append or renumber new tasks without disturbing recorded history. + +### 8. Return the result + +Set exactly one internal state: + +- `plan_ready` +- `needs_clarification` +- `blocked` + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Tone + +Every question and open question this skill writes is read by the user. Write +them the way a senior engineer talks in review: direct, specific, and unbothered +by the possibility of being unwelcome. + +- Ask about the thing that actually worries you, not a safer neighbouring thing. + A question you would not bother asking a colleague is not worth the user's + attention either. +- State a doubt as a doubt. "I do not think this is worth the two tasks it + costs, because X" is useful. "It may be worth considering whether this aligns + with broader goals" is noise. +- Name the alternative you have in mind. A challenge with no proposal behind it + is just friction. +- Do not open with praise, do not close with reassurance, and do not apologize + for asking. Do not pad a doubt with hedges to make it land more gently. +- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not + restate the same doubt in three shapes to give it more weight. +- Being disagreeable is not the goal. Being easy to agree with is the failure + mode. A plan the user waves through without reading has cost them nothing and + bought them nothing. + +When the user overrules a doubt, record it and move on. Do not relitigate a +decision the user has made, and do not smuggle the objection back in as a +constraint, a non-goal, or a task. + +## Boundaries + +Do not: + +- Ask the user questions directly. Set internal status `needs_clarification` and let the + invoking workflow present the questions. +- Answer your own clarification questions. +- Write a plan file when returning `needs_clarification` or `blocked`. +- Implement any task in the plan. +- Modify application code or tests. +- Modify any file under `context/` outside `context/plans/`. Plan the context + repair instead of performing it. +- Mark any task complete. +- Request implementation confirmation. +- Run task execution. +- Synchronize context. +- Run final validation. +- Author a validation, cleanup, or context-verification task. `/validate` owns + that phase. +- Set internal status `plan_ready` for a plan with no incomplete task. +- Create a Git commit. +- Author more than one plan. + +## Completion + +The skill is complete after: + +- One plan target was resolved, or resolution failed and was reported. +- The plan file was written, or no file was written because the result is + `needs_clarification` or `blocked`. +- One valid result matching the internal authoring state described by this workflow was returned. + +## Internal persisted-document format: Plan template + +# SCE Plan Template + +The document format for `context/plans/{plan_name}.md`. This is the plan file +written to disk, not the result returned to the invoking workflow. + +Copy the template below and fill every `{placeholder}`. Omit optional sections +entirely rather than writing them empty. + +--- + +## Template + +```markdown +# Plan: {plan-name} + +## Change summary + +{One or two paragraphs: what changes, where, and why. State whether this +extends existing behavior, replaces it, or preserves work already in progress.} + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [ ] AC1: {observable outcome, stated as behavior rather than as work done} + - Validate: `{command, assertion, or inspection that proves AC1}` +- [ ] AC2: {observable outcome} + - Validate: `{command, assertion, or inspection that proves AC2}` + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `{full check suite command}` +- `{generated-output or parity check command, when applicable}` + +### Context sync + +- {Durable context files that must describe the change once implemented.} + +## Constraints and non-goals + +- **In scope:** {files, modules, and surfaces this plan may touch} +- **Out of scope:** {adjacent work explicitly excluded} +- **Constraints:** {dependencies, conventions, compatibility, or policy limits} +- **Non-goal:** {tempting generalization this plan deliberately avoids} + +## Assumptions + +{Include only when the user allowed assumptions, or ordinary local choices were +recorded. Remove the section otherwise.} + +- {Assumption, and the convention or decision record it rests on.} + +## Task stack + +- [ ] T01: `{single intent title}` (status:todo) + - Task ID: T01 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: {task IDs, or none} + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +- [ ] T02: `{single intent title}` (status:todo) + - Task ID: T02 + - Goal: {one outcome} + - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. + - Dependencies: T01 + - Done when: {clear acceptance for one coherent change} + - Verification notes (commands or checks): {targeted checks for this change} + +## Open questions + +{Non-blocking questions only. A question that would change scope, success +criteria, or task ordering blocks authoring instead. Write `None.` with a short +justification when nothing remains.} + +{Unresolved doubt about the change's value belongs here — whether it is worth +building, whether it duplicates behavior the repository already has, whether a +smaller version would do. State it plainly and name the alternative. Do not +invent one: `None.` is the expected answer for a well-specified change.} +``` + +--- + +## Filled-in task example + +```markdown +- [ ] T02: `Add /auth/refresh endpoint` (status:todo) + - Task ID: T02 + - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. + - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. + - Dependencies: T01 + - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. + - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. +``` + +## Acceptance criteria rules + +- Acceptance criteria describe the finished system, not the work. Prefer "the + endpoint returns 401 on an expired token" over "add expiry handling". +- Every criterion carries a `Validate:` line. A criterion nobody can check is + not an acceptance criterion. +- Prefer a runnable command. Fall back to a named inspection only when no + automated check exists, and say exactly what to look at. +- List repository-wide checks once under `Full validation` instead of repeating + them per criterion. +- Task-level `Verification notes` prove one task. Acceptance criteria prove the + plan. Keep them distinct: a task's checks are narrow and local, a criterion's + check is end-to-end. +- The union of the acceptance criteria must cover every success signal in the + change request. If a criterion has no task that could satisfy it, the task + stack is incomplete. + +## Task rules + +- Every task is a checkbox line so progress stays machine-readable: + `- [ ] T01: {title} (status:todo)`. +- Author each executable task as one atomic commit unit by default. +- Scope every task so one contributor can complete it and land it as one + coherent commit without bundling unrelated changes. +- Split any candidate task that would require multiple independent commits, for + example a refactor plus a behavior change plus documentation. +- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of + executable tasks. Convert them into specific outcomes with concrete + acceptance checks. +- Order tasks so each one's declared dependencies precede it. + +## No validation task + +- The last task in the stack is an ordinary implementation task. Do not author a + trailing "validation and cleanup" task. +- Final validation, cleanup, and success-criteria verification are run by + `/validate` from the `Acceptance criteria` section after the last task + completes. +- Do not author a task whose only purpose is running the full check suite, + verifying durable context, or removing scaffolding. +- A task may still create or update durable context when that context is part of + the change itself. + +## Completion records + +the **Task execution phase** appends evidence to a task when it completes, and flips the +checkbox and status: + +```markdown +- [x] T01: `{title}` (status:done) + - {authored fields, unchanged} + - Completed: {YYYY-MM-DD} + - Files changed: {paths} + - Evidence: {commands run and their outcomes} + - Notes: {material deviations or approved assumptions} +``` + +`/validate` appends a `## Validation Report` section at the end of the plan. +Do not author either while planning. + +## Updating an existing plan + +- Preserve completed tasks, their `(status:done)` markers, and their recorded + evidence verbatim. +- Preserve the plan's existing structure and terminology. +- Append new tasks after the existing stack. Renumber only when added work must + run earlier, and never renumber a completed task. +- Add acceptance criteria for newly planned outcomes rather than rewriting + criteria already satisfied. + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.opencode/skills/sce-plan-authoring/references/plan-summary.md b/.pi/skills/sce-change-to-plan/references/output.md similarity index 69% rename from .opencode/skills/sce-plan-authoring/references/plan-summary.md rename to .pi/skills/sce-change-to-plan/references/output.md index 0261808d..c2351217 100644 --- a/.opencode/skills/sce-plan-authoring/references/plan-summary.md +++ b/.pi/skills/sce-change-to-plan/references/output.md @@ -1,3 +1,62 @@ +# Change-to-plan output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Missing context bootstrap gate + +```markdown +------------------------------------- + +# This repository has no durable context. + +Bootstrap it, then continue in this session: + +`sce setup --bootstrap-context` +``` + +## Clarification gate + +```markdown +------------------------------------- + +# Clarification needed. + +No plan was written. + +Answer each question below. + +## {question-id} · {category} + +{question} + +Why this blocks planning: {why_blocking} +``` + +## Blocked + +Present each issue's problem, impact, and required decision. For ambiguity, list +candidate plan paths and explain that naming one candidate resolves it. + +## Ready continuation + +```markdown +------------------------------------- + +# Plan {plan-name} is ready. + +{total-tasks} {task|tasks} planned. + +This plan is a draft. State a correction and it will be updated. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +For revisions, replace `is ready` with `revised`. + # SCE Plan Summary The user-facing summary shown after a plan is written. The invoking workflow diff --git a/.pi/skills/sce-commit/SKILL.md b/.pi/skills/sce-commit/SKILL.md new file mode 100644 index 00000000..9c843242 --- /dev/null +++ b/.pi/skills/sce-commit/SKILL.md @@ -0,0 +1,333 @@ +--- +name: sce-commit +description: > + Analyze staged changes and run the regular or explicit bypass commit workflow +--- + +# SCE Commit + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Atomic commit phase** to turn staged changes into atomic commit message proposals" +argument-hint: "[oneshot|skip] [commit context]" + + +SCE COMMIT `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is optional. Split it into two parts before invoking the skill: + +`[mode-token] [commit context]` + +- `mode-token` is present only when the first whitespace-separated token is + exactly `oneshot` or `skip`, compared case-insensitively. Any other first + token is not a mode token. +- `commit context` is everything else: free-form prose that refines message + wording only. + +A `mode-token` selects the bypass path. Its absence selects the regular path. +Do not infer the bypass path from anything else — not from the commit context, +not from repository state, and not from the conversation. + +Empty `$ARGUMENTS` is valid. It selects the regular path with no commit +context, and commit intent is inferred from the staged changes alone. + +Pass `commit context` to the **Atomic commit phase** unmodified. Do not restate, +summarize, or pre-scope it. Never pass the `mode-token` as commit context. + +Staged changes are the source of truth for what is being committed. This +command never stages, unstages, or modifies files. + +## Workflow + +Follow exactly one path. + +### Bypass path (`oneshot` or `skip`) + +#### 1. Validate that staged content exists + +Run `git diff --cached --quiet`. A zero exit status means nothing is staged. + +When nothing is staged, stop with exactly: + +`No staged changes. Stage changes before commit.` + +Do not stage anything. Do not proceed to the skill. + +#### 2. Request one commit message + +Run the **Atomic commit phase** with `mode: bypass` and the commit context. + +Bypass mode is the skill's contract for producing exactly one message. Do not +restate its overrides here; the **Atomic commit phase** owns them. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and stop. Do not commit. + +`bypass_message` -> Continue to the next step. + +The skill never returns `proposal` in bypass mode. Treat a `proposal` result as +a contract violation: report it and stop without committing. + +#### 3. Execute exactly one commit + +Run `git commit` once with the returned message. + +On success, report the resulting commit hash and stop. + +On failure, report the failure as returned by Git and stop. Do not retry, do +not amend, do not stage additional files, and do not invent a fallback commit. + +### Regular path (no mode token) + +#### 1. Confirm staging + +Before invoking the skill, stop and prompt the user: + +``` +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +Wait for the user's confirmation. Do not stage files on their behalf, and do +not skip this prompt because the working tree looks ready. + +#### 2. Propose commits + +After confirmation, run the **Atomic commit phase** with `mode: regular` and the +commit context. + +the **Atomic commit phase** exclusively owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Classifying staged scope and applying context-file guidance gating. +- Writing every commit message subject and body. +- Applying the plan-citation body rule. + +Do not duplicate any of it. Do not write commit messages yourself. + +The skill must return a result matching its commit contract. Branch on +`status`: + +`blocked` -> Present the issue and the decision it requires. Stop. + +`proposal` -> Present each proposed commit: its message, the files it covers, +and, when more than one commit is proposed, why the split is recommended. + +Then stop. The regular path is proposal-only. + +Do not run `git commit`. Do not offer to commit on the user's behalf. The user +runs the commits they accept. + +## Rules + +- Produce at most one commit per invocation, and only on the bypass path. +- Never commit on the regular path. +- Recognize `oneshot` and `skip` only as an exact case-insensitive first token. + They are behaviorally identical. +- Do not duplicate the internal instructions of the **Atomic commit phase**. +- Do not stage, unstage, restore, or otherwise modify files. +- Do not amend, reset, revert, rebase, or push. +- Do not read unstaged or untracked changes as commit input. +- Do not infer success when the **Atomic commit phase** returns a non-success status. +- Do not proceed past a failed `git commit`. +- Do not run plan, task, or validation workflows from this command. + +## Embedded phase behavior + +## Internal phase: Atomic commit phase + + +name: Atomic commit phase +description: > + Internal SCE workflow skill that analyzes the staged diff and returns atomic, + repository-style commit messages: coherent-unit detection, split guidance, + scope and subject wording, and the plan-citation body rule. Returns one internal state + result (proposal, bypass_message, or blocked). Use from /commit. Do not stage + files, create commits, or ask the user to confirm staging. + + +# SCE Atomic Commit + +## Purpose + +Turn the current staged changes into atomic repository-style commit messages. + +This skill owns: + +- Reading and analyzing the staged diff. +- Deciding whether staged changes form one coherent unit or several. +- Choosing the scope and writing the subject and body of every message. +- Applying the plan-citation body rule. +- Classifying staged scope and applying context-file guidance gating. +- Recording one terminal internal state. + +Write messages matching: + +`references/output.md` + +Return a result matching: + +the internal commit state described by this workflow + +Committing is not this skill's job. The invoking `/commit` workflow decides +whether a returned message is committed, and it is the only thing that runs +`git commit`. + +## Input + +The invoking workflow provides: + +- A mode: `regular` or `bypass`. +- Optional commit context, in free-form prose. + +The mode is supplied by the workflow from an explicit user-supplied token. +Never infer it, and never switch modes mid-analysis. + +Commit context refines wording only. The staged diff decides what the change +is; context never overrides staged truth, and never adds a claim the diff does +not support. + +Do not accept an unstaged diff, a working-tree summary, or a conversational +description as a substitute for the staged diff. + +## Workflow + +### 1. Read the staged diff + +Read the staged changes with `git diff --cached`, and the staged file list with +`git diff --cached --name-status`. + +Read staged file contents only when the diff alone does not explain the change. + +Set internal status `blocked` when nothing is staged. + +### 2. Identify coherent units + +Infer the main reason for the staged change from the diff first. + +A coherent unit is one goal a reviewer would accept as a single commit. Group +staged files by that goal, not by directory. + +In `bypass` mode, stop grouping here: the result is exactly one message +covering all staged files, whether or not the diff is coherent. Do not propose +splits, and do not report split guidance. + +### 3. Choose a scope for each unit + +Use the smallest stable subsystem or module name recognizable in the repository. + +When no such name applies, use the primary directory or package of the unit's +changes. + +### 4. Write each message + +Follow `references/output.md` for the subject pattern, the body +rules, issue references, the plan-citation rule, and the anti-patterns. + +### 5. Apply the plan-citation rule + +When the unit's staged files include `context/plans/*.md`, cite the affected +plan slug and updated task IDs in the body. + +When the staged plan diff does not expose the slug or task ID clearly enough to +cite faithfully: + +- In `regular` mode, set internal status `blocked` and ask for the reference to be stated or + staged explicitly. +- In `bypass` mode, infer the citation when the diff supports it, and otherwise + omit it. Never stop, and never invent a slug or task ID. + +### 6. Apply context-file guidance gating + +This step applies in `regular` mode only. Skip it entirely in `bypass` mode; do +not classify staged scope there. + +Classify the staged diff: + +- Context-only (`context/**`): context-file-focused guidance is allowed. +- Mixed (`context/**` plus non-`context/**`): suppress default context-file + commit reminders and give guidance that reflects the full staged scope. + +### 7. Propose split guidance + +This step applies in `regular` mode only. + +When the units found in step 2 pursue unrelated goals, return one message per +unit, and state why the split is recommended and which staged files belong to +each. + +When the staged changes form one unit, return one message and no split +guidance. Do not split coherent work to appear thorough. + +### 8. Validate the result + +Confirm before returning that: + +- Every message describes its unit faithfully and covers only that unit's files. +- Every staged file belongs to exactly one returned message. +- No plan slug or task ID appears that the staged diff does not support. +- The mode's own constraints hold. + +### 9. Return internal state + +Set exactly one internal state matching the internal commit state described by this workflow: + +- `proposal` in `regular` mode, with one or more messages. +- `bypass_message` in `bypass` mode, with exactly one message. +- `blocked` when messages cannot be written faithfully. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Run `git commit`, or any command that writes to the repository or its index. +- Stage, unstage, or modify files. +- Ask the user to stage or confirm staging. +- Analyze unstaged or untracked changes. +- Return more than one message in `bypass` mode. +- Return split guidance in `bypass` mode. +- Stop for plan-citation ambiguity in `bypass` mode. +- Invent plan slugs, task IDs, or issue references. +- Mention `context/` synchronization activity in a commit message. +- Claim a message was committed. +- Run plan, task, or validation workflows. + +## Completion + +The skill is complete after: + +- The staged diff was read, or reading it failed and was reported. +- Messages were written for every staged file, or a blocker prevented it. +- One valid terminal internal state matching the internal commit state described by this workflow was + returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.pi/skills/sce-atomic-commit/references/commit-message-style.md b/.pi/skills/sce-commit/references/output.md similarity index 69% rename from .pi/skills/sce-atomic-commit/references/commit-message-style.md rename to .pi/skills/sce-commit/references/output.md index 7a1b5084..fb62021a 100644 --- a/.pi/skills/sce-atomic-commit/references/commit-message-style.md +++ b/.pi/skills/sce-commit/references/output.md @@ -1,6 +1,45 @@ +# Commit output layouts + +Use only the applicable layout. Values come from staged truth and internal +workflow state. + +## Regular-mode staging gate + +```markdown +Please run `git add ` for all changes you want included in this commit. +Atomic commits should only include intentionally staged changes. +Confirm once staging is complete. +``` + +## No staged changes + +```markdown +No staged changes. Stage changes before commit. +``` + +## Regular proposal + +For each proposal, present the complete commit message and covered files. When +more than one commit is proposed, also present the split rationale. Do not claim a +commit was created. + +## Blocked + +Present every issue's problem, impact, and required decision. Do not commit. + +## Bypass success + +```markdown +Committed {commit-hash} +``` + +## Bypass Git failure + +Present Git's failure unchanged and stop without retrying. + # Commit message style -The wording rules for every message `sce-atomic-commit` returns, in either +The wording rules for every message the **Atomic commit phase** returns, in either mode. This file is the only authority for message content and shape. Messages are carried in the result's `message` field, subject first, then one diff --git a/.pi/skills/sce-context-load/SKILL.md b/.pi/skills/sce-context-load/SKILL.md deleted file mode 100644 index c944be76..00000000 --- a/.pi/skills/sce-context-load/SKILL.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: sce-context-load -description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. ---- - -# SCE Context Load - -## Purpose - -Load the durable context needed to reason about one focus, and no more. - -`context/` is AI-first memory describing current state. This skill turns it into -a scoped brief so later phases start from recorded truth instead of rediscovering -the repository. - -This skill owns: - -- Confirming `context/` exists. -- Reading the context entry points. -- Selecting the domain context relevant to the focus. -- Reporting focus areas with no durable context. -- Reporting context that contradicts the code. -- Returning one structured context brief. - -Return a result matching: - -`references/context-brief.yaml` - -## Input - -The invoking workflow provides: - -- One focus: a change request, a task, or a named area. -- Optionally, paths or areas already known to be relevant. - -## Workflow - -### 1. Confirm the context root - -When `context/` does not exist, return `bootstrap_required` immediately. Read -nothing further. - -Bootstrapping is the invoking workflow's decision, not this skill's. - -### 2. Read the entry points - -Read, when present: - -- `context/context-map.md` -- `context/overview.md` -- `context/glossary.md` - -Read `context/architecture.md` when the focus touches structure, boundaries, or -data flow. Read `context/patterns.md` when it touches conventions the change -must follow. - -A missing entry point is a gap, not a failure. Record it and continue. - -### 3. Select the relevant domain context - -Consult `context/context-map.md` before any broad exploration. The map's -annotations name what each domain file owns; use them to select files, rather -than globbing or searching `context/`. - -Select only files whose subject overlaps the focus. Follow at most one level of -links out of a selected file, and only when the link is needed to understand the -focus. - -Do not read every domain file. A brief that includes everything has selected -nothing. - -Record focus areas with no matching context file under `gaps`. - -### 4. Check recorded context against the code - -For each selected file, spot-check its central claims against the code it -describes. - -When context and code diverge, the code is the source of truth. Record the -divergence under `drift` with what context says, what the code shows, and the -repair the context needs. - -Do not repair it here. Later phases decide whether repair belongs in the current -work. - -Keep this proportional: check the claims the focus depends on, not every -sentence. - -### 5. Return the brief - -Return exactly one structured result: - -- `loaded` -- `bootstrap_required` - -Report facts the invoking workflow can act on. A brief that only lists file -paths has moved no knowledge. - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Create, update, move, or delete any file under `context/`. -- Bootstrap `context/`. -- Repair drift or stale context. -- Modify application code or tests. -- Read the entire `context/` tree by default. -- Explore the repository beyond what the focus and the selected context require. -- Ask the user questions. Report gaps and drift, and let the invoking workflow - decide. -- Author a plan, select a task, or implement anything. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or `bootstrap_required` was returned. -- The entry points were read, and the relevant domain context was selected and - read. -- One valid result matching `references/context-brief.yaml` was returned. diff --git a/.pi/skills/sce-context-load/references/context-brief.yaml b/.pi/skills/sce-context-load/references/context-brief.yaml deleted file mode 100644 index 0def559b..00000000 --- a/.pi/skills/sce-context-load/references/context-brief.yaml +++ /dev/null @@ -1,153 +0,0 @@ -version: 1 -name: sce-context-load-result - -description: > - Output contract for sce-context-load. The skill returns exactly one YAML - document representing loaded or bootstrap_required. - -output_rules: - - Return exactly one result variant. - - The top-level status must be loaded or bootstrap_required. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - List every file that was read, and no file that was not. - - Report key_facts as durable statements the invoking workflow can act on, not - as summaries of what a file discusses. - - Do not include recommendations about how to plan or implement the focus. - - Do not report context edits. This skill never writes. - -variants: - - loaded: - meaning: > - The context root exists and the context relevant to the focus was read. - - required_fields: - - status - - context_root - - entry_points - - domain_context - - gaps - - optional_fields: - - drift - - field_rules: - - List entry_points with the read status of each, including entry points - that are absent. - - Include a domain_context entry only for a file that was actually read. - - Record a gap for any focus area with no durable context, and for any - absent entry point. - - Include drift only when recorded context contradicts the code. An - absence of drift means the checked claims held. - - An empty domain_context list is valid when the context root exists but - holds nothing relevant to the focus. Record the gap. - - shape: - status: loaded - - context_root: string - - entry_points: - - path: string - read: true | false - reason: string - - domain_context: - - path: string - relevance: string - key_facts: - - string - - gaps: - - area: string - detail: string - - drift: - - path: string - context_says: string - code_says: string - repair_needed: string - - example: - status: loaded - - context_root: context/ - - entry_points: - - path: context/context-map.md - read: true - - path: context/overview.md - read: true - - path: context/glossary.md - read: true - - path: context/architecture.md - read: false - reason: The focus does not change structure, boundaries, or data flow. - - domain_context: - - path: context/cli/styling-service.md - relevance: > - Owns the CLI banner rendering the focus changes. - - key_facts: - - Color output is gated by a shared supports_color() policy honoring NO_COLOR and TTY detection. - - The banner gradient is applied per column by services::style. - - owo-colors is the established styling dependency; no theme configuration surface exists. - - - path: context/cli/cli-command-surface.md - relevance: > - Owns which help surfaces render the banner. - - key_facts: - - The top-level banner is shared by sce, sce help, and sce --help. - - Command-local help does not render the banner. - - gaps: - - area: gradient regression coverage - detail: > - No durable context records how banner rendering is tested. - - drift: - - path: context/cli/styling-service.md - context_says: The banner gradient runs right to left in cyan and magenta. - code_says: > - services::style renders a left-to-right red gradient in the current - working tree. - repair_needed: > - Update the styling context to the implemented gradient direction and - endpoints. - - bootstrap_required: - meaning: > - The context root does not exist, so no durable context could be loaded. - Nothing was read and nothing was created. - - required_fields: - - status - - context_root - - reason - - field_rules: - - Report context_root as the path that was expected. - - Do not create the directory. Bootstrapping is owned by - `sce setup --bootstrap-context`, which the user runs. - - shape: - status: bootstrap_required - - context_root: string - - reason: string - - example: - status: bootstrap_required - - context_root: context/ - - reason: > - The repository has no context/ directory, so there is no durable memory - to load for this focus. diff --git a/.pi/skills/sce-next-task/SKILL.md b/.pi/skills/sce-next-task/SKILL.md new file mode 100644 index 00000000..a07f72d6 --- /dev/null +++ b/.pi/skills/sce-next-task/SKILL.md @@ -0,0 +1,938 @@ +--- +name: sce-next-task +description: > + Review, approve, implement, verify, and synchronize one SCE plan task +--- + +# SCE Next Task + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Plan review phase** -> the **Task execution phase** -> the **Task context synchronization phase** for one SCE plan task" +argument-hint: " [T0X] [approved]" + + +SCE NEXT TASK `$ARGUMENTS` + +## Input + +Parse `$ARGUMENTS` into three positional parts before invoking any skill: + + [task-id] [auto-approve] + +- `plan-name-or-path` is required. +- `task-id` is optional. It is present only when the token matches a task ID (`T01`, `T02`, ...). +- `auto-approve` is optional. It is present only when the token is exactly `approved`. + +Resolve `auto-approve` even when `task-id` is absent. + +A token matching neither a task ID nor `approved` is an error. Report the unrecognized token and the expected arguments, and stop. Do not guess its meaning. + +Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by the **Plan review phase** (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + +## Workflow + +### 1. Review the task + +Run the **Plan review phase** with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + +Do not pass the `auto-approve` token to the **Plan review phase**. + +The skill must return a result matching its readiness contract. + +Branch on `status`: + +`blocked` -> Do not run implementation. Present the result as prose. Do not print the raw result. Stop. + +When `candidates` is present, the plan could not be resolved. Present: + +- The problem reported by the review. +- The candidate plan paths. +- `/next-task {candidate-path}` for the intended plan. + +Otherwise one plan and task were resolved. Present: + +- The task ID and title. +- Each issue in `issues`: its problem, its impact, and the decision it requires. +- When `executable_tasks_remaining` is true: other tasks remain executable, and `/next-task {plan-path} {task-id}` selects one. +- When `executable_tasks_remaining` is false: no task in the plan can proceed until the plan is updated. + +`plan_complete` -> Return: + +``` + +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +`ready` -> Pass the complete readiness result to the **Task execution phase**. + +Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. + +### 2. Execute the task + +Run the **Task execution phase** with the complete `ready` result from the **Plan review phase**. + +Branch on `auto-approve`: + +`approved` -> Also pass the `approve` flag. the **Task execution phase** then shows its implementation gate as a summary and proceeds without asking. + +else -> Do not pass the `approve` flag. the **Task execution phase** shows its implementation gate and waits for the user's decision. + +the **Task execution phase** exclusively owns: + +- Presenting the implementation summary. +- Requesting implementation confirmation. +- Implementing the task. +- Running task-level verification. +- Updating the task status and evidence. + +Do not present an additional implementation confirmation. + +Branch on the execution result. + +`declined` -> Present "You have declined to proceed with this task". Do not run context synchronization. Stop. + +`blocked` -> Present: + +- The blocker. +- Work completed before the blocker. +- The decision or action required. + +Do not run context synchronization. Stop. + +`incomplete` -> Present: + +- Work completed. +- Verification evidence. +- Remaining work. +- The reason the task is incomplete. + +Do not run context synchronization. Do not select another task. Stop. + +`complete` -> continue to the next step. + +### 3. Synchronize context + +Run the **Task context synchronization phase** with the complete `complete` result returned by the **Task execution phase**. + +Pass that result verbatim. It is the authoritative handoff, and the **Task context synchronization phase** owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the execution result. + +Branch on the synchronization result. + +`blocked` -> The task itself succeeded and is already marked complete in the plan. Present: + +- That task {completed-task-id} was implemented, verified, and recorded in the plan. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date, and that synchronization must be resolved before continuing the plan. Nothing records the skipped synchronization, so it is lost once this session ends. + +Do not select another task. Stop. + +`synced` | `no_context_change` -> Print out the report the **Task context synchronization phase** returned. Continue to the next step. + +### 4. Determine the continuation + +Use `plan.completed_tasks` and `plan.total_tasks` from the execution result to determine which continuation applies. + +Do not execute another task. Return exactly one continuation. + +If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; the **Plan review phase** checks them when the emitted command runs and returns `blocked` if they are unmet. + +Return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +If all tasks are completed return: + +``` + +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +Stop. + +## Rules + +- Execute at most one plan task per invocation. +- Review at most one task. +- Do not duplicate the internal instructions of embedded phases. +- Do not ask for implementation confirmation outside "Task execution phase". +- Do not run full-plan validation. +- Do not mark the plan complete. +- Do not execute the continuation returned at the end. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve completed work and evidence when a later phase fails. + +## Embedded phase behavior + +## Internal phase: Plan review phase + + +name: Plan review phase +description: > + Internal SCE workflow skill that resolves one task from an existing plan and + determines whether it is ready for implementation. Returns ready, blocked, or + plan_complete with a structured payload. Use from /next-task. Do not implement + changes, request implementation approval, update the plan, synchronize + context, or run final validation. + + +# SCE Plan Review + +## Purpose + +Resolve exactly one task from an SCE plan (located in `context/plans/`) and +determine whether it can enter the implementation phase without inventing +material requirements. + +This skill owns: + +- Resolving one plan. +- Selecting at most one task. +- Inspecting the context needed to judge readiness. +- Determining readiness. +- Recording one structured readiness result. + +Return a result matching: + +the internal readiness state described by this workflow + +## Input + +The invoking workflow provides: + +- A plan name or path. +- An optional task ID. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` with +the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Resolve one task + +When a task ID is supplied, select that task. + +Otherwise, select the first incomplete task in plan order whose declared +dependencies are complete. + +Set internal status `plan_complete` when no incomplete tasks remain. + +Set internal status `blocked` when incomplete tasks remain but none can currently be +executed. + +Review at most one task per invocation. + +### 3. Inspect relevant context + +Start with the task and the files it directly references. + +Inspect only what is needed to understand: + +- Existing behavior. +- Applicable repository conventions. +- Architectural boundaries. +- Relevant tests. +- Available verification commands. +- Decisions or specifications connected to the task. + +Load root context only when the task affects repository-wide behavior, +architecture, shared terminology, or cross-domain interfaces. + +Do not explore the entire repository by default. + +### 4. Determine readiness + +A task is `ready` when: + +- Its goal is clear. +- Its scope is sufficiently bounded. +- Its dependencies are complete. +- Its done checks are observable. +- A credible verification method exists. +- No unresolved decision would materially change the implementation. + +Use repository conventions for ordinary local choices. + +Do not block on: + +- Naming inferable from surrounding code. +- Established formatting or style. +- Reversible local implementation details. +- Details that do not change observable behavior or scope. + +Record these choices under `assumptions`. + +Set internal status `blocked` when a missing decision materially affects: + +- User-visible behavior. +- Public interfaces. +- Architecture or ownership boundaries. +- Data shape or persistence. +- Security or privacy. +- External dependencies. +- Destructive or difficult-to-reverse behavior. +- The evidence needed to prove completion. + +### 5. Return the result + +Set exactly one internal state: + +- `ready` +- `blocked` +- `plan_complete` + +Record only the internal state. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Modify application code. +- Modify tests. +- Update the plan. +- Mark the task complete. +- Request implementation confirmation. +- Run task execution. +- Synchronize context. +- Run final validation. +- Review more than one task. + +## Completion + +The skill is complete after: + +- One plan was resolved. +- At most one task was resolved. +- One valid readiness result matching the internal readiness state described by this workflow was + returned. + +## Internal phase: Task execution phase + + +name: Task execution phase +description: > + Internal SCE workflow skill that always presents one reviewed task to the + user before editing, executes it only after approval, verifies the + task, records evidence in the plan, and returns one internal state: declined, + blocked, incomplete, or complete. Accepts a ready result from + Plan review phase. Do not select or execute another task, + synchronize durable context, run final plan validation, create commits, or + expand task scope. + + +# SCE Task Execution + +## Purpose + +Execute exactly one reviewed SCE plan task (located in `context/plans/`). + +This skill owns: + +- Showing the implementation gate at the start of every invocation. +- Receiving the user's approval or rejection, or accepting approval + pre-supplied by the invoking workflow. +- Implementing one approved task. +- Running task-level verification. +- Updating that task and its evidence in the plan. +- Recording one terminal internal state. + +Use the gate defined in: + +`references/output.md` + +Return a final result matching: + +the internal execution state described by this workflow + +## Input + +The invoking workflow provides: + +- The complete `ready` result from the **Plan review phase**. +- An optional `approve` flag. + +The `approve` flag means the user pre-approved this task when invoking the +workflow. It suppresses the approval question and the wait. It never suppresses +the gate. Only the invoking workflow may set it, and only from an explicit +user-supplied approval token. Never infer it. + +The readiness result must identify: + +- One resolved plan. +- Exactly one incomplete task. +- The task goal and scope boundaries. +- Done checks. +- Verification expectations. +- Relevant files and context. +- Review assumptions. + +If required handoff information is absent or stale, still show the gate using +what is known, clearly identify the handoff problem, and do not edit files. +After the user responds, set internal status `blocked`. + +## Workflow + +### 1. Validate the handoff without editing + +Confirm that: + +- The readiness status is `ready`. +- Exactly one task is present. +- The plan file exists. +- The selected task is still incomplete. +- The task has not materially changed since review. +- Declared dependencies remain complete. + +Do not reconstruct missing material requirements. + +### 2. Always show the implementation gate + +At the start of the skill, before any file modification, present the task using +`references/output.md`. + +The gate must be shown even when: + +- The task appears straightforward. +- The invoking workflow believes approval was already implied. +- The handoff is stale or incomplete. +- The user is likely to approve. + +When the `approve` flag is absent, end the gate with exactly one approval +question: + +`Continue with implementation now? (yes/no)` + +Stop and wait for the user's answer. Do not return internal state, and make no file +modifications, until the user has answered. + +When the `approve` flag is supplied, show the gate as a summary, omit the +approval question, do not wait, and continue at *Prepare the implementation*. + +### 3. Handle the user's decision + +Skip this step when the `approve` flag was supplied. + +When the user rejects or cancels, do not modify files and set internal status `declined`. + +When the user does not clearly approve, do not modify files. Ask the same +approval question once more only when the response is genuinely ambiguous. +Otherwise set internal status `blocked`. + +When the user approves, continue with implementation. + +Treat constraints supplied with approval as part of the approved task boundary. +If those constraints materially contradict the reviewed task, set internal status `blocked` +before editing. + +### 4. Prepare the implementation + +Before editing: + +- Read the relevant files supplied by plan review. +- Inspect nearby code and tests when needed. +- Identify the smallest coherent change satisfying the task. +- Follow surrounding naming, structure, error handling, and test style. +- Preserve unrelated behavior. + +Do not create a second plan. + +Do not broaden the reviewed task. + +### 5. Implement one task + +Make the minimum coherent changes required to satisfy the task goal and done +checks. + +Use judgment for ordinary, reversible local implementation choices. + +Stop when implementation requires: + +- Material scope expansion. +- A new external dependency not authorized by the task. +- A public-interface decision not established by the plan. +- A destructive or difficult-to-reverse operation. +- An unresolved security, privacy, or data decision. +- Contradicting the reviewed task or repository architecture. + +When stopped, preserve completed in-scope work unless retaining it would leave +the repository unsafe or invalid. + +### 6. Verify the task + +Run the narrowest authoritative checks that demonstrate the done checks. + +Start with verification supplied by the readiness result. Add nearby or directly +relevant checks only when needed. + +Verification may include: + +- Targeted tests. +- Type checking for affected code. +- Linting affected files. +- Formatting checks. +- A focused build or compile step. +- Direct behavioral inspection when no automated check exists. + +Do not run final plan validation unless the task itself explicitly requires it. + +When a check fails: + +- Determine whether the task caused the failure. +- Fix it when the correction remains in scope. +- Rerun the relevant check. +- Set internal status `incomplete` when a done check remains unsatisfied, or `blocked` when + completing it requires an unapproved decision or scope expansion. + +Never report a check as passed unless it ran successfully. + +### 7. Update the plan + +Only after successful implementation and task-level verification: + +- Mark only the selected task complete. +- Record concise implementation evidence. +- Record verification commands and outcomes. +- Record material deviations or approved assumptions. +- Preserve the plan's existing structure and terminology. + +Do not mark the task complete when returning `declined`, `blocked`, or +`incomplete`. + +### 8. Determine the terminal status + +Set internal status `complete` when the task was implemented, verified, and marked complete +in the plan with evidence. + +Set internal status `incomplete` when in-scope work was completed but one or more done checks +remain unsatisfied. + +Set internal status `declined` when the user rejected implementation. + +Set internal status `blocked` for every other non-successful outcome, including: + +- Missing approval. +- Stale or invalid handoff. +- Material blocker. +- A verification failure that cannot be resolved in scope. + +Use a blocker category defined by the internal execution state described by this workflow. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +### 9. Return internal state + +After the skill reaches a terminal state, set exactly one internal state +matching the internal execution state described by this workflow. + +Record only the internal state. Do not add explanatory prose before or after it. + +## Boundaries + +Do not: + +- Edit before approval, whether explicit or pre-supplied. +- Execute more than one task. +- Select or execute the next task. +- Skip the implementation gate. +- Ask for multiple approval gates for the same unchanged task. +- Expand scope without authorization. +- Synchronize durable context. +- Run final plan validation. +- Determine whether the plan is complete. +- Create a Git commit. +- Push changes. +- Modify unrelated files. +- Claim verification that was not performed. + +## Completion + +The skill is complete after: + +- The implementation gate was shown. +- The user approved or rejected the task, or approval was pre-supplied. +- At most one task was executed. +- One valid terminal internal state matching the internal execution state described by this workflow + was returned. + +## Internal phase: Task context synchronization phase + + +name: Task context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful status: complete result + from Task execution phase, reconciles the completed implementation with durable + repository context, and returns a Markdown synchronization report. Run only + after one task has been implemented and verified successfully. Do not implement + application code, change plan state, determine whether the plan is complete, + run final validation, or select another task. + + +# SCE Task Context Sync + +## Purpose + +Reconcile one completed task with the repository's durable context and return a +Markdown report. + +This skill owns: + +- Validating the execution handoff. +- Confirming the context root exists. +- Discovering the context affected by one completed task. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +## Input + +The invoking workflow provides: + +- The complete result returned by the **Task execution phase**. + +The execution result must have: + +```text +status: complete +``` + +Treat the execution result as the authoritative handoff for: + +- The resolved plan and completed task. +- Files changed by implementation. +- Implementation summary. +- Verification evidence. +- Done-check evidence. +- Reported context impact. + +This skill must not be run for `declined`, `blocked`, or `incomplete` +execution results. + +Do not reconstruct a missing execution result from conversation history. + +## Workflow + +### 1. Validate the execution handoff + +Confirm that: + +- `status` is exactly `complete`. +- A `plan` object with a `path` is present. +- Exactly one completed task is identified. +- Changed files and an implementation summary are present. +- Verification evidence is present. +- Done-check evidence is present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that the task itself is complete and recorded in the plan, and that +synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the execution result: + +- `context_impact.classification` +- `context_impact.affected_areas` +- Changed files. +- Implementation summary. +- Done-check evidence. + +Then inspect existing repository context in this order when present: + +1. `context/context-map.md` +2. Context files for the affected domain or subsystem +3. `context/overview.md` +4. `context/architecture.md` +5. `context/glossary.md` +6. `context/patterns.md` +7. Operational, product, or decision records directly related to the change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +completed implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in task evidence. +- Speculation or future work not established by the completed implementation. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass. + +- `none`: Make no edits beyond any correction the root pass turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +A change is `root` when it introduces cross-cutting behavior, repository-wide +policy or contracts, an architecture or ownership boundary, or a change to +canonical terminology. A change confined to one feature or domain, with no +repository-wide behavior, architecture, or terminology impact, is `domain` or +`local`: capture its detail in domain files and leave the root files unedited. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the implementation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the completed implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the execution result verbatim into context files. +- Do not change application code, tests, or plan state. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the completed task implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the task implemented a feature no context file describes, add that +description. A feature that fits no existing domain file gets a new focused +file; do not defer it to a later task. Prefer a small, precise domain file over +overloading `overview.md` with detail. + +This is the one case where documentation is warranted by the change itself +rather than by a gap in durable knowledge. It is not license to narrate the +diff: describe what the feature is and how it behaves, not what was edited. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the task introduced. +New terminology is durable knowledge whatever the classification is: a `domain` +change that names a new concept still earns its glossary entry. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the completed implementation. +- No edited statement contradicts the code, plan, or execution evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Each feature implemented by the task has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not run full application or plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +Do not determine whether the plan is complete. The invoking `/next-task` +workflow owns that decision after context synchronization. + +## Boundaries + +Do not: + +- Accept an execution result whose status is not `complete`. +- Implement or modify application code. +- Modify tests. +- Change task completion status or plan evidence. +- Determine whether the plan is complete. +- Select or execute another task. +- Run full-plan validation. +- Mark the plan validated, closed, or archived. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return an execution-style internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + + + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.pi/skills/sce-task-context-sync/references/sync-report.md b/.pi/skills/sce-next-task/references/output.md similarity index 50% rename from .pi/skills/sce-task-context-sync/references/sync-report.md rename to .pi/skills/sce-next-task/references/output.md index 581177da..791f8f21 100644 --- a/.pi/skills/sce-task-context-sync/references/sync-report.md +++ b/.pi/skills/sce-next-task/references/output.md @@ -1,3 +1,144 @@ +# Next-task output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Review blocked + +Present the selected task, then each issue's problem, impact, and required +decision. If plan resolution is ambiguous, list candidate paths and +`/next-task {candidate-path}`. State whether another task remains executable. + +## Plan already complete + +```markdown +------------------------------------- + +# Implementation tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +## Declined + +```markdown +You have declined to proceed with this task +``` + +## Execution blocked or incomplete + +For `blocked`, present the blocker, work completed before it, and the required +decision or action. For `incomplete`, present completed work, verification +evidence, remaining work, and the reason it remains incomplete. + +## Context synchronization blocked + +State that task `{completed-task-id}` was implemented, verified, and recorded; +report the contradiction or synchronization failure, preserved edits, required +action, and retry condition. State that durable context is out of date and must +be synchronized before continuing. + +## More tasks remain + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +{completed-tasks} of {total-tasks} tasks complete. + +Next up: + +{next-task-id} — {next-task-title} + +`/next-task {plan-path} {next-task-id}` +``` + +## All tasks complete + +```markdown +------------------------------------- + +# Task {completed-task-id} completed. + +All tasks are complete. + +Run the final validation: + +`/validate {plan-path}` +``` + +# Implementation gate + +Always show this gate at the start of the **Task execution phase**, before editing any +file. + +The gate is user-facing prose. It is never serialized into a YAML result. This +file is the only authority for the gate's content and order. + +## Format + +# `{task.id} - {task.title} - {plan.name}` + +## Goal + +{task.goal} + +## In scope + +- {task.in_scope} + +## Out of scope + +- {task.out_of_scope} + +## Done when + +- {task.done_checks} + +## Expected changes + +- List confirmed files or areas expected to change. +- Label uncertain entries as likely rather than confirmed. + +## Approach + +Describe the smallest coherent implementation approach in 2–5 steps. + +## Assumptions + +- Include material assumptions returned by plan review. +- Omit this section when there are no assumptions. + +## Risks or trade-offs + +- Include only risks relevant to approving this task. +- Omit this section when there are no meaningful risks. + +## Verification + +- {task.verification} + +When the `approve` flag is absent, end with exactly: + +`Continue with implementation now? (yes/no)` + +When the `approve` flag is supplied, omit the question and end after +**Verification**. + +## Rules + +- Show the gate exactly once for an unchanged task. +- Do not modify files before approval. +- Do not add requirements absent from the reviewed task. +- Do not present multiple competing approaches unless a material decision is + required. +- Do not emit YAML while waiting for the user's answer. Stop after the gate and + wait. +- If the handoff is stale or incomplete, show the known task information and + identify the problem under **Risks or trade-offs**. + # Context Sync Report Return only one completed Markdown report using the applicable variant below. diff --git a/.pi/skills/sce-plan-authoring/SKILL.md b/.pi/skills/sce-plan-authoring/SKILL.md deleted file mode 100644 index 946e686b..00000000 --- a/.pi/skills/sce-plan-authoring/SKILL.md +++ /dev/null @@ -1,289 +0,0 @@ ---- -name: sce-plan-authoring -description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. ---- - -# SCE Plan Authoring - -## Purpose - -Turn exactly one change request into `context/plans/{plan_name}.md` without -inventing material requirements. - -This skill owns: - -- Resolving whether the request targets a new or an existing plan. -- Judging whether the change is worth making, and recording the doubt when it - is not clear that it is. -- Deciding whether the request can be planned safely. -- Normalizing the change summary, acceptance criteria, constraints, and - non-goals. -- Slicing the work into atomic implementation tasks. -- Writing the plan file. -- Returning one structured authoring result. - -Use the document format defined in: - -`references/plan-template.md` - -Return a result matching: - -`references/authoring-contract.yaml` - -The invoking workflow renders that result as the summary defined in: - -`references/plan-summary.md` - -## Input - -The invoking workflow provides: - -- One change request, in free-form prose. -- The `loaded` context brief from `sce-context-load`. - -The change request may name a plan, describe a change to an existing plan, or -describe entirely new work. Resolving which applies is this skill's -responsibility. - -The context brief is the durable memory this plan starts from. Treat its -`key_facts` as recorded current state, its `gaps` as areas with no durable -context, and its `drift` as context the code has already outrun. - -When no brief is supplied, load the context named by the change request before -authoring, and follow the selection discipline in *Inspect relevant context*. - -Answers the user gave to earlier clarification questions arrive as part of the -change request. Incorporate them into the plan. - -A revision of a plan authored earlier in the session also arrives as the change -request, and it is usually terse: a task boundary the user disagrees with, an -ordering they want changed, work they want added or dropped. Read it against the -existing plan, which supplies the scope, criteria, and terminology it omits. -Terseness is not ambiguity. Do not return `needs_clarification` for detail the -plan already carries; ask only when the revision itself is genuinely undecidable. - -## Workflow - -### 1. Resolve the plan target - -Determine whether the request targets a new plan or an existing plan in -`context/plans/`. - -When it targets an existing plan, read that plan before authoring. Preserve its -completed tasks, their recorded evidence, its structure, and its terminology. - -When multiple existing plans match and none can be selected safely, return -`blocked` with the matching candidates. - -When the request targets a new plan, derive `plan_name` as a short kebab-case -slug of the change, and confirm it does not collide with an existing plan. - -Resolve exactly one plan target per invocation. - -### 2. Challenge the change - -Before planning how to build the change, work out whether it is worth building. -A plan is a commitment of someone's time; authoring one for work that should not -happen is worse than authoring none. - -Interrogate the request: - -- What breaks, or stays broken, if this is never built? If the answer is - nothing concrete, say so. -- What problem is it actually solving, as opposed to what it proposes to do? A - request that names only a solution has not stated a problem. -- Does the repository already do this, or most of it? The brief's `key_facts` - are the first place to check. -- Is there a materially smaller version that gets most of the value? Name it. -- What does this cost beyond the tasks: new dependency, new concept in the - glossary, a boundary crossed, a surface that now needs maintaining forever? -- Does the stated justification survive contact with the code, or does the code - show the premise is already false? - -Doubt that survives this is not an implementation detail to be tidied away. It -belongs in the plan's `Open questions` and in `open_questions`, in the plain -words you would use to a colleague. "Is this worth doing at all, given X?" is a -legitimate open question. So is "this looks like it duplicates Y". - -Weigh honestly in both directions. A request that is obviously worth building -gets no manufactured doubt: inventing questions to look rigorous is its own -failure, and it teaches the user to ignore the section. Most changes are fine. -Say nothing when there is nothing to say. - -Keep going regardless. Skepticism shapes the plan and the open questions; it -does not withhold the plan. The only value judgment that stops authoring is -`no_actionable_work`, when the change is already implemented. - -### 3. Run the clarification gate - -Before writing or updating any plan file, check the request for critical -unresolved detail: - -- Scope boundaries and out-of-scope items. -- Acceptance criteria and the checks that prove them. -- Constraints and non-goals. -- Dependency choices, including new libraries or services, versions, and the - integration approach. -- Domain ambiguity, including unclear business rules, terminology, or ownership. -- Architecture concerns, including patterns, interfaces, data flow, migration - strategy, and risk tradeoffs. -- Task ordering assumptions and prerequisite sequencing. - -Return `needs_clarification` with one to three targeted questions when any of -these would materially change the plan. Write no plan file in that case. - -Use repository conventions for ordinary local choices. Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change scope, acceptance criteria, or task ordering. - -Record those choices under `assumptions`. - -Do not silently invent missing requirements. When the user has explicitly -allowed assumptions, record them in the plan's `Assumptions` section instead of -asking. - -A justification that does not survive inspection is itself a critical unresolved -detail. "For consistency", "to make it cleaner", "we will need it later" name no -outcome and prove nothing; ask what the change is actually for before planning -around it. Do not treat confident phrasing as evidence. - -### 4. Inspect relevant context - -Start from the context brief. Read code only where the brief leaves the change -underspecified: - -- Existing behavior the change affects. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests and available verification commands. -- Decisions or specifications connected to the change. - -Where the brief reports `drift`, the code is the source of truth. Plan against -the code, and schedule the context repair as part of the change when it falls -inside scope. - -Where the brief reports `gaps`, the plan may need to establish durable context -the repository does not yet have. - -Do not explore the entire repository by default. - -### 5. Author the acceptance criteria - -State how the finished plan is proven, before slicing tasks. - -Each criterion describes observable behavior of the finished system and names -the check that proves it. Record repository-wide checks once under -`Full validation`, and the durable context the change must be reflected in -under `Context sync`. - -`/validate` runs this section after the last task completes. It is the only -place a plan says how it is validated. - -### 6. Author the task stack - -Slice the work into sequential tasks `T01..T0N` using the task format and the -atomic slicing contract in `references/plan-template.md`. - -Every executable task must be completable and landable as one coherent commit. -Split any task that would require multiple independent commits. Convert broad -wrappers such as `polish` or `finalize` into specific outcomes with concrete -acceptance checks. - -Order tasks so each one's declared dependencies precede it. - -The last task is an ordinary implementation task. Do not author a trailing -validation-and-cleanup task, or any task whose only purpose is running the full -check suite, verifying durable context, or removing scaffolding. - -Confirm every acceptance criterion is satisfied by at least one task. When one -is not, the task stack is incomplete. - -A finished stack always leaves at least one incomplete task, so the invoking -workflow can always hand off to `/next-task`. When the request resolves to a -plan but produces no incomplete task, because the change is already implemented -or already covered by completed tasks, return `blocked` with category -`no_actionable_work` instead of writing the plan. - -### 7. Write the plan - -Write `context/plans/{plan_name}.md` using `references/plan-template.md`. - -When updating an existing plan, keep completed tasks and their evidence intact, -and append or renumber new tasks without disturbing recorded history. - -### 8. Return the result - -Return exactly one structured result: - -- `plan_ready` -- `needs_clarification` -- `blocked` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Tone - -Every question and open question this skill writes is read by the user. Write -them the way a senior engineer talks in review: direct, specific, and unbothered -by the possibility of being unwelcome. - -- Ask about the thing that actually worries you, not a safer neighbouring thing. - A question you would not bother asking a colleague is not worth the user's - attention either. -- State a doubt as a doubt. "I do not think this is worth the two tasks it - costs, because X" is useful. "It may be worth considering whether this aligns - with broader goals" is noise. -- Name the alternative you have in mind. A challenge with no proposal behind it - is just friction. -- Do not open with praise, do not close with reassurance, and do not apologize - for asking. Do not pad a doubt with hedges to make it land more gently. -- Be persistent, not repetitive. Ask once, plainly, and let it stand; do not - restate the same doubt in three shapes to give it more weight. -- Being disagreeable is not the goal. Being easy to agree with is the failure - mode. A plan the user waves through without reading has cost them nothing and - bought them nothing. - -When the user overrules a doubt, record it and move on. Do not relitigate a -decision the user has made, and do not smuggle the objection back in as a -constraint, a non-goal, or a task. - -## Boundaries - -Do not: - -- Ask the user questions directly. Return `needs_clarification` and let the - invoking workflow present the questions. -- Answer your own clarification questions. -- Write a plan file when returning `needs_clarification` or `blocked`. -- Implement any task in the plan. -- Modify application code or tests. -- Modify any file under `context/` outside `context/plans/`. Plan the context - repair instead of performing it. -- Mark any task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Author a validation, cleanup, or context-verification task. `/validate` owns - that phase. -- Return `plan_ready` for a plan with no incomplete task. -- Create a Git commit. -- Author more than one plan. - -## Completion - -The skill is complete after: - -- One plan target was resolved, or resolution failed and was reported. -- The plan file was written, or no file was written because the result is - `needs_clarification` or `blocked`. -- One valid result matching `references/authoring-contract.yaml` was returned. diff --git a/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml b/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml deleted file mode 100644 index afd4ce0d..00000000 --- a/.pi/skills/sce-plan-authoring/references/authoring-contract.yaml +++ /dev/null @@ -1,256 +0,0 @@ -version: 1 -name: sce-plan-authoring-result - -description: > - Output contract for sce-plan-authoring. The skill returns exactly one YAML - document representing plan_ready, needs_clarification, or blocked. - -output_rules: - - Return exactly one result variant. - - The top-level status must be plan_ready, needs_clarification, or blocked. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.name as the plan file's base name without its extension, and - plan.path as the exact written path, so emitted commands are runnable. - - Report plan.completed_tasks and plan.total_tasks as they stand in the - written plan. - - Write a plan file only for plan_ready. needs_clarification and blocked mean - nothing was written or modified. - - Do not ask the user questions directly. Clarification questions belong in - the needs_clarification variant. - - Do not report a trailing validation, cleanup, or context-verification task. - The written plan states how it is validated in its acceptance criteria, and - /validate runs that phase after the last task. - - plan_ready always leaves at least one incomplete task and always names - next_task. A request that would add no incomplete task is not plan_ready; - return blocked with category no_actionable_work. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - plan_ready: - meaning: > - One plan was written or updated and its task stack is ready to enter the - review-and-implementation workflow. - - required_fields: - - status - - plan - - summary - - tasks - - next_task - - assumptions - - optional_fields: - - open_questions - - field_rules: - - Report summary as one or two sentences condensing the plan's Change - summary section: what changes, where, and why. It is what the user reads - to decide whether the plan understood the request at all. - - Write summary as the resulting behavior, not as a list of the tasks. The - task list is already carried by tasks. - - Set plan.action to created for a new plan file, or updated for an - existing one. - - List tasks in plan order, including tasks already complete on an - updated plan. - - Report next_task as the first unchecked task in plan order. It is always - present, because plan_ready requires at least one incomplete task. - - Include open_questions only for non-blocking questions recorded in the - plan. A blocking question requires needs_clarification instead. - - Record unresolved doubt about the change's value here: whether it is - worth building, whether it duplicates existing behavior, whether a - smaller version would do. Such a doubt does not block authoring, and - the invoking workflow surfaces it before handing off. - - Omit open_questions when there is nothing genuinely unresolved. Do not - manufacture a question to appear rigorous. An empty section is the - expected outcome for a well-specified change. - - shape: - status: plan_ready - - plan: - path: string - name: string - action: created | updated - completed_tasks: integer - total_tasks: integer - - summary: string - - tasks: - - id: string - title: string - status: todo | done - - next_task: - id: string - title: string - - assumptions: - - string - - open_questions: - - string - - example: - status: plan_ready - - plan: - path: context/plans/authentication.md - name: authentication - action: created - completed_tasks: 0 - total_tasks: 3 - - summary: > - Adds password authentication to the HTTP API: a login endpoint that - verifies credentials and issues a token, and refresh-token rotation - behind it. Registration and password reset are untouched. - - tasks: - - id: T01 - title: Add credential verifier - status: todo - - id: T02 - title: Add login endpoint - status: todo - - id: T03 - title: Add refresh-token rotation - status: todo - - next_task: - id: T01 - title: Add credential verifier - - assumptions: - - Use the error-response convention established by existing handlers. - - open_questions: - - T03 adds refresh-token rotation, but nothing in the request says a token is ever revoked. Is rotation worth its own task here, or is it being planned because it usually comes with auth? - - needs_clarification: - meaning: > - A critical detail is unresolved, so no plan was written. The invoking - workflow must present the questions and stop. - - required_fields: - - status - - questions - - optional_fields: - - plan_target - - field_rules: - - Include one to three questions. Each must be specific, answerable, and - blocking. - - Include plan_target when the request clearly resolved to one new or - existing plan before the gate stopped authoring. - - Do not include a plan path unless that plan already exists on disk. - - shape: - status: needs_clarification - - plan_target: - name: string - action: created | updated - path: string - - questions: - - id: string - category: scope | success_criteria | constraints | dependency | domain | architecture | sequencing - question: string - why_blocking: string - - example: - status: needs_clarification - - plan_target: - name: authentication - action: created - - questions: - - id: Q01 - category: architecture - - question: > - Should the new endpoint authenticate via the existing JWT - middleware, or is a separate auth flow in scope? - - why_blocking: > - The answer changes the task stack, the affected modules, and the - security boundary. - - - id: Q02 - category: scope - - question: > - Is database migration rollback a hard requirement, or is - forward-only acceptable for this change? - - why_blocking: > - Rollback support is a separate atomic task with its own - verification. - - blocked: - meaning: > - The plan target could not be resolved, or the request cannot be planned - safely. No plan was written. - - required_fields: - - status - - issues - - optional_fields: - - candidates - - field_rules: - - Include candidates only when the request matched more than one existing - plan and none could be selected safely. - - Use needs_clarification, not blocked, when the request is plannable once - the user answers a question. - - Use no_actionable_work when the request resolved to a plan but produced - no incomplete task, for example because the requested change is already - implemented or already covered by completed tasks. - - shape: - status: blocked - - candidates: - - string - - issues: - - id: string - category: ambiguous_plan_target | missing_request | conflicting_request | no_actionable_work | other - problem: string - impact: string - decision_required: string - - example: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguous_plan_target - - problem: > - The change request matches more than one existing plan and none can - be selected safely. - - impact: > - Updating the wrong plan would reorder tasks unrelated to the - request. - - decision_required: > - Name the exact plan path to update, or state that a new plan should - be created. diff --git a/.pi/skills/sce-plan-authoring/references/plan-template.md b/.pi/skills/sce-plan-authoring/references/plan-template.md deleted file mode 100644 index a13407fc..00000000 --- a/.pi/skills/sce-plan-authoring/references/plan-template.md +++ /dev/null @@ -1,170 +0,0 @@ -# SCE Plan Template - -The document format for `context/plans/{plan_name}.md`. This is the plan file -written to disk, not the result returned to the invoking workflow. - -Copy the template below and fill every `{placeholder}`. Omit optional sections -entirely rather than writing them empty. - ---- - -## Template - -```markdown -# Plan: {plan-name} - -## Change summary - -{One or two paragraphs: what changes, where, and why. State whether this -extends existing behavior, replaces it, or preserves work already in progress.} - -## Acceptance criteria - -How this plan is proven complete. Each criterion is observable and names the -check that proves it. `/validate` runs these checks; no task in the stack -performs final validation. - -- [ ] AC1: {observable outcome, stated as behavior rather than as work done} - - Validate: `{command, assertion, or inspection that proves AC1}` -- [ ] AC2: {observable outcome} - - Validate: `{command, assertion, or inspection that proves AC2}` - -### Full validation - -Repository-wide checks `/validate` runs after the last task, regardless of -which criterion they map to. - -- `{full check suite command}` -- `{generated-output or parity check command, when applicable}` - -### Context sync - -- {Durable context files that must describe the change once implemented.} - -## Constraints and non-goals - -- **In scope:** {files, modules, and surfaces this plan may touch} -- **Out of scope:** {adjacent work explicitly excluded} -- **Constraints:** {dependencies, conventions, compatibility, or policy limits} -- **Non-goal:** {tempting generalization this plan deliberately avoids} - -## Assumptions - -{Include only when the user allowed assumptions, or ordinary local choices were -recorded. Remove the section otherwise.} - -- {Assumption, and the convention or decision record it rests on.} - -## Task stack - -- [ ] T01: `{single intent title}` (status:todo) - - Task ID: T01 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: {task IDs, or none} - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -- [ ] T02: `{single intent title}` (status:todo) - - Task ID: T02 - - Goal: {one outcome} - - Boundaries (in/out of scope): In — {tight scope}. Out — {excluded work}. - - Dependencies: T01 - - Done when: {clear acceptance for one coherent change} - - Verification notes (commands or checks): {targeted checks for this change} - -## Open questions - -{Non-blocking questions only. A question that would change scope, success -criteria, or task ordering blocks authoring instead. Write `None.` with a short -justification when nothing remains.} - -{Unresolved doubt about the change's value belongs here — whether it is worth -building, whether it duplicates behavior the repository already has, whether a -smaller version would do. State it plainly and name the alternative. Do not -invent one: `None.` is the expected answer for a well-specified change.} -``` - ---- - -## Filled-in task example - -```markdown -- [ ] T02: `Add /auth/refresh endpoint` (status:todo) - - Task ID: T02 - - Goal: Implement a POST `/auth/refresh` endpoint that exchanges a valid refresh token for a new access token. - - Boundaries (in/out of scope): In — route handler, token validation logic, response schema. Out — refresh token rotation policy (covered in T03), client-side storage changes. - - Dependencies: T01 - - Done when: `POST /auth/refresh` returns a signed JWT on valid input and 401 on expired or invalid token; targeted tests pass; OpenAPI spec updated. - - Verification notes (commands or checks): `pnpm test src/auth/refresh.test.ts`; `curl -X POST localhost:3000/auth/refresh -d '{"token":"..."}' -w "%{http_code}"`. -``` - -## Acceptance criteria rules - -- Acceptance criteria describe the finished system, not the work. Prefer "the - endpoint returns 401 on an expired token" over "add expiry handling". -- Every criterion carries a `Validate:` line. A criterion nobody can check is - not an acceptance criterion. -- Prefer a runnable command. Fall back to a named inspection only when no - automated check exists, and say exactly what to look at. -- List repository-wide checks once under `Full validation` instead of repeating - them per criterion. -- Task-level `Verification notes` prove one task. Acceptance criteria prove the - plan. Keep them distinct: a task's checks are narrow and local, a criterion's - check is end-to-end. -- The union of the acceptance criteria must cover every success signal in the - change request. If a criterion has no task that could satisfy it, the task - stack is incomplete. - -## Task rules - -- Every task is a checkbox line so progress stays machine-readable: - `- [ ] T01: {title} (status:todo)`. -- Author each executable task as one atomic commit unit by default. -- Scope every task so one contributor can complete it and land it as one - coherent commit without bundling unrelated changes. -- Split any candidate task that would require multiple independent commits, for - example a refactor plus a behavior change plus documentation. -- Keep broad wrappers such as `polish`, `finalize`, or `misc updates` out of - executable tasks. Convert them into specific outcomes with concrete - acceptance checks. -- Order tasks so each one's declared dependencies precede it. - -## No validation task - -- The last task in the stack is an ordinary implementation task. Do not author a - trailing "validation and cleanup" task. -- Final validation, cleanup, and success-criteria verification are run by - `/validate` from the `Acceptance criteria` section after the last task - completes. -- Do not author a task whose only purpose is running the full check suite, - verifying durable context, or removing scaffolding. -- A task may still create or update durable context when that context is part of - the change itself. - -## Completion records - -`sce-task-execution` appends evidence to a task when it completes, and flips the -checkbox and status: - -```markdown -- [x] T01: `{title}` (status:done) - - {authored fields, unchanged} - - Completed: {YYYY-MM-DD} - - Files changed: {paths} - - Evidence: {commands run and their outcomes} - - Notes: {material deviations or approved assumptions} -``` - -`/validate` appends a `## Validation Report` section at the end of the plan. -Do not author either while planning. - -## Updating an existing plan - -- Preserve completed tasks, their `(status:done)` markers, and their recorded - evidence verbatim. -- Preserve the plan's existing structure and terminology. -- Append new tasks after the existing stack. Renumber only when added work must - run earlier, and never renumber a completed task. -- Add acceptance criteria for newly planned outcomes rather than rewriting - criteria already satisfied. diff --git a/.pi/skills/sce-plan-context-sync/SKILL.md b/.pi/skills/sce-plan-context-sync/SKILL.md deleted file mode 100644 index 04958458..00000000 --- a/.pi/skills/sce-plan-context-sync/SKILL.md +++ /dev/null @@ -1,308 +0,0 @@ ---- -name: sce-plan-context-sync -description: > - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - repository context, and returns a Markdown synchronization report. Invoke only - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. ---- - -# SCE Plan Context Sync - -## Purpose - -Reconcile one fully validated plan with the repository's durable context and -return a Markdown report. - -This skill owns: - -- Validating the validation handoff. -- Confirming the context root exists. -- Discovering the context required by the finished plan. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -Task-level context sync may already have run after individual tasks. This skill -is the plan-level final pass: it starts from the plan's `Context sync` -requirements and the validated implementation, and closes gaps that remain. - -## Input - -The invoking workflow provides: - -- The complete Markdown result returned by `sce-validation`. - -The validation result must report: - -```markdown -**Status:** validated -**Plan:** {plan path} -``` - -Treat that Markdown as the authoritative handoff for: - -- The resolved plan path. -- Validation commands and outcomes. -- Acceptance-criteria evidence. -- Scaffolding removals. -- Reported context impact, required context paths, and affected areas. - -This skill must not be invoked for `failed` or `blocked` validation results. -Those are not success states. Same rule as `sce-task-context-sync`: context sync -runs only after a successful prior phase. - -Do not reconstruct a missing validation result from conversation history. - -## Workflow - -### 1. Validate the validation handoff - -Confirm that: - -- `Status:` is exactly `validated`. -- `Plan:` names an existing plan path. -- Acceptance-criteria evidence is present and every criterion is met. -- Commands run are present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that validation itself succeeded and is recorded in the plan, and that -plan context synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the validated Markdown result: - -- **Context impact** classification, required context, and affected areas. -- Acceptance-criteria evidence. -- Commands run. - -Then read the plan's `Context sync` section and inspect existing repository -context in this order when present: - -1. Paths named by the plan's `Context sync` section -2. `context/context-map.md` -3. Context files for the affected domain or subsystem -4. `context/overview.md` -5. `context/architecture.md` -6. `context/glossary.md` -7. `context/patterns.md` -8. Operational, product, or decision records directly related to the finished - change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -finished implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -#### Plan context requirements - -Every path or statement listed under the plan's `Context sync` section must be -accounted for in the report as already accurate or updated. A requirement the -finished code still does not satisfy is a blocker, not a note. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -finished implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in validation evidence. -- Speculation or future work not established by the finished plan. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass or the plan's Context -sync requirements. - -- `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the validation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the finished implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the validation result verbatim into context files. -- Do not change application code, tests, or plan validation evidence. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the finished plan implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the plan delivered a feature no context file describes, add that -description. Prefer a small, precise domain file over overloading -`overview.md` with detail. - -This is not license to narrate the diff: describe what the feature is and how -it behaves, not what was edited during the plan. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the plan introduced. -New terminology is durable knowledge whatever the classification is. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the finished implementation. -- No edited statement contradicts the code, plan, or validation evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Every plan `Context sync` requirement is met. -- Each feature implemented by the plan has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not rerun full-plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Accept a validation result whose status is not `validated`. -- Accept `failed` or `blocked` validation results. -- Implement or modify application code. -- Modify tests. -- Change task completion status, acceptance-criteria marks, or the Validation - Report. -- Rerun full-plan validation. -- Select or execute an implementation task. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return YAML. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Plan context requirements were checked. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.pi/skills/sce-plan-context-sync/references/sync-report.md b/.pi/skills/sce-plan-context-sync/references/sync-report.md deleted file mode 100644 index 21ff3e3a..00000000 --- a/.pi/skills/sce-plan-context-sync/references/sync-report.md +++ /dev/null @@ -1,142 +0,0 @@ -# Plan Context Sync Report - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `synced` -- `no_context_change` -- `blocked` - -The input validation status is always `validated` and does not need to be -repeated as a separate workflow state. This skill is not invoked for `failed` -or `blocked` validation results. - -## Synced variant - -# Plan Context Sync Report - -**Status:** synced -**Plan:** `{plan path}` - -## Context impact - -**Classification:** `{local | domain | root}` -**Affected areas:** `{comma-separated areas}` - -{Explain which durable behavior, architecture, terminology, operation, or -constraint required plan-level synchronization after validation.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — {met by edit | already accurate} - -## Updated context - -- `{context file}` — {concise description of the durable truth updated} - -## Root pass - -- `context/overview.md` — {verified | edited | absent} -- `context/architecture.md` — {verified | edited | absent} -- `context/glossary.md` — {verified | edited | absent} -- `context/patterns.md` — {verified | edited | absent} -- `context/context-map.md` — {verified | edited | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}` - -## Verification - -- {How the edited context was checked against the finished implementation and validation evidence.} -- {File hygiene: line counts, relative links, diagrams where structure is complex.} -- {Documentation, link, or formatting checks that were run, when applicable.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## No-context-change variant - -# Plan Context Sync Report - -**Status:** no_context_change -**Plan:** `{plan path}` - -## Context impact - -**Classification:** none - -{Explain why the finished plan introduced no durable, non-obvious repository -knowledge requiring an update, or why existing context already matched.} - -## Plan context requirements - -- `{required context path or statement from the plan}` — already accurate -- None listed by the plan. - -## Context reviewed - -- `{context file or area}` — {what was checked and why it remains accurate} - -## Root pass - -- `context/overview.md` — {verified | absent} -- `context/architecture.md` — {verified | absent} -- `context/glossary.md` — {verified | absent} -- `context/patterns.md` — {verified | absent} -- `context/context-map.md` — {verified | absent} - -## Feature existence - -- `{feature}` — `{context file that canonically describes it}`, already present. - -## Verification - -- {How existing context was compared with the finished implementation and validation evidence.} - ---- - -## Blocked variant - -# Plan Context Sync Report - -**Status:** blocked -**Plan:** `{plan path}` - -## Blocker - -**Problem:** {specific synchronization blocker} -**Impact:** {why context cannot be made authoritative safely} -**Required action:** {decision or correction required} - -## Context changes - -- {List safe context edits preserved, or state `No context files were changed.`} - -## Retry condition - -{State the concrete condition under which plan context synchronization should -run again.} - -## Report rules - -- Name exact context files when they were changed or reviewed. -- Report every file in the root pass, including any that is absent. -- Report the missing context root as `blocked`, with `sce setup - --bootstrap-context` as the required action and the existence of `context/` as - the retry condition. -- Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. -- Omit **Feature existence** only when the plan implemented no feature. -- Describe durable truth, not validation-session chronology. -- Keep evidence concise and factual. -- Do not claim implementation tasks remain open. -- Do not reopen validation checks. -- Do not recommend a next implementation task unless context cannot be repaired - without one, and then only as the required action. diff --git a/.pi/skills/sce-plan-review/SKILL.md b/.pi/skills/sce-plan-review/SKILL.md deleted file mode 100644 index 77c36481..00000000 --- a/.pi/skills/sce-plan-review/SKILL.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -name: sce-plan-review -description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. ---- - -# SCE Plan Review - -## Purpose - -Resolve exactly one task from an SCE plan (located in `context/plans/`) and -determine whether it can enter the implementation phase without inventing -material requirements. - -This skill owns: - -- Resolving one plan. -- Selecting at most one task. -- Inspecting the context needed to judge readiness. -- Determining readiness. -- Returning one structured readiness result. - -Return a result matching: - -`references/readiness-contract.yaml` - -## Input - -The invoking workflow provides: - -- A plan name or path. -- An optional task ID. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` with -the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Resolve one task - -When a task ID is supplied, select that task. - -Otherwise, select the first incomplete task in plan order whose declared -dependencies are complete. - -Return `plan_complete` when no incomplete tasks remain. - -Return `blocked` when incomplete tasks remain but none can currently be -executed. - -Review at most one task per invocation. - -### 3. Inspect relevant context - -Start with the task and the files it directly references. - -Inspect only what is needed to understand: - -- Existing behavior. -- Applicable repository conventions. -- Architectural boundaries. -- Relevant tests. -- Available verification commands. -- Decisions or specifications connected to the task. - -Load root context only when the task affects repository-wide behavior, -architecture, shared terminology, or cross-domain interfaces. - -Do not explore the entire repository by default. - -### 4. Determine readiness - -A task is `ready` when: - -- Its goal is clear. -- Its scope is sufficiently bounded. -- Its dependencies are complete. -- Its done checks are observable. -- A credible verification method exists. -- No unresolved decision would materially change the implementation. - -Use repository conventions for ordinary local choices. - -Do not block on: - -- Naming inferable from surrounding code. -- Established formatting or style. -- Reversible local implementation details. -- Details that do not change observable behavior or scope. - -Record these choices under `assumptions`. - -Return `blocked` when a missing decision materially affects: - -- User-visible behavior. -- Public interfaces. -- Architecture or ownership boundaries. -- Data shape or persistence. -- Security or privacy. -- External dependencies. -- Destructive or difficult-to-reverse behavior. -- The evidence needed to prove completion. - -### 5. Return the result - -Return exactly one structured result: - -- `ready` -- `blocked` -- `plan_complete` - -Return only the structured result. Do not add explanatory prose before or after -it. - -## Boundaries - -Do not: - -- Modify application code. -- Modify tests. -- Update the plan. -- Mark the task complete. -- Request implementation confirmation. -- Invoke task execution. -- Synchronize context. -- Run final validation. -- Review more than one task. - -## Completion - -The skill is complete after: - -- One plan was resolved. -- At most one task was resolved. -- One valid readiness result matching `references/readiness-contract.yaml` was - returned. diff --git a/.pi/skills/sce-plan-review/references/readiness-contract.yaml b/.pi/skills/sce-plan-review/references/readiness-contract.yaml deleted file mode 100644 index 4d65e94e..00000000 --- a/.pi/skills/sce-plan-review/references/readiness-contract.yaml +++ /dev/null @@ -1,246 +0,0 @@ -version: 1 -name: sce-plan-review-result - -description: > - Output contract for sce-plan-review. The skill returns exactly one YAML - document representing ready, blocked, or plan_complete. - -output_rules: - - Return exactly one result variant. - - The top-level status must be ready, blocked, or plan_complete. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields belonging to the selected variant. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Report plan.name as the plan file's base name without its extension. It is - required by the ready variant, which renders the implementation gate. - - Do not request implementation confirmation. - - Do not include implementation results. - - Do not include context synchronization results. - - Do not include final validation results. - -variants: - - ready: - meaning: > - One task has been selected and contains enough information to enter - the implementation-confirmation phase. - - required_fields: - - status - - plan - - task - - relevant_files - - relevant_context - - assumptions - - shape: - status: ready - - plan: - path: string - name: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - goal: string - - in_scope: - - string - - out_of_scope: - - string - - done_checks: - - string - - dependencies: - - id: string - status: complete - - verification: - - string - - relevant_files: - - string - - relevant_context: - - string - - assumptions: - - string - - example: - status: ready - - plan: - path: context/plans/authentication.md - name: authentication - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - goal: > - Add an endpoint that authenticates a user and returns the existing - token response type. - - in_scope: - - Add the login request handler. - - Reuse the existing credential verifier. - - Add tests for valid and invalid credentials. - - out_of_scope: - - Refresh-token support. - - Password reset. - - Changes to user registration. - - done_checks: - - Valid credentials return the existing token response type. - - Invalid credentials return the standard authentication error. - - Targeted authentication tests pass. - - dependencies: - - id: T02 - status: complete - - verification: - - npm test -- tests/auth/login.test.ts - - relevant_files: - - src/auth/credentials.ts - - src/auth/token.ts - - tests/auth/login.test.ts - - relevant_context: - - context/authentication/overview.md - - assumptions: - - Use the error-response convention established by existing authentication handlers. - - blocked: - meaning: > - A plan could not be resolved, or a task cannot safely enter implementation - because a material decision, dependency, scope boundary, or completion - condition is unresolved. - - required_fields: - - status - - issues - - optional_fields: - - plan - - task - - candidates - - executable_tasks_remaining - - field_rules: - - Include plan whenever exactly one plan was resolved. - - Include candidates only when plan resolution was ambiguous or failed. - - Include task only when one task was selected before blocking. - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - candidates: - - string - - task: - id: string - title: string - - issues: - - id: string - category: missing_decision | ambiguity | missing_acceptance_criteria | dependency | scope - problem: string - impact: string - decision_required: string - - executable_tasks_remaining: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - issues: - - id: B01 - category: missing_decision - - problem: > - The plan does not specify whether authentication uses sessions - or tokens. - - impact: > - The decision changes persistence behavior, endpoint responses, - and the security model. - - decision_required: > - Choose session-based or token-based authentication. - - executable_tasks_remaining: true - - example_plan_unresolved: - status: blocked - - candidates: - - context/plans/authentication.md - - context/plans/authentication-refresh.md - - issues: - - id: B01 - category: ambiguity - - problem: > - The supplied plan name matches more than one plan and none can be - selected safely. - - impact: > - Reviewing the wrong plan would select an unrelated task. - - decision_required: > - Name the exact plan path to review. - - plan_complete: - meaning: > - The selected plan contains no incomplete implementation tasks. - - required_fields: - - status - - plan - - shape: - status: plan_complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - example: - status: plan_complete - - plan: - path: context/plans/authentication.md - completed_tasks: 5 - total_tasks: 5 diff --git a/.pi/skills/sce-task-context-sync/SKILL.md b/.pi/skills/sce-task-context-sync/SKILL.md deleted file mode 100644 index 7af7c880..00000000 --- a/.pi/skills/sce-task-context-sync/SKILL.md +++ /dev/null @@ -1,310 +0,0 @@ ---- -name: sce-task-context-sync -description: > - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - repository context, and returns a Markdown synchronization report. Invoke only - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. ---- - -# SCE Task Context Sync - -## Purpose - -Reconcile one completed task with the repository's durable context and return a -Markdown report. - -This skill owns: - -- Validating the execution handoff. -- Confirming the context root exists. -- Discovering the context affected by one completed task. -- Deciding whether durable context changed. -- Editing and verifying the affected context files. -- Returning one Markdown synchronization report. - -Use the report format in: - -`references/sync-report.md` - -## Input - -The invoking workflow provides: - -- The complete result returned by `sce-task-execution`. - -The execution result must have: - -```yaml -status: complete -``` - -Treat the execution result as the authoritative handoff for: - -- The resolved plan and completed task. -- Files changed by implementation. -- Implementation summary. -- Verification evidence. -- Done-check evidence. -- Reported context impact. - -This skill must not be invoked for `declined`, `blocked`, or `incomplete` -execution results. - -Do not reconstruct a missing execution result from conversation history. - -## Workflow - -### 1. Validate the execution handoff - -Confirm that: - -- `status` is exactly `complete`. -- A `plan` object with a `path` is present. -- Exactly one completed task is identified. -- Changed files and an implementation summary are present. -- Verification evidence is present. -- Done-check evidence is present. -- A context-impact classification is present. - -If the handoff is missing required information or is internally contradictory, -do not modify context. Return a `blocked` Markdown report. - -### 2. Confirm the context root - -When `context/` does not exist, there is no durable memory to synchronize. -Do not create it, and do not write context files outside it. - -Return a `blocked` report whose required action is: - -`sce setup --bootstrap-context` - -State that the task itself is complete and recorded in the plan, and that -synchronization should run again once the context root exists. - -Bootstrapping is the user's action, not this skill's. - -### 3. Discover applicable context - -Start with the execution result: - -- `context_impact.classification` -- `context_impact.affected_areas` -- Changed files. -- Implementation summary. -- Done-check evidence. - -Then inspect existing repository context in this order when present: - -1. `context/context-map.md` -2. Context files for the affected domain or subsystem -3. `context/overview.md` -4. `context/architecture.md` -5. `context/glossary.md` -6. `context/patterns.md` -7. Operational, product, or decision records directly related to the change - -Use the context map and existing links to locate authoritative files. - -Do not scan or rewrite the entire `context/` tree by default. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -#### The mandatory root pass - -Every invocation verifies these five files against code truth, whatever the -reported classification is: - -- `context/overview.md` -- `context/architecture.md` -- `context/glossary.md` -- `context/patterns.md` -- `context/context-map.md` - -Verifying is not editing. A classification that warrants no root edit still -requires reading each of these and confirming it is not contradicted by the -completed implementation. A file that is absent is a gap; record it in the -report rather than creating it to satisfy the pass. - -Report each of the five as verified or edited. Never declare synchronization -done while one of them is unchecked. - -Do not create a new context file when an existing authoritative file can be -updated coherently. - -### 4. Determine whether durable context changed - -Use the reported context impact as a strong hint, then verify it against the -implementation and existing context. - -Durable context includes non-obvious repository knowledge such as: - -- User-visible or externally observable behavior. -- Architecture, boundaries, ownership, and dependency direction. -- Public interfaces, data contracts, and persistence behavior. -- Operational procedures and important failure modes. -- Security or privacy behavior. -- Shared terminology. -- Intentional limitations and meaningful design decisions. - -Do not document: - -- Details already obvious from the implementation. -- Temporary debugging information. -- A file-by-file narration of the change. -- Test output that belongs only in task evidence. -- Speculation or future work not established by the completed implementation. -- Generic engineering practices. - -Interpret impact classifications as follows. Each governs which files are -*edited*; none of them waives the mandatory root pass. - -- `none`: Make no edits beyond any correction the root pass turns up. -- `local`: Update the nearest existing authoritative context only when the new - behavior is not reliably discoverable from code. -- `domain`: Update affected domain context and the context map when its links or - summaries changed. -- `root`: Update the relevant root context and any affected domain context. - -A change is `root` when it introduces cross-cutting behavior, repository-wide -policy or contracts, an architecture or ownership boundary, or a change to -canonical terminology. A change confined to one feature or domain, with no -repository-wide behavior, architecture, or terminology impact, is `domain` or -`local`: capture its detail in domain files and leave the root files unedited. - -If the reported classification is inconsistent with the actual change, use the -verified classification and explain the difference in the report. - -### 5. Synchronize context - -Make the smallest coherent documentation change that preserves repository truth. - -When editing context: - -- Describe the resulting behavior, not the implementation session. -- Preserve repository terminology and document structure. -- Remove or correct statements contradicted by the completed implementation. -- Update cross-references when files are added, moved, renamed, or superseded. -- Keep one authoritative statement for each durable fact. -- Avoid copying the execution result verbatim into context files. -- Do not change application code, tests, or plan state. - -Create a new context file only when: - -- The knowledge is durable and non-obvious. -- No existing file owns it coherently. -- The new file has a clear place in the context map. - -#### Feature existence - -Every feature the completed task implemented must have at least one durable -canonical description discoverable from `context/`, in a domain file under -`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - -When the task implemented a feature no context file describes, add that -description. A feature that fits no existing domain file gets a new focused -file; do not defer it to a later task. Prefer a small, precise domain file over -overloading `overview.md` with detail. - -This is the one case where documentation is warranted by the change itself -rather than by a gap in durable knowledge. It is not license to narrate the -diff: describe what the feature is and how it behaves, not what was edited. - -#### Glossary - -Add a `context/glossary.md` entry for any domain language the task introduced. -New terminology is durable knowledge whatever the classification is: a `domain` -change that names a new concept still earns its glossary entry. - -#### File hygiene - -Every context file this skill writes must satisfy: - -- One topic per file. -- At most 250 lines. When an edit would push a file past 250 lines, split it - into focused files and link them rather than letting it grow. -- Relative paths in every link to another context file. -- A Mermaid diagram where structure, boundaries, or flows are complex enough - that prose alone would not carry them. -- Concrete code examples only where they clarify non-trivial behavior. - -When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a -concise pointer behind, and link the new file from `context/context-map.md`. - -### 6. Verify synchronization - -After edits, verify: - -- Every changed context file accurately reflects the completed implementation. -- No edited statement contradicts the code, plan, or execution evidence. -- Every file in the mandatory root pass was read and confirmed against code - truth, whether or not it was edited. -- Each feature implemented by the task has a durable canonical description - reachable from `context/`. -- Every changed file is at or below 250 lines, covers one topic, and links other - context files by relative path. -- Diagrams are present where structure, boundaries, or flows are complex. -- Links and referenced paths resolve when practical to check. -- New context files are reachable from the context map or another authoritative - index. -- Root context remains concise and delegates details to domain files. -- Unrelated context was not changed. - -Use focused documentation, link, or formatting checks when available. - -Do not run full application or plan validation. - -If synchronization cannot be completed without inventing facts or resolving a -material contradiction, preserve safe edits when appropriate and return a -`blocked` report. - -### 7. Return the Markdown report - -Return exactly one report status: - -- `synced` -- `no_context_change` -- `blocked` - -`synced` means context files were updated and verified. `no_context_change` -means existing context was checked and no edit was warranted. `blocked` means -context could not be synchronized safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -## Boundaries - -Do not: - -- Accept an execution result whose status is not `complete`. -- Implement or modify application code. -- Modify tests. -- Change task completion status or plan evidence. -- Determine whether the plan is complete. -- Select or execute another task. -- Run full-plan validation. -- Mark the plan validated, closed, or archived. -- Create a Git commit or push changes. -- Create the context root. `sce setup --bootstrap-context` owns that. -- Narrate changed files as documentation. Feature existence is the only reason - to document a change that introduced no other durable knowledge. -- Delete a context file that has uncommitted changes. -- Return an execution-style YAML result. - -## Completion - -The skill is complete after: - -- The context root was confirmed, or a `blocked` report named - `sce setup --bootstrap-context` as the required action. -- The mandatory root pass was run. -- Applicable durable context was synchronized and verified, no context change - was warranted, or a synchronization blocker was reported. -- One Markdown report matching `references/sync-report.md` was returned. diff --git a/.pi/skills/sce-task-execution/SKILL.md b/.pi/skills/sce-task-execution/SKILL.md deleted file mode 100644 index 3c8f7f70..00000000 --- a/.pi/skills/sce-task-execution/SKILL.md +++ /dev/null @@ -1,246 +0,0 @@ ---- -name: sce-task-execution -description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. ---- - -# SCE Task Execution - -## Purpose - -Execute exactly one reviewed SCE plan task (located in `context/plans/`). - -This skill owns: - -- Showing the implementation gate at the start of every invocation. -- Receiving the user's approval or rejection, or accepting approval - pre-supplied by the invoking workflow. -- Implementing one approved task. -- Running task-level verification. -- Updating that task and its evidence in the plan. -- Returning one terminal YAML result. - -Use the gate defined in: - -`references/implementation-gate.md` - -Return a final result matching: - -`references/execution-contract.yaml` - -## Input - -The invoking workflow provides: - -- The complete `ready` result from `sce-plan-review`. -- An optional `approve` flag. - -The `approve` flag means the user pre-approved this task when invoking the -workflow. It suppresses the approval question and the wait. It never suppresses -the gate. Only the invoking workflow may set it, and only from an explicit -user-supplied approval token. Never infer it. - -The readiness result must identify: - -- One resolved plan. -- Exactly one incomplete task. -- The task goal and scope boundaries. -- Done checks. -- Verification expectations. -- Relevant files and context. -- Review assumptions. - -If required handoff information is absent or stale, still show the gate using -what is known, clearly identify the handoff problem, and do not edit files. -After the user responds, return `blocked`. - -## Workflow - -### 1. Validate the handoff without editing - -Confirm that: - -- The readiness status is `ready`. -- Exactly one task is present. -- The plan file exists. -- The selected task is still incomplete. -- The task has not materially changed since review. -- Declared dependencies remain complete. - -Do not reconstruct missing material requirements. - -### 2. Always show the implementation gate - -At the start of the skill, before any file modification, present the task using -`references/implementation-gate.md`. - -The gate must be shown even when: - -- The task appears straightforward. -- The invoking workflow believes approval was already implied. -- The handoff is stale or incomplete. -- The user is likely to approve. - -When the `approve` flag is absent, end the gate with exactly one approval -question: - -`Continue with implementation now? (yes/no)` - -Stop and wait for the user's answer. Do not return YAML, and make no file -modifications, until the user has answered. - -When the `approve` flag is supplied, show the gate as a summary, omit the -approval question, do not wait, and continue at *Prepare the implementation*. - -### 3. Handle the user's decision - -Skip this step when the `approve` flag was supplied. - -When the user rejects or cancels, do not modify files and return `declined`. - -When the user does not clearly approve, do not modify files. Ask the same -approval question once more only when the response is genuinely ambiguous. -Otherwise return `blocked`. - -When the user approves, continue with implementation. - -Treat constraints supplied with approval as part of the approved task boundary. -If those constraints materially contradict the reviewed task, return `blocked` -before editing. - -### 4. Prepare the implementation - -Before editing: - -- Read the relevant files supplied by plan review. -- Inspect nearby code and tests when needed. -- Identify the smallest coherent change satisfying the task. -- Follow surrounding naming, structure, error handling, and test style. -- Preserve unrelated behavior. - -Do not create a second plan. - -Do not broaden the reviewed task. - -### 5. Implement one task - -Make the minimum coherent changes required to satisfy the task goal and done -checks. - -Use judgment for ordinary, reversible local implementation choices. - -Stop when implementation requires: - -- Material scope expansion. -- A new external dependency not authorized by the task. -- A public-interface decision not established by the plan. -- A destructive or difficult-to-reverse operation. -- An unresolved security, privacy, or data decision. -- Contradicting the reviewed task or repository architecture. - -When stopped, preserve completed in-scope work unless retaining it would leave -the repository unsafe or invalid. - -### 6. Verify the task - -Run the narrowest authoritative checks that demonstrate the done checks. - -Start with verification supplied by the readiness result. Add nearby or directly -relevant checks only when needed. - -Verification may include: - -- Targeted tests. -- Type checking for affected code. -- Linting affected files. -- Formatting checks. -- A focused build or compile step. -- Direct behavioral inspection when no automated check exists. - -Do not run final plan validation unless the task itself explicitly requires it. - -When a check fails: - -- Determine whether the task caused the failure. -- Fix it when the correction remains in scope. -- Rerun the relevant check. -- Return `incomplete` when a done check remains unsatisfied, or `blocked` when - completing it requires an unapproved decision or scope expansion. - -Never report a check as passed unless it ran successfully. - -### 7. Update the plan - -Only after successful implementation and task-level verification: - -- Mark only the selected task complete. -- Record concise implementation evidence. -- Record verification commands and outcomes. -- Record material deviations or approved assumptions. -- Preserve the plan's existing structure and terminology. - -Do not mark the task complete when returning `declined`, `blocked`, or -`incomplete`. - -### 8. Determine the terminal status - -Return `complete` when the task was implemented, verified, and marked complete -in the plan with evidence. - -Return `incomplete` when in-scope work was completed but one or more done checks -remain unsatisfied. - -Return `declined` when the user rejected implementation. - -Return `blocked` for every other non-successful outcome, including: - -- Missing approval. -- Stale or invalid handoff. -- Material blocker. -- A verification failure that cannot be resolved in scope. - -Use a blocker category defined by `references/execution-contract.yaml`. - -Do not determine whether the plan is complete. The invoking `/next-task` -workflow owns that decision after context synchronization. - -### 9. Return YAML - -After the skill reaches a terminal state, return exactly one YAML document -matching `references/execution-contract.yaml`. - -Return only the YAML document. Do not add explanatory prose before or after it. - -## Boundaries - -Do not: - -- Edit before approval, whether explicit or pre-supplied. -- Execute more than one task. -- Select or execute the next task. -- Skip the implementation gate. -- Ask for multiple approval gates for the same unchanged task. -- Expand scope without authorization. -- Synchronize durable context. -- Run final plan validation. -- Determine whether the plan is complete. -- Create a Git commit. -- Push changes. -- Modify unrelated files. -- Claim verification that was not performed. - -## Completion - -The skill is complete after: - -- The implementation gate was shown. -- The user approved or rejected the task, or approval was pre-supplied. -- At most one task was executed. -- One valid terminal YAML result matching `references/execution-contract.yaml` - was returned. diff --git a/.pi/skills/sce-task-execution/references/execution-contract.yaml b/.pi/skills/sce-task-execution/references/execution-contract.yaml deleted file mode 100644 index cf45b58a..00000000 --- a/.pi/skills/sce-task-execution/references/execution-contract.yaml +++ /dev/null @@ -1,306 +0,0 @@ -version: 1 -name: sce-task-execution-result - -description: > - Output contract for sce-task-execution. The skill returns exactly one YAML - document representing declined, blocked, incomplete, or complete. - -output_rules: - - Return exactly one result variant. - - Return YAML only, without a Markdown code fence or explanatory prose. - - Include only fields relevant to the selected status. - - Omit optional fields that do not apply rather than sending them empty. - - Do not return empty strings or null placeholders. An empty list is a valid - value for a required list field. - - Report plan.completed_tasks and plan.total_tasks as they stand when the - result is returned. - - Do not serialize the implementation gate. The gate is user-facing prose - defined by implementation-gate.md, and no result is returned until the - user has answered it. - - Do not select or describe the next task. - - Do not include context synchronization results. - - Do not include final plan validation results. - -variants: - - declined: - meaning: > - The user declined implementation and no implementation changes were made. - - required_fields: - - status - - plan - - task - - shape: - status: declined - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - example: - status: declined - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocked: - meaning: > - The task cannot continue without a material decision or authorization. - - required_fields: - - status - - plan - - task - - blocker - - work_preserved - - optional_fields: - - changes - - verification - - shape: - status: blocked - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - blocker: - category: stale_review | scope | dependency | architecture | security | data | destructive_operation | other - problem: string - impact: string - decision_required: string - - changes: - files_changed: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - work_preserved: boolean - - example: - status: blocked - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - blocker: - category: dependency - problem: The implementation requires adding a new token-signing package. - impact: The task does not authorize a new production dependency. - decision_required: Approve the dependency or choose an existing repository implementation. - - work_preserved: true - - incomplete: - meaning: > - In-scope implementation work was completed, but one or more task done - checks remain unsatisfied. - - required_fields: - - status - - plan - - task - - changes - - verification - - remaining_work - - optional_fields: - - satisfied_done_checks - - unsatisfied_done_checks - - reason - - shape: - status: incomplete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed | failed | not_run - summary: string - - satisfied_done_checks: - - string - - unsatisfied_done_checks: - - string - - remaining_work: - - string - - reason: string - - example: - status: incomplete - - plan: - path: context/plans/authentication.md - completed_tasks: 2 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login handler. - - Added valid-credential coverage. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: failed - summary: Invalid-credential response does not match the expected error format. - - satisfied_done_checks: - - Valid credentials return a token. - - unsatisfied_done_checks: - - Invalid credentials return the standard authentication error. - - remaining_work: - - Correct invalid-credential error mapping. - - Rerun targeted authentication tests. - - reason: Completing the correction requires clarification of the expected error mapping. - - complete: - meaning: > - The selected task was implemented, verified, and marked complete in - the plan with evidence. - - required_fields: - - status - - plan - - task - - changes - - verification - - done_checks - - plan_update - - context_impact - - shape: - status: complete - - plan: - path: string - completed_tasks: integer - total_tasks: integer - - task: - id: string - title: string - - changes: - files_changed: - - string - summary: - - string - - verification: - - command: string - outcome: passed - summary: string - - done_checks: - - check: string - evidence: string - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: none | local | domain | root - affected_areas: - - string - reason: string - - example: - status: complete - - plan: - path: context/plans/authentication.md - completed_tasks: 3 - total_tasks: 5 - - task: - id: T03 - title: Add login endpoint - - changes: - files_changed: - - src/auth/login.ts - - tests/auth/login.test.ts - summary: - - Added the login request handler. - - Reused the existing credential verifier and token response. - - Added focused success and failure tests. - - verification: - - command: npm test -- tests/auth/login.test.ts - outcome: passed - summary: 8 authentication tests passed. - - done_checks: - - check: Valid credentials return a token. - evidence: Covered by the successful login test. - - check: Invalid credentials return the standard authentication error. - evidence: Covered by the invalid-credential test. - - check: Targeted authentication tests pass. - evidence: npm test -- tests/auth/login.test.ts exited successfully. - - plan_update: - task_marked_complete: true - evidence_recorded: true - - context_impact: - classification: domain - affected_areas: - - authentication - reason: The task introduced durable login behavior that should be reflected in authentication context. diff --git a/.pi/skills/sce-task-execution/references/implementation-gate.md b/.pi/skills/sce-task-execution/references/implementation-gate.md deleted file mode 100644 index d4ad836c..00000000 --- a/.pi/skills/sce-task-execution/references/implementation-gate.md +++ /dev/null @@ -1,69 +0,0 @@ -# Implementation gate - -Always show this gate at the start of `sce-task-execution`, before editing any -file. - -The gate is user-facing prose. It is never serialized into a YAML result. This -file is the only authority for the gate's content and order. - -## Format - -# `{task.id} - {task.title} - {plan.name}` - -## Goal - -{task.goal} - -## In scope - -- {task.in_scope} - -## Out of scope - -- {task.out_of_scope} - -## Done when - -- {task.done_checks} - -## Expected changes - -- List confirmed files or areas expected to change. -- Label uncertain entries as likely rather than confirmed. - -## Approach - -Describe the smallest coherent implementation approach in 2–5 steps. - -## Assumptions - -- Include material assumptions returned by plan review. -- Omit this section when there are no assumptions. - -## Risks or trade-offs - -- Include only risks relevant to approving this task. -- Omit this section when there are no meaningful risks. - -## Verification - -- {task.verification} - -When the `approve` flag is absent, end with exactly: - -`Continue with implementation now? (yes/no)` - -When the `approve` flag is supplied, omit the question and end after -**Verification**. - -## Rules - -- Show the gate exactly once for an unchanged task. -- Do not modify files before approval. -- Do not add requirements absent from the reviewed task. -- Do not present multiple competing approaches unless a material decision is - required. -- Do not emit YAML while waiting for the user's answer. Stop after the gate and - wait. -- If the handoff is stale or incomplete, show the known task information and - identify the problem under **Risks or trade-offs**. diff --git a/.pi/skills/sce-validate/SKILL.md b/.pi/skills/sce-validate/SKILL.md new file mode 100644 index 00000000..d711aa42 --- /dev/null +++ b/.pi/skills/sce-validate/SKILL.md @@ -0,0 +1,766 @@ +--- +name: sce-validate +description: > + Validate one completed SCE plan and synchronize its durable context +--- + +# SCE Validate + +## Purpose + +Own this workflow from input parsing through its terminal user-visible response. +Execute the phases below directly and in order. Phase statuses are internal state, +not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or +workflow command. + +## User-visible output + +Use `references/output.md` for every gate and terminal response. Render no raw +internal state. The reference contains only human-visible Markdown layouts. + +## Canonical workflow + + +description: "Run the **Validation phase** -> the **Plan context synchronization phase** to finish an SCE plan" +argument-hint: "" + + +SCE VALIDATE `$ARGUMENTS` + +## Input + +`$ARGUMENTS` is the plan name or plan path. + +- The plan name or path is required. +- Resolve exactly one plan. Do not invent a plan from the conversation or from + incomplete nearby work. + +When `$ARGUMENTS` is empty, report that a plan name or path is required, state +the expected argument, and stop. Do not infer the plan from repository state or +the conversation. + +Pass the plan name or path to the **Validation phase** unmodified. Do not restate, +summarize, or pre-scope it. + +Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is +the path carried by the **Validation phase** in its Markdown result (`Plan:`, or a +candidate path), so every emitted command is directly runnable. + +## Workflow + +### 1. Validate the plan + +Run the **Validation phase** with the plan name or path. + +the **Validation phase** exclusively owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running full validation and acceptance-criteria checks. +- Removing temporary scaffolding. +- Writing the Validation Report into the plan. +- Returning one Markdown validation result. + +Do not duplicate any of it. Do not write the Validation Report yourself. + +The skill must return a Markdown result matching its validation-result contract. +Branch on the report's `Status:`. + +`blocked` -> Do not run context synchronization. Print the blocked Markdown +report as returned. Do not rephrase it into a different layout. Stop. + +`failed` -> Do not run context synchronization. Print the failed Markdown +report as returned. It is already a session handoff: self-contained, actionable, +and ending with `/validate {plan-path}` after repairs. + +Do not rewrite it into a shorter summary. Do not drop the retry command. Do not +add an alternate continuation that replaces `/validate`. + +Stop. Do not mark the plan finished. Do not continue to context synchronization. +Do not start the repair work in this workflow unless the user explicitly asks +to continue here; the default is that the handoff can leave this session. + +`validated` -> Pass the complete validated Markdown result to +the **Plan context synchronization phase**. + +Do not reconstruct, summarize, or reinterpret the validation result before +passing it. + +### 2. Synchronize plan context + +Run the **Plan context synchronization phase** only with a `Status: validated` Markdown result +from the **Validation phase**. + +Do not run the **Plan context synchronization phase** for `failed` or `blocked`. Those are not +success states. + +Pass the validated result verbatim. It is the authoritative handoff, and +the **Plan context synchronization phase** owns reading the plan path, required context paths, +validation evidence, and reported context impact out of it. + +Do not restate, summarize, or reconstruct any part of the validation result. + +Branch on the synchronization result. + +`blocked` -> Validation itself succeeded and is already recorded in the plan. +Present: + +- That plan `{plan-path}` passed final validation and its Validation Report is + written. +- The context contradiction or synchronization failure. +- Any context edits the report says were preserved. +- The action required to resolve the problem. +- The retry condition stated by the report. + +State that durable context is now out of date relative to the validated +implementation, and that plan context synchronization must be resolved before +treating the plan as fully closed. Nothing records the skipped synchronization, +so it is lost once this session ends. + +Stop. + +`synced` | `no_context_change` -> Print out the report +the **Plan context synchronization phase** returned. Continue to the next step. + +### 3. Report completion + +Return exactly one completion block. Do not start another workflow. + +``` + +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +When the synchronization status was `no_context_change`, keep the same +completion block. "Synchronized" here means the final context pass finished +successfully, including the case where no edit was warranted. + +Stop. + +## Rules + +- Validate at most one plan per invocation. +- Do not duplicate the internal instructions of embedded phases. +- Do not run final validation when implementation tasks remain; the **Validation phase** + returns `blocked`, and this workflow stops. +- Run the **Plan context synchronization phase** only when the **Validation phase** returned + `Status: validated`. Do not run it for `failed` or `blocked`. +- On `failed`, print the handoff Markdown as returned and stop. Preserve the + retry `/validate {plan-path}` instruction. Do not synchronize context. +- Do not implement remaining plan tasks from this workflow unless the user + explicitly continues in-session after a failed handoff. +- Do not create a Git commit or push changes. +- Do not mark the plan archived or delete the plan. +- Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` + yourself. +- Do not infer success when an embedded phase returns a non-success status. +- Preserve validation evidence already written to the plan when context + synchronization fails. + +## Embedded phase behavior + +## Internal phase: Validation phase + + +name: Validation phase +description: > + Internal SCE workflow skill that runs final plan validation after all + implementation tasks are complete: full validation commands, acceptance + criteria checks, temporary scaffolding cleanup, a Validation Report written + into the plan, and one internal state (validated, failed, or blocked). + Failing checks are reported only; do not modify tests or product code to make + validation pass. A failed result is a session handoff that ends by retrying + /validate. Use from /validate. Do not synchronize durable context, implement + remaining plan tasks, create commits, or select another task. + + +# SCE Validation + +## Purpose + +Prove that one finished SCE plan meets its acceptance criteria and repository +validation bar, then record the evidence on the plan and return one Markdown +result. + +This skill owns: + +- Resolving one plan. +- Confirming every implementation task is complete. +- Running the plan's full validation commands and each acceptance criterion + check. +- Removing temporary scaffolding introduced by the change. +- Writing the Validation Report into the plan. +- Marking acceptance criteria against the evidence. +- Recording one Markdown validation result. + +Return a result matching: + +`references/output.md` + +Write plan-file evidence matching: + +the **Plan-file validation report** section embedded in this file + +Context synchronization is not this skill's job. The invoking `/validate` +workflow runs the **Plan context synchronization phase** only after a `validated` result. + +## Input + +The invoking workflow provides: + +- A plan name or path. + +## Workflow + +### 1. Resolve the plan + +Resolve the supplied plan name or path to exactly one existing plan under +`context/plans/`. + +When no plan can be found, set internal status `blocked`. + +When multiple plans match and none can be selected safely, set internal status `blocked` +with the matching candidates. + +Read the selected plan before exploring the repository. + +### 2. Confirm implementation is finished + +Set internal status `blocked` with incomplete tasks listed when any implementation task +remains incomplete. + +Final validation measures finished work. Do not run the full suite against a +partial stack, and do not complete remaining tasks here. + +### 3. Read the validation contract from the plan + +From the plan, collect: + +- Every acceptance criterion and its `Validate:` check. +- The `Full validation` command list. +- The `Context sync` requirements, for the context-impact handoff only. + +Set internal status `blocked` when the plan has no usable acceptance criteria, or when no +validation commands can be determined from the plan or repository conventions. + +Prefer the plan's authored checks. Fall back to repository-primary test, lint, +and format commands only when `Full validation` is absent, and record that +fallback under notes on a `validated` or `failed` result. + +### 4. Remove temporary scaffolding + +Before or while running checks, remove temporary scaffolding introduced during +the change when it is clearly throwaway: + +- Debug-only patches or flags left enabled. +- Temporary files or intermediate artifacts not part of the delivered design. +- Local scaffolding the plan or task notes mark as temporary. + +Do not delete durable product code, tests, configuration, or context files. + +Record every removed path. When nothing temporary remains, report `None.` + +### 5. Run full validation and acceptance checks + +Run the plan's `Full validation` commands. + +Then verify each acceptance criterion using its `Validate:` line. Prefer a +runnable command. Use a named inspection only when the criterion authorizes it, +and say exactly what was inspected. + +When a check fails, record the failure and continue gathering evidence. Do not +modify tests, application code, or configuration to make a check pass. Final +validation measures the finished work; repair belongs to a later work session, +not this skill. + +Never report a check as passed unless it ran successfully or the authorized +inspection confirmed the criterion. + +Do not run task-by-task implementation work for incomplete tasks. That belongs +to `/next-task`. + +### 6. Update the plan + +For `validated` and `failed` outcomes: + +- Mark each acceptance criterion checkbox to match the evidence. +- Append or replace the plan's `## Validation Report` section using + the **Plan-file validation report** section embedded in this file. +- When status is `failed`, the plan-file report must include the retry command + `/validate {plan path}`. + +Do not reopen completed tasks, rewrite task evidence, or change the task stack. + +For `blocked`, leave the plan file unchanged. + +### 7. Determine context impact for the handoff + +On `validated` only, classify the durable context impact of the finished plan +so the **Plan context synchronization phase** can start from the plan's own requirements: + +- Start from the plan's `Context sync` section. +- Inspect what the completed implementation actually changed when needed. +- Report required context paths and affected areas. +- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level + context sync. + +Do not edit context files here. + +On `failed` or `blocked`, omit context impact; context sync will not run. + +### 8. Return the internal state + +Set exactly one internal state: + +- `validated` when every acceptance criterion is met, required full validation + passed, and the Validation Report was written. +- `failed` when evidence was captured but required checks or criteria remain + unsatisfied. Shape it as a session handoff per + `references/output.md`, ending recommended work with + `/validate {plan path}`. +- `blocked` when validation cannot proceed safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. Do not return internal state. + +## Boundaries + +Do not: + +- Validate more than one plan. +- Complete remaining implementation tasks. +- Modify tests, application code, or configuration to make a failing check pass. +- Apply lint or format auto-fixes that change product or test files as part of + making validation green. +- Synchronize durable context under `context/` outside the plan file. +- Create the context root. +- Mark the plan archived or delete the plan. +- Create a Git commit or push changes. +- Invent acceptance criteria the plan does not state. +- Claim verification that was not performed. +- Return a internal state. +- Run plan context synchronization. The workflow owns that step. + +## Completion + +The skill is complete after: + +- One plan was resolved, or resolution failed and was reported. +- Implementation completeness was checked. +- Validation ran to a terminal state, or a blocker prevented it. +- One valid internal state matching `references/output.md` was + returned. + +## Internal phase: Plan context synchronization phase + + +name: Plan context synchronization phase +description: > + Internal SCE workflow skill that accepts a successful Status: validated + internal state from Validation phase, reconciles the finished plan with durable + repository context, and returns a Markdown synchronization report. Run only + after final validation has passed. Do not implement application code, change + plan validation state, rerun full validation, or select another task. + + +# SCE Plan Context Sync + +## Purpose + +Reconcile one fully validated plan with the repository's durable context and +return a Markdown report. + +This skill owns: + +- Validating the validation handoff. +- Confirming the context root exists. +- Discovering the context required by the finished plan. +- Deciding whether durable context changed. +- Editing and verifying the affected context files. +- Recording one Markdown synchronization report. + +Use the report format in: + +`references/output.md` + +Task-level context sync may already have run after individual tasks. This skill +is the plan-level final pass: it starts from the plan's `Context sync` +requirements and the validated implementation, and closes gaps that remain. + +## Input + +The invoking workflow provides: + +- The complete internal state returned by the **Validation phase**. + +The validation result must report: + +```markdown +**Status:** validated +**Plan:** {plan path} +``` + +Treat that Markdown as the authoritative handoff for: + +- The resolved plan path. +- Validation commands and outcomes. +- Acceptance-criteria evidence. +- Scaffolding removals. +- Reported context impact, required context paths, and affected areas. + +This skill must not be run for `failed` or `blocked` validation results. +Those are not success states. Same rule as the **Task context synchronization phase**: context sync +runs only after a successful prior phase. + +Do not reconstruct a missing validation result from conversation history. + +## Workflow + +### 1. Validate the validation handoff + +Confirm that: + +- `Status:` is exactly `validated`. +- `Plan:` names an existing plan path. +- Acceptance-criteria evidence is present and every criterion is met. +- Commands run are present. +- A context-impact classification is present. + +If the handoff is missing required information or is internally contradictory, +do not modify context. Return a `blocked` Markdown report. + +### 2. Confirm the context root + +When `context/` does not exist, there is no durable memory to synchronize. +Do not create it, and do not write context files outside it. + +Return a `blocked` report whose required action is: + +`sce setup --bootstrap-context` + +State that validation itself succeeded and is recorded in the plan, and that +plan context synchronization should run again once the context root exists. + +Bootstrapping is the user's action, not this skill's. + +### 3. Discover applicable context + +Start with the validated internal state: + +- **Context impact** classification, required context, and affected areas. +- Acceptance-criteria evidence. +- Commands run. + +Then read the plan's `Context sync` section and inspect existing repository +context in this order when present: + +1. Paths named by the plan's `Context sync` section +2. `context/context-map.md` +3. Context files for the affected domain or subsystem +4. `context/overview.md` +5. `context/architecture.md` +6. `context/glossary.md` +7. `context/patterns.md` +8. Operational, product, or decision records directly related to the finished + change + +Use the context map and existing links to locate authoritative files. + +Do not scan or rewrite the entire `context/` tree by default. + +Do not create a new context file when an existing authoritative file can be +updated coherently. + +#### The mandatory root pass + +Every invocation verifies these five files against code truth, whatever the +reported classification is: + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/patterns.md` +- `context/context-map.md` + +Verifying is not editing. A classification that warrants no root edit still +requires reading each of these and confirming it is not contradicted by the +finished implementation. A file that is absent is a gap; record it in the +report rather than creating it to satisfy the pass. + +Report each of the five as verified or edited. Never declare synchronization +done while one of them is unchecked. + +#### Plan context requirements + +Every path or statement listed under the plan's `Context sync` section must be +accounted for in the report as already accurate or updated. A requirement the +finished code still does not satisfy is a blocker, not a note. + +### 4. Determine whether durable context changed + +Use the reported context impact as a strong hint, then verify it against the +finished implementation and existing context. + +Durable context includes non-obvious repository knowledge such as: + +- User-visible or externally observable behavior. +- Architecture, boundaries, ownership, and dependency direction. +- Public interfaces, data contracts, and persistence behavior. +- Operational procedures and important failure modes. +- Security or privacy behavior. +- Shared terminology. +- Intentional limitations and meaningful design decisions. + +Do not document: + +- Details already obvious from the implementation. +- Temporary debugging information. +- A file-by-file narration of the change. +- Test output that belongs only in validation evidence. +- Speculation or future work not established by the finished plan. +- Generic engineering practices. + +Interpret impact classifications as follows. Each governs which files are +*edited*; none of them waives the mandatory root pass or the plan's Context +sync requirements. + +- `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. +- `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. +- `domain`: Update affected domain context and the context map when its links or + summaries changed. +- `root`: Update the relevant root context and any affected domain context. + +If the reported classification is inconsistent with the actual change, use the +verified classification and explain the difference in the report. + +### 5. Synchronize context + +Make the smallest coherent documentation change that preserves repository truth. + +When editing context: + +- Describe the resulting behavior, not the validation session. +- Preserve repository terminology and document structure. +- Remove or correct statements contradicted by the finished implementation. +- Update cross-references when files are added, moved, renamed, or superseded. +- Keep one authoritative statement for each durable fact. +- Avoid copying the validation result verbatim into context files. +- Do not change application code, tests, or plan validation evidence. + +Create a new context file only when: + +- The knowledge is durable and non-obvious. +- No existing file owns it coherently. +- The new file has a clear place in the context map. + +#### Feature existence + +Every feature the finished plan implemented must have at least one durable +canonical description discoverable from `context/`, in a domain file under +`context/{domain}/` or in `context/overview.md` for a cross-cutting feature. + +When the plan delivered a feature no context file describes, add that +description. Prefer a small, precise domain file over overloading +`overview.md` with detail. + +This is not license to narrate the diff: describe what the feature is and how +it behaves, not what was edited during the plan. + +#### Glossary + +Add a `context/glossary.md` entry for any domain language the plan introduced. +New terminology is durable knowledge whatever the classification is. + +#### File hygiene + +Every context file this skill writes must satisfy: + +- One topic per file. +- At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. +- Relative paths in every link to another context file. +- A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. +- Concrete code examples only where they clarify non-trivial behavior. + +When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a +concise pointer behind, and link the new file from `context/context-map.md`. + +### 6. Verify synchronization + +After edits, verify: + +- Every changed context file accurately reflects the finished implementation. +- No edited statement contradicts the code, plan, or validation evidence. +- Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. +- Every plan `Context sync` requirement is met. +- Each feature implemented by the plan has a durable canonical description + reachable from `context/`. +- Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. +- Diagrams are present where structure, boundaries, or flows are complex. +- Links and referenced paths resolve when practical to check. +- New context files are reachable from the context map or another authoritative + index. +- Root context remains concise and delegates details to domain files. +- Unrelated context was not changed. + +Use focused documentation, link, or formatting checks when available. + +Do not rerun full-plan validation. + +If synchronization cannot be completed without inventing facts or resolving a +material contradiction, preserve safe edits when appropriate and return a +`blocked` report. + +### 7. Return the Markdown report + +Set exactly one report status: + +- `synced` +- `no_context_change` +- `blocked` + +`synced` means context files were updated and verified. `no_context_change` +means existing context was checked and no edit was warranted. `blocked` means +context could not be synchronized safely. + +Record only the Markdown report. Do not add explanatory prose before or after +it. + +## Boundaries + +Do not: + +- Accept a validation result whose status is not `validated`. +- Accept `failed` or `blocked` validation results. +- Implement or modify application code. +- Modify tests. +- Change task completion status, acceptance-criteria marks, or the Validation + Report. +- Rerun full-plan validation. +- Select or execute an implementation task. +- Create a Git commit or push changes. +- Create the context root. `sce setup --bootstrap-context` owns that. +- Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. +- Delete a context file that has uncommitted changes. +- Return internal state. + +## Completion + +The skill is complete after: + +- The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. +- The mandatory root pass was run. +- Plan context requirements were checked. +- Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. +- One Markdown report matching `references/output.md` was returned. + +## Internal persisted-document format: Plan-file validation report + +# Plan-file Validation Report + +The Markdown section the **Validation phase** appends to the plan file when returning +`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` +under exactly one `## Validation Report` heading. + +This is plan-file content. The skill's return value to the workflow is defined +separately in `validation-result.md`. + +Do not author this section while planning. Only `/validate` through +the **Validation phase** writes it. + +## Layout + +```markdown +## Validation Report + +**Status:** {validated | failed} +**Date:** {YYYY-MM-DD} + +### Commands run + +- `{command}` -> exit {code} ({concise outcome summary}) +- `{command}` -> exit {code} ({concise outcome summary}) + +### Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +### Success-criteria verification + +- [x] AC1: {criterion statement} -> {evidence} +- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} + +### Failed checks and follow-ups + +- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} +- None. + +### Residual risks + +- {risk} +- None identified. + +### Retry + +{Only when Status is failed:} + +After repairs, rerun: + +`/validate {plan path}` +``` + +## Rules + +- Use **Status:** `validated` only when every acceptance criterion is met and + every required full-validation command passed. +- Use **Status:** `failed` when evidence was captured but required checks or + criteria remain unsatisfied. +- List every command that ran under **Commands run**, including ones that + failed. Do not invent exit codes or outcomes. +- Prefer the plan's `Full validation` commands and each criterion's `Validate:` + line over rediscovering project defaults. Fall back to repository conventions + only when the plan omits them. +- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` + section to match the evidence. Do not mark a criterion met unless the check + ran successfully or the inspection named by `Validate:` confirms it. +- Under **Scaffolding removed**, list only temporary debug code, intermediate + artifacts, or throwaway files introduced during the change. Write `None.` when + nothing temporary remained. +- Under **Failed checks and follow-ups**, record the failing check and its + evidence only. Do not describe code or test edits made during validation; + validation does not modify tests or product code to clear failures. Write + `None.` when status is `validated`. +- When status is `failed`, always include **Retry** with the exact + `/validate {plan path}` command. Omit **Retry** when status is `validated`. +- Keep evidence concise and factual. Do not narrate the whole implementation + history. +- Do not claim context synchronization completed. Plan context sync is a later + workflow step and runs only after `validated`. +- Do not rewrite task evidence or reopen completed tasks. +- When a previous `## Validation Report` already exists, replace it with the new + one rather than stacking duplicates. + +## Composite control flow + +Keep phase results as internal state and continue immediately whenever the +canonical workflow says to continue. Stop only at a user wait or terminal branch. +Approval, clarification, revision, failed-validation repair, and bootstrap waits +resume this same skill in the same session. Never expose an internal phase result +as the workflow's final response. diff --git a/.pi/skills/sce-validate/references/output.md b/.pi/skills/sce-validate/references/output.md new file mode 100644 index 00000000..3e4c5519 --- /dev/null +++ b/.pi/skills/sce-validate/references/output.md @@ -0,0 +1,429 @@ +# Validate output layouts + +Use only the applicable layout. Values come from internal workflow state. + +## Validation blocked + +```markdown +# Validation blocked + +**Status:** blocked +**Plan:** `{plan-path when resolved}` +**Name:** `{plan-name when resolved}` + +## Issues + +- **{issue-id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision-or-action} + +## Incomplete tasks + +- `{task-id}` — {title} + +## Candidates + +- `{candidate-plan-path}` + +## Next step + +{one continuation matching the blocker} +``` + +Omit inapplicable optional sections. + +## Validation failed handoff + +```markdown +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan-path}` +**Name:** `{plan-name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan-path}` + +## Goal for the next session + +{repair goal} + +## What failed + +- `{check-or-AC}`: {problem} + - Evidence: {evidence} + - Required action: {action} + +## Acceptance criteria + +- [{x-or-space}] {criterion}: {evidence} + +## Commands run + +- `{command}` -> {passed|failed|not_run} — {summary} + +## Constraints + +{canonical validation constraints} + +## Residual risks + +- {risk-or-none} + +## Recommended work + +1. {repair} +2. Rerun final validation after repairs: + +`/validate {plan-path}` +``` + +## Context synchronization blocked + +State that validation passed and its report is recorded, then report the context +failure, preserved edits, required action, and retry condition. State that durable +context remains out of date and synchronization must finish before closure. + +## Completion + +```markdown +------------------------------------- + +# Plan {plan-name} validated. + +All implementation tasks were already complete. +Final validation passed. +Durable context is synchronized. + +Validation report: {plan-path} +``` + +# Validation Result + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `validated` +- `failed` +- `blocked` + +The plan-file `## Validation Report` section is written separately using +`validation-report.md`. This file is the skill's return value to the invoking +workflow. + +## Validated variant + +# Validation Report + +**Status:** validated +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` + +## Commands run + +- `{command}` -> {passed} — {concise outcome summary} + +## Acceptance criteria + +- [x] AC1: {criterion statement} — {evidence} +- [x] AC2: {criterion statement} — {evidence} + +## Scaffolding removed + +- `{path}` — {why it was temporary} +- None. + +## Residual risks + +- {risk} +- None identified. + +## Context impact + +**Classification:** `{none | local | domain | root}` +**Affected areas:** `{comma-separated areas}` +**Required context:** + +- `{path or statement from the plan Context sync section}` + +{One or two sentences on why this classification fits the finished plan.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## Failed variant + +This variant is a session handoff. Another agent or a later session must be +able to act from it alone. Write it as a prompt the user can paste forward, not +as a summary of the validation run. + +# Validation failed — handoff + +**Status:** failed +**Plan:** `{plan path}` +**Name:** `{plan name}` +**Tasks:** `{completed}/{total} complete` +**Date:** `{YYYY-MM-DD}` +**Validation report:** written to `{plan path}` + +## Goal for the next session + +Repair the unfinished validation so every acceptance criterion and full +validation command passes. Do not modify tests or product code inside a +`/validate` run to force green results; fix the implementation (or the plan) in +a normal work session, then rerun validation. + +## What failed + +- `{check or AC id}`: {problem} + - Evidence: {command output, exit summary, or inspection finding} + - Required action: {concrete repair or decision} + +## Acceptance criteria + +- [x] AC1: {criterion} — {evidence} +- [ ] AC2: {criterion} — {why unmet} + +## Commands run + +- `{command}` -> {passed | failed | not_run} — {concise outcome summary} + +## Constraints + +- All implementation tasks were already complete when validation ran. +- Validation did not modify tests, application code, or configuration to clear + failures. +- Durable context was not synchronized; plan context sync runs only after + validation succeeds. +- Prefer the plan at `{plan path}` and its Validation Report as the source of + recorded evidence. + +## Residual risks + +- {risk} +- None identified. + +## Recommended work + +1. {First concrete fix, with files or areas when known} +2. {Second concrete fix, or decision the user must make} +3. Rerun final validation after the fixes land: + +`/validate {plan path}` + +Do not stop after the repair. The plan is not finished until `/validate` +returns `validated` and plan context sync completes. + +--- + +## Blocked variant + +# Validation blocked + +**Status:** blocked +**Plan:** `{plan path when resolved}` +**Name:** `{plan name when resolved}` + +## Issues + +- **{issue id}** ({category}): {problem} + - Impact: {impact} + - Required: {decision or action} + +## Incomplete tasks + +- `{task id}` — {title} +- Omit this section when no incomplete tasks apply. + +## Candidates + +- `{candidate plan path}` +- Omit this section when plan resolution was not ambiguous. + +## Next step + +{Exactly one continuation, matching the blocker:} + +- Incomplete tasks: + +`/next-task {plan path}` + +- Ambiguous plan: + +`/validate {candidate path}` + +- Missing plan content or other blocker: state the decision required. Do not + invent a command. + +--- + +## Report rules + +- Name the exact `Plan:` path so every emitted command is runnable. +- Use **Status:** exactly `validated`, `failed`, or `blocked`. +- Never claim a check passed unless it ran successfully or the authorized + inspection confirmed it. +- Do not modify tests or product code to clear a failure; record it under + **What failed**. +- The failed variant must always end its **Recommended work** with + `/validate {plan path}` as the final step after repairs. +- The failed variant must be self-contained enough to hand to another session + without the original chat. +- Include **Context impact** only on `validated`. Omit it on `failed` and + `blocked`; plan context sync is not run for non-success states. +- Do not include context synchronization results in this report. The invoking + workflow runs the **Plan context synchronization phase** only after `validated`. +- Do not select or describe an unrelated next implementation task when status is + `validated`. +- Omit empty optional sections rather than writing placeholders. + +# Plan Context Sync Report + +Return only one completed Markdown report using the applicable variant below. +Do not include unused sections, placeholders, YAML, or a fenced code block. + +The `Status` value must be exactly one of: + +- `synced` +- `no_context_change` +- `blocked` + +The input validation status is always `validated` and does not need to be +repeated as a separate workflow state. This skill is not run for `failed` +or `blocked` validation results. + +## Synced variant + +# Plan Context Sync Report + +**Status:** synced +**Plan:** `{plan path}` + +## Context impact + +**Classification:** `{local | domain | root}` +**Affected areas:** `{comma-separated areas}` + +{Explain which durable behavior, architecture, terminology, operation, or +constraint required plan-level synchronization after validation.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — {met by edit | already accurate} + +## Updated context + +- `{context file}` — {concise description of the durable truth updated} + +## Root pass + +- `context/overview.md` — {verified | edited | absent} +- `context/architecture.md` — {verified | edited | absent} +- `context/glossary.md` — {verified | edited | absent} +- `context/patterns.md` — {verified | edited | absent} +- `context/context-map.md` — {verified | edited | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}` + +## Verification + +- {How the edited context was checked against the finished implementation and validation evidence.} +- {File hygiene: line counts, relative links, diagrams where structure is complex.} +- {Documentation, link, or formatting checks that were run, when applicable.} + +## Notes + +{Include only non-blocking information the invoking workflow should retain. +Omit this section when unnecessary.} + +--- + +## No-context-change variant + +# Plan Context Sync Report + +**Status:** no_context_change +**Plan:** `{plan path}` + +## Context impact + +**Classification:** none + +{Explain why the finished plan introduced no durable, non-obvious repository +knowledge requiring an update, or why existing context already matched.} + +## Plan context requirements + +- `{required context path or statement from the plan}` — already accurate +- None listed by the plan. + +## Context reviewed + +- `{context file or area}` — {what was checked and why it remains accurate} + +## Root pass + +- `context/overview.md` — {verified | absent} +- `context/architecture.md` — {verified | absent} +- `context/glossary.md` — {verified | absent} +- `context/patterns.md` — {verified | absent} +- `context/context-map.md` — {verified | absent} + +## Feature existence + +- `{feature}` — `{context file that canonically describes it}`, already present. + +## Verification + +- {How existing context was compared with the finished implementation and validation evidence.} + +--- + +## Blocked variant + +# Plan Context Sync Report + +**Status:** blocked +**Plan:** `{plan path}` + +## Blocker + +**Problem:** {specific synchronization blocker} +**Impact:** {why context cannot be made authoritative safely} +**Required action:** {decision or correction required} + +## Context changes + +- {List safe context edits preserved, or state `No context files were changed.`} + +## Retry condition + +{State the concrete condition under which plan context synchronization should +run again.} + +## Report rules + +- Name exact context files when they were changed or reviewed. +- Report every file in the root pass, including any that is absent. +- Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. +- Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. +- Omit **Feature existence** only when the plan implemented no feature. +- Describe durable truth, not validation-session chronology. +- Keep evidence concise and factual. +- Do not claim implementation tasks remain open. +- Do not reopen validation checks. +- Do not recommend a next implementation task unless context cannot be repaired + without one, and then only as the required action. diff --git a/.pi/skills/sce-validation/SKILL.md b/.pi/skills/sce-validation/SKILL.md deleted file mode 100644 index 2cd7557b..00000000 --- a/.pi/skills/sce-validation/SKILL.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -name: sce-validation -description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. ---- - -# SCE Validation - -## Purpose - -Prove that one finished SCE plan meets its acceptance criteria and repository -validation bar, then record the evidence on the plan and return one Markdown -result. - -This skill owns: - -- Resolving one plan. -- Confirming every implementation task is complete. -- Running the plan's full validation commands and each acceptance criterion - check. -- Removing temporary scaffolding introduced by the change. -- Writing the Validation Report into the plan. -- Marking acceptance criteria against the evidence. -- Returning one Markdown validation result. - -Return a result matching: - -`references/validation-result.md` - -Write plan-file evidence matching: - -`references/validation-report.md` - -Context synchronization is not this skill's job. The invoking `/validate` -workflow runs `sce-plan-context-sync` only after a `validated` result. - -## Input - -The invoking workflow provides: - -- A plan name or path. - -## Workflow - -### 1. Resolve the plan - -Resolve the supplied plan name or path to exactly one existing plan under -`context/plans/`. - -When no plan can be found, return `blocked`. - -When multiple plans match and none can be selected safely, return `blocked` -with the matching candidates. - -Read the selected plan before exploring the repository. - -### 2. Confirm implementation is finished - -Return `blocked` with incomplete tasks listed when any implementation task -remains incomplete. - -Final validation measures finished work. Do not run the full suite against a -partial stack, and do not complete remaining tasks here. - -### 3. Read the validation contract from the plan - -From the plan, collect: - -- Every acceptance criterion and its `Validate:` check. -- The `Full validation` command list. -- The `Context sync` requirements, for the context-impact handoff only. - -Return `blocked` when the plan has no usable acceptance criteria, or when no -validation commands can be determined from the plan or repository conventions. - -Prefer the plan's authored checks. Fall back to repository-primary test, lint, -and format commands only when `Full validation` is absent, and record that -fallback under notes on a `validated` or `failed` result. - -### 4. Remove temporary scaffolding - -Before or while running checks, remove temporary scaffolding introduced during -the change when it is clearly throwaway: - -- Debug-only patches or flags left enabled. -- Temporary files or intermediate artifacts not part of the delivered design. -- Local scaffolding the plan or task notes mark as temporary. - -Do not delete durable product code, tests, configuration, or context files. - -Record every removed path. When nothing temporary remains, report `None.` - -### 5. Run full validation and acceptance checks - -Run the plan's `Full validation` commands. - -Then verify each acceptance criterion using its `Validate:` line. Prefer a -runnable command. Use a named inspection only when the criterion authorizes it, -and say exactly what was inspected. - -When a check fails, record the failure and continue gathering evidence. Do not -modify tests, application code, or configuration to make a check pass. Final -validation measures the finished work; repair belongs to a later work session, -not this skill. - -Never report a check as passed unless it ran successfully or the authorized -inspection confirmed the criterion. - -Do not run task-by-task implementation work for incomplete tasks. That belongs -to `/next-task`. - -### 6. Update the plan - -For `validated` and `failed` outcomes: - -- Mark each acceptance criterion checkbox to match the evidence. -- Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. -- When status is `failed`, the plan-file report must include the retry command - `/validate {plan path}`. - -Do not reopen completed tasks, rewrite task evidence, or change the task stack. - -For `blocked`, leave the plan file unchanged. - -### 7. Determine context impact for the handoff - -On `validated` only, classify the durable context impact of the finished plan -so `sce-plan-context-sync` can start from the plan's own requirements: - -- Start from the plan's `Context sync` section. -- Inspect what the completed implementation actually changed when needed. -- Report required context paths and affected areas. -- Use `none`, `local`, `domain`, or `root` with the same meanings as task-level - context sync. - -Do not edit context files here. - -On `failed` or `blocked`, omit context impact; context sync will not run. - -### 8. Return the Markdown result - -Return exactly one Markdown result: - -- `validated` when every acceptance criterion is met, required full validation - passed, and the Validation Report was written. -- `failed` when evidence was captured but required checks or criteria remain - unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with - `/validate {plan path}`. -- `blocked` when validation cannot proceed safely. - -Return only the Markdown report. Do not add explanatory prose before or after -it. Do not return YAML. - -## Boundaries - -Do not: - -- Validate more than one plan. -- Complete remaining implementation tasks. -- Modify tests, application code, or configuration to make a failing check pass. -- Apply lint or format auto-fixes that change product or test files as part of - making validation green. -- Synchronize durable context under `context/` outside the plan file. -- Create the context root. -- Mark the plan archived or delete the plan. -- Create a Git commit or push changes. -- Invent acceptance criteria the plan does not state. -- Claim verification that was not performed. -- Return a YAML result. -- Invoke plan context sync. The workflow owns that step. - -## Completion - -The skill is complete after: - -- One plan was resolved, or resolution failed and was reported. -- Implementation completeness was checked. -- Validation ran to a terminal state, or a blocker prevented it. -- One valid Markdown result matching `references/validation-result.md` was - returned. diff --git a/.pi/skills/sce-validation/references/validation-report.md b/.pi/skills/sce-validation/references/validation-report.md deleted file mode 100644 index 877095ec..00000000 --- a/.pi/skills/sce-validation/references/validation-report.md +++ /dev/null @@ -1,84 +0,0 @@ -# Plan-file Validation Report - -The Markdown section `sce-validation` appends to the plan file when returning -`validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` -under exactly one `## Validation Report` heading. - -This is plan-file content. The skill's return value to the workflow is defined -separately in `validation-result.md`. - -Do not author this section while planning. Only `/validate` through -`sce-validation` writes it. - -## Layout - -```markdown -## Validation Report - -**Status:** {validated | failed} -**Date:** {YYYY-MM-DD} - -### Commands run - -- `{command}` -> exit {code} ({concise outcome summary}) -- `{command}` -> exit {code} ({concise outcome summary}) - -### Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -### Success-criteria verification - -- [x] AC1: {criterion statement} -> {evidence} -- [ ] AC2: {criterion statement} -> {evidence of failure or not checked} - -### Failed checks and follow-ups - -- {check}: {problem}; evidence: {command output or inspection}; required: {decision or next action} -- None. - -### Residual risks - -- {risk} -- None identified. - -### Retry - -{Only when Status is failed:} - -After repairs, rerun: - -`/validate {plan path}` -``` - -## Rules - -- Use **Status:** `validated` only when every acceptance criterion is met and - every required full-validation command passed. -- Use **Status:** `failed` when evidence was captured but required checks or - criteria remain unsatisfied. -- List every command that ran under **Commands run**, including ones that - failed. Do not invent exit codes or outcomes. -- Prefer the plan's `Full validation` commands and each criterion's `Validate:` - line over rediscovering project defaults. Fall back to repository conventions - only when the plan omits them. -- Mark each acceptance criterion checkbox in the plan's `## Acceptance criteria` - section to match the evidence. Do not mark a criterion met unless the check - ran successfully or the inspection named by `Validate:` confirms it. -- Under **Scaffolding removed**, list only temporary debug code, intermediate - artifacts, or throwaway files introduced during the change. Write `None.` when - nothing temporary remained. -- Under **Failed checks and follow-ups**, record the failing check and its - evidence only. Do not describe code or test edits made during validation; - validation does not modify tests or product code to clear failures. Write - `None.` when status is `validated`. -- When status is `failed`, always include **Retry** with the exact - `/validate {plan path}` command. Omit **Retry** when status is `validated`. -- Keep evidence concise and factual. Do not narrate the whole implementation - history. -- Do not claim context synchronization completed. Plan context sync is a later - workflow step and runs only after `validated`. -- Do not rewrite task evidence or reopen completed tasks. -- When a previous `## Validation Report` already exists, replace it with the new - one rather than stacking duplicates. diff --git a/.pi/skills/sce-validation/references/validation-result.md b/.pi/skills/sce-validation/references/validation-result.md deleted file mode 100644 index 569ec235..00000000 --- a/.pi/skills/sce-validation/references/validation-result.md +++ /dev/null @@ -1,186 +0,0 @@ -# Validation Result - -Return only one completed Markdown report using the applicable variant below. -Do not include unused sections, placeholders, YAML, or a fenced code block. - -The `Status` value must be exactly one of: - -- `validated` -- `failed` -- `blocked` - -The plan-file `## Validation Report` section is written separately using -`validation-report.md`. This file is the skill's return value to the invoking -workflow. - -## Validated variant - -# Validation Report - -**Status:** validated -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` - -## Commands run - -- `{command}` -> {passed} — {concise outcome summary} - -## Acceptance criteria - -- [x] AC1: {criterion statement} — {evidence} -- [x] AC2: {criterion statement} — {evidence} - -## Scaffolding removed - -- `{path}` — {why it was temporary} -- None. - -## Residual risks - -- {risk} -- None identified. - -## Context impact - -**Classification:** `{none | local | domain | root}` -**Affected areas:** `{comma-separated areas}` -**Required context:** - -- `{path or statement from the plan Context sync section}` - -{One or two sentences on why this classification fits the finished plan.} - -## Notes - -{Include only non-blocking information the invoking workflow should retain. -Omit this section when unnecessary.} - ---- - -## Failed variant - -This variant is a session handoff. Another agent or a later session must be -able to act from it alone. Write it as a prompt the user can paste forward, not -as a summary of the validation run. - -# Validation failed — handoff - -**Status:** failed -**Plan:** `{plan path}` -**Name:** `{plan name}` -**Tasks:** `{completed}/{total} complete` -**Date:** `{YYYY-MM-DD}` -**Validation report:** written to `{plan path}` - -## Goal for the next session - -Repair the unfinished validation so every acceptance criterion and full -validation command passes. Do not modify tests or product code inside a -`/validate` run to force green results; fix the implementation (or the plan) in -a normal work session, then rerun validation. - -## What failed - -- `{check or AC id}`: {problem} - - Evidence: {command output, exit summary, or inspection finding} - - Required action: {concrete repair or decision} - -## Acceptance criteria - -- [x] AC1: {criterion} — {evidence} -- [ ] AC2: {criterion} — {why unmet} - -## Commands run - -- `{command}` -> {passed | failed | not_run} — {concise outcome summary} - -## Constraints - -- All implementation tasks were already complete when validation ran. -- Validation did not modify tests, application code, or configuration to clear - failures. -- Durable context was not synchronized; plan context sync runs only after - validation succeeds. -- Prefer the plan at `{plan path}` and its Validation Report as the source of - recorded evidence. - -## Residual risks - -- {risk} -- None identified. - -## Recommended work - -1. {First concrete fix, with files or areas when known} -2. {Second concrete fix, or decision the user must make} -3. Rerun final validation after the fixes land: - -`/validate {plan path}` - -Do not stop after the repair. The plan is not finished until `/validate` -returns `validated` and plan context sync completes. - ---- - -## Blocked variant - -# Validation blocked - -**Status:** blocked -**Plan:** `{plan path when resolved}` -**Name:** `{plan name when resolved}` - -## Issues - -- **{issue id}** ({category}): {problem} - - Impact: {impact} - - Required: {decision or action} - -## Incomplete tasks - -- `{task id}` — {title} -- Omit this section when no incomplete tasks apply. - -## Candidates - -- `{candidate plan path}` -- Omit this section when plan resolution was not ambiguous. - -## Next step - -{Exactly one continuation, matching the blocker:} - -- Incomplete tasks: - -`/next-task {plan path}` - -- Ambiguous plan: - -`/validate {candidate path}` - -- Missing plan content or other blocker: state the decision required. Do not - invent a command. - ---- - -## Report rules - -- Name the exact `Plan:` path so every emitted command is runnable. -- Use **Status:** exactly `validated`, `failed`, or `blocked`. -- Never claim a check passed unless it ran successfully or the authorized - inspection confirmed it. -- Do not modify tests or product code to clear a failure; record it under - **What failed**. -- The failed variant must always end its **Recommended work** with - `/validate {plan path}` as the final step after repairs. -- The failed variant must be self-contained enough to hand to another session - without the original chat. -- Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. -- Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. -- Do not select or describe an unrelated next implementation task when status is - `validated`. -- Omit empty optional sections rather than writing placeholders. From 2aab6c8e162e1bd8b6c26257f0bd4b560e289be2 Mon Sep 17 00:00:00 2001 From: David Abram Date: Wed, 29 Jul 2026 23:15:18 +0200 Subject: [PATCH 19/21] pkl: Centralize workflow metadata and generation contracts Add a typed workflow catalog for shared identity and routing metadata. Enforce the exact 46-artifact inventory, reject stale workflow references, and cover failure cases with negative fixtures. Remove the stray rendered evaluation artifact and correct documentation for the shared four-package target model without changing generated output. Co-authored-by: SCE --- config/pkl/README.md | 16 +-- config/pkl/base/workflow-catalog.pkl | 51 ++++++++ config/pkl/check-generated.sh | 40 ++++++ config/pkl/rendered | 3 - config/pkl/renderers/claude-metadata.pkl | 13 +- .../fixtures/extra-artifact-check.pkl | 14 ++ .../forbidden-workflow-reference-check.pkl | 14 ++ .../fixtures/missing-artifact-check.pkl | 15 +++ .../renderers/generation-contract-check.pkl | 101 +++++++++++++++ .../pkl/renderers/metadata-coverage-check.pkl | 47 ++++--- config/pkl/renderers/opencode-content.pkl | 14 +- config/pkl/renderers/opencode-metadata.pkl | 17 ++- config/pkl/renderers/workflow-composite.pkl | 45 ++----- context/architecture.md | 13 +- ...29-cross-target-workflow-skill-packages.md | 4 +- context/glossary.md | 5 +- context/overview.md | 6 +- context/patterns.md | 10 +- .../strengthen-pkl-structure-foundation.md | 122 ++++++++++++++++++ 19 files changed, 442 insertions(+), 108 deletions(-) create mode 100644 config/pkl/base/workflow-catalog.pkl delete mode 100644 config/pkl/rendered create mode 100644 config/pkl/renderers/fixtures/extra-artifact-check.pkl create mode 100644 config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl create mode 100644 config/pkl/renderers/fixtures/missing-artifact-check.pkl create mode 100644 config/pkl/renderers/generation-contract-check.pkl create mode 100644 context/plans/strengthen-pkl-structure-foundation.md diff --git a/config/pkl/README.md b/config/pkl/README.md index 095f7cf7..6f71035d 100644 --- a/config/pkl/README.md +++ b/config/pkl/README.md @@ -4,7 +4,7 @@ Canonical generation pipeline for the four SCE workflows across OpenCode, Claude ## Ownership and target matrix -Author workflow behavior in: +`config/pkl/**` is the sole canonical authoring source consumed by generation and packaging. Author workflow behavior in: - `config/pkl/base/workflow-change-to-plan.pkl` - `config/pkl/base/workflow-next-task.pkl` @@ -15,18 +15,18 @@ Author workflow behavior in: Apply target-specific rendering and supported metadata under `config/pkl/renderers/`. Do not hand-edit generated artifacts. +The project-root `.pi/` workflow tree is the accepted behavioral reference used to review canonical behavior. It is not a second generation source: generators and packages consume `config/pkl/**`, not `.pi/`. + `config/pkl/generate.pkl` emits: | Target | Workflow Markdown | Retained non-Markdown | | --- | --- | --- | -| OpenCode | Four commands, eight self-contained skill packages, two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | -| Claude | Four thin commands and four self-contained workflow skill packages; no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | -| Pi | Four prompts and eight self-contained skill packages; no agent-role prompts | `extensions/sce/index.ts` | +| OpenCode | Four commands, four self-contained workflow skill packages (eight Markdown files), two thin routing agents | `lib/bash-policy-presets.json`, `plugins/{sce-bash-policy,sce-agent-trace}.ts`, `opencode.json` | +| Claude | Four thin commands and four self-contained workflow skill packages (eight Markdown files); no agents | `hooks/run-sce-or-show-install-guidance.sh`, `settings.json` | +| Pi | Four prompts and four self-contained workflow skill packages (eight Markdown files); no agent-role prompts | `extensions/sce/index.ts` | | SCE config | None | `config/schema/sce-config.schema.json` | -Pi and OpenCode skill packages include package-local `SKILL.md` files and their nested `references/` documents. Their generated trees remain self-contained; no skill depends on a sibling package. - -Pi and OpenCode consume the canonical eight multi-file phase packages, including YAML phase-result contracts under `references/`. Claude instead composes each canonical workflow into one target-specific package: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each Claude command invokes exactly its corresponding workflow skill, and each package contains exactly `SKILL.md` plus `references/output.md`. The entrypoint owns the complete phase sequence, internal statuses, waits and same-session resume behavior; `output.md` is the sole package reference and defines the workflow's human-visible gates and terminal Markdown layouts. Canonical phase contracts remain unchanged for Pi and OpenCode and are not emitted as Claude inter-skill handoffs. +OpenCode, Claude, and Pi each receive the same four workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Every package contains exactly `SKILL.md` plus `references/output.md`, for eight workflow Markdown files per target. Each command or prompt invokes exactly its corresponding workflow skill, and no skill depends on a sibling package. The workflow entrypoint owns the complete phase sequence, internal statuses, waits, and same-session resume behavior; `output.md` is the sole package reference and defines the workflow's human-visible gates and terminal Markdown layouts. Canonical phase modules remain authoring inputs under `config/pkl/base/` and are composed into these workflow packages rather than emitted as separate phase packages. The automated OpenCode profile, the generated `/handover` command, legacy bootstrap/handover/context-sync skills, Claude agents, and Pi agent-role prompts are removed surfaces. `config/automated/.opencode` and `config/.claude/agents` must remain absent. @@ -71,7 +71,7 @@ nix run .#pkl-check-generated The check: - rejects committed `config/.opencode`, `config/.claude`, `config/.pi`, `config/schema/sce-config.schema.json`, and `cli/assets/generated` outputs; -- evaluates `metadata-coverage-check.pkl` for exact inventories: four commands and eight phase-skill packages for OpenCode/Pi, four one-to-one workflow skill packages with exactly two files each for Claude, and two OpenCode agents; +- evaluates `metadata-coverage-check.pkl` for exact inventories: four entrypoints and four one-to-one workflow skill packages containing exactly `SKILL.md` and `references/output.md` for each target, plus two OpenCode agents; - generates twice into temporary directories and compares sorted SHA-256 inventories; - requires all generated target roots and the SCE config schema while rejecting removed surfaces such as `config/automated/.opencode` and `config/.claude/agents`; - prints the stable inventory count and digest without preserving generated files. diff --git a/config/pkl/base/workflow-catalog.pkl b/config/pkl/base/workflow-catalog.pkl new file mode 100644 index 00000000..82772067 --- /dev/null +++ b/config/pkl/base/workflow-catalog.pkl @@ -0,0 +1,51 @@ +/// Target-neutral workflow identity plus the small amount of target routing +/// metadata that varies by workflow. Content modules and renderers remain +/// responsible for workflow behavior and output formatting. +class WorkflowRecord { + commandSlug: String + skillSlug: String + title: String + description: String + argumentHint: String + openCodeAgentSlug: String + claudeAllowedTools: String +} + +workflows: Mapping = new Mapping { + ["change-to-plan"] = new WorkflowRecord { + commandSlug = "change-to-plan" + skillSlug = "sce-change-to-plan" + title = "SCE Change to Plan" + description = "Turn one change request into a scoped SCE plan in one self-contained workflow" + argumentHint = "" + openCodeAgentSlug = "shared-context-plan" + claudeAllowedTools = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" + } + ["next-task"] = new WorkflowRecord { + commandSlug = "next-task" + skillSlug = "sce-next-task" + title = "SCE Next Task" + description = "Review, approve, implement, verify, and synchronize one SCE plan task" + argumentHint = " [T0X] [approved]" + openCodeAgentSlug = "shared-context-code" + claudeAllowedTools = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" + } + ["validate"] = new WorkflowRecord { + commandSlug = "validate" + skillSlug = "sce-validate" + title = "SCE Validate" + description = "Validate one completed SCE plan and synchronize its durable context" + argumentHint = "" + openCodeAgentSlug = "shared-context-code" + claudeAllowedTools = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" + } + ["commit"] = new WorkflowRecord { + commandSlug = "commit" + skillSlug = "sce-commit" + title = "SCE Commit" + description = "Analyze staged changes and run the regular or explicit bypass commit workflow" + argumentHint = "[oneshot|skip] [commit context]" + openCodeAgentSlug = "shared-context-code" + claudeAllowedTools = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" + } +} diff --git a/config/pkl/check-generated.sh b/config/pkl/check-generated.sh index ce36e0cb..894108aa 100755 --- a/config/pkl/check-generated.sh +++ b/config/pkl/check-generated.sh @@ -20,6 +20,17 @@ if ! command -v pkl >/dev/null 2>&1; then exit 1 fi +forbidden_source_artifacts=( + "config/pkl/rendered" +) + +for path in "${forbidden_source_artifacts[@]}"; do + if [[ -e "$path" ]]; then + printf 'Accidental repository-local Pkl evaluation artifact exists at %s\n' "$path" >&2 + exit 1 + fi +done + legacy_paths=( "config/.opencode" "config/.claude" @@ -46,6 +57,35 @@ second_root="$tmp_dir/second" mkdir -p "$first_root" "$second_root" pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null +pkl eval config/pkl/renderers/generation-contract-check.pkl >/dev/null + +expect_pkl_fixture_failure() { + local fixture_path="$1" + local expected_diagnostic="$2" + local diagnostic + + if diagnostic="$(pkl eval "$fixture_path" 2>&1 >/dev/null)"; then + printf 'Negative Pkl fixture unexpectedly passed: %s\n' "$fixture_path" >&2 + exit 1 + fi + + if [[ "$diagnostic" != *"$expected_diagnostic"* ]]; then + printf 'Negative Pkl fixture failed without the expected diagnostic: %s\n%s\n' \ + "$fixture_path" "$diagnostic" >&2 + exit 1 + fi +} + +expect_pkl_fixture_failure \ + "config/pkl/renderers/fixtures/extra-artifact-check.pkl" \ + "generated artifact inventory does not match the exact expected path contract" +expect_pkl_fixture_failure \ + "config/pkl/renderers/fixtures/missing-artifact-check.pkl" \ + "generated artifact inventory does not match the exact expected path contract" +expect_pkl_fixture_failure \ + "config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl" \ + "generated workflow document contains a forbidden sibling-package reference or unresolved internalization token" + pkl eval -m "$first_root" config/pkl/generate.pkl >/dev/null pkl eval -m "$second_root" config/pkl/generate.pkl >/dev/null diff --git a/config/pkl/rendered b/config/pkl/rendered deleted file mode 100644 index 06e1e1a8..00000000 --- a/config/pkl/rendered +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rendered": "{\n \"$id\": \"https://sce.crocoder.dev/config.json\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"SCE Config\",\n \"description\": \"Canonical JSON Schema for global and repo-local sce/config.json files.\",\n \"type\": \"object\",\n \"properties\": {\n \"$schema\": {\n \"type\": \"string\",\n \"const\": \"https://sce.crocoder.dev/config.json\"\n },\n \"log_level\": {\n \"type\": \"string\",\n \"enum\": [\n \"error\",\n \"warn\",\n \"info\",\n \"debug\"\n ]\n },\n \"log_format\": {\n \"type\": \"string\",\n \"enum\": [\n \"text\",\n \"json\"\n ]\n },\n \"log_file\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"log_file_mode\": {\n \"type\": \"string\",\n \"enum\": [\n \"truncate\",\n \"append\"\n ]\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"workos_client_id\": {\n \"type\": \"string\"\n },\n \"policies\": {\n \"type\": \"object\",\n \"properties\": {\n \"attribution_hooks\": {\n \"type\": \"object\",\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n },\n \"database_retry\": {\n \"type\": \"object\",\n \"properties\": {\n \"local_db\": {\n \"type\": \"object\",\n \"properties\": {\n \"connection_open\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n },\n \"query\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n }\n },\n \"additionalProperties\": false\n },\n \"agent_trace_db\": {\n \"type\": \"object\",\n \"properties\": {\n \"connection_open\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n },\n \"query\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n }\n },\n \"additionalProperties\": false\n },\n \"auth_db\": {\n \"type\": \"object\",\n \"properties\": {\n \"connection_open\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n },\n \"query\": {\n \"type\": \"object\",\n \"properties\": {\n \"max_attempts\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"timeout_ms\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"initial_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max_backoff_ms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"max_attempts\",\n \"timeout_ms\",\n \"initial_backoff_ms\",\n \"max_backoff_ms\"\n ]\n }\n },\n \"additionalProperties\": false\n }\n },\n \"additionalProperties\": false\n },\n \"bash\": {\n \"type\": \"object\",\n \"properties\": {\n \"presets\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"enum\": [\n \"forbid-git-all\",\n \"forbid-git-commit\",\n \"use-pnpm-over-npm\",\n \"use-bun-over-npm\",\n \"use-nix-flake-over-cargo\"\n ]\n },\n \"uniqueItems\": true,\n \"allOf\": [\n {\n \"not\": {\n \"allOf\": [\n {\n \"contains\": {\n \"const\": \"use-pnpm-over-npm\"\n }\n },\n {\n \"contains\": {\n \"const\": \"use-bun-over-npm\"\n }\n }\n ]\n }\n }\n ]\n },\n \"custom\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"not\": {\n \"enum\": [\n \"forbid-git-all\",\n \"forbid-git-commit\",\n \"use-pnpm-over-npm\",\n \"use-bun-over-npm\",\n \"use-nix-flake-over-cargo\"\n ]\n }\n },\n \"match\": {\n \"type\": \"object\",\n \"properties\": {\n \"argv_prefix\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"minItems\": 1\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"argv_prefix\"\n ]\n },\n \"message\": {\n \"type\": \"string\",\n \"minLength\": 1\n }\n },\n \"additionalProperties\": false,\n \"required\": [\n \"id\",\n \"match\",\n \"message\"\n ]\n }\n }\n },\n \"additionalProperties\": false\n }\n },\n \"additionalProperties\": false\n }\n },\n \"additionalProperties\": false,\n \"dependentRequired\": {\n \"log_file_mode\": [\n \"log_file\"\n ]\n }\n}\n" -} diff --git a/config/pkl/renderers/claude-metadata.pkl b/config/pkl/renderers/claude-metadata.pkl index 6effbaac..37b30100 100644 --- a/config/pkl/renderers/claude-metadata.pkl +++ b/config/pkl/renderers/claude-metadata.pkl @@ -1,12 +1,7 @@ -import "workflow-composite.pkl" as composite +import "../base/workflow-catalog.pkl" as catalog commandAllowedTools = new Mapping { - ["next-task"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" - ["change-to-plan"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill" - ["validate"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" - ["commit"] = "Task, Read, Glob, Grep, Edit, Write, Question, Skill, Bash" + for (slug, workflow in catalog.workflows) { + [slug] = workflow.claudeAllowedTools + } } - -/// The workflow slugs are target-neutral; Claude re-exports the shared mapping -/// so command routing and coverage checks read it from one place. -workflowSkillSlugByCommand = composite.workflowSkillSlugByCommand diff --git a/config/pkl/renderers/fixtures/extra-artifact-check.pkl b/config/pkl/renderers/fixtures/extra-artifact-check.pkl new file mode 100644 index 00000000..da8bb718 --- /dev/null +++ b/config/pkl/renderers/fixtures/extra-artifact-check.pkl @@ -0,0 +1,14 @@ +import "../generation-contract-check.pkl" as contract + +local artifactsWithExtraPath = new Mapping { + for (path, text in contract.generatedArtifacts) { + [path] = text + } + ["config/.opencode/unexpected-artifact.txt"] = "fixture" +} + +result = if ( + artifactsWithExtraPath.length == contract.expectedArtifactPaths.length + && contract.expectedArtifactPaths.every((path, _) -> artifactsWithExtraPath.containsKey(path)) +) "negative fixture unexpectedly matched" +else error("generated artifact inventory does not match the exact expected path contract") diff --git a/config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl b/config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl new file mode 100644 index 00000000..7af58fac --- /dev/null +++ b/config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl @@ -0,0 +1,14 @@ +import "../generation-contract-check.pkl" as contract + +local documentsWithForbiddenReference = new Mapping { + for (path, text in contract.workflowDocuments) { + [path] = if (path == "config/.opencode/skills/sce-next-task/SKILL.md") + "\(text)\nInvoke `sce-plan-review`." + else text + } +} + +result = if ( + documentsWithForbiddenReference.every((_, text) -> !text.contains("sce-plan-review")) +) "negative fixture unexpectedly contained no forbidden reference" +else error("generated workflow document contains a forbidden sibling-package reference or unresolved internalization token") diff --git a/config/pkl/renderers/fixtures/missing-artifact-check.pkl b/config/pkl/renderers/fixtures/missing-artifact-check.pkl new file mode 100644 index 00000000..9c2a96d4 --- /dev/null +++ b/config/pkl/renderers/fixtures/missing-artifact-check.pkl @@ -0,0 +1,15 @@ +import "../generation-contract-check.pkl" as contract + +local artifactsWithMissingPath = new Mapping { + for (path, text in contract.generatedArtifacts) { + when (path != "config/schema/sce-config.schema.json") { + [path] = text + } + } +} + +result = if ( + artifactsWithMissingPath.length == contract.expectedArtifactPaths.length + && contract.expectedArtifactPaths.every((path, _) -> artifactsWithMissingPath.containsKey(path)) +) "negative fixture unexpectedly matched" +else error("generated artifact inventory does not match the exact expected path contract") diff --git a/config/pkl/renderers/generation-contract-check.pkl b/config/pkl/renderers/generation-contract-check.pkl new file mode 100644 index 00000000..784af9e6 --- /dev/null +++ b/config/pkl/renderers/generation-contract-check.pkl @@ -0,0 +1,101 @@ +import "../generate.pkl" as generated +import "opencode-content.pkl" as opencode +import "claude-content.pkl" as claude +import "pi-content.pkl" as pi + +/// Build the expected inventory from each target's independently checked +/// document inventory plus the retained non-workflow assets. This deliberately +/// does not iterate `generate.pkl`'s output assembly. +hidden expectedArtifactPaths = new Mapping { + for (_, document in opencode.agents) { + ["config/.opencode/agent/\(document.title).md"] = true + } + for (slug, _ in opencode.commands) { + ["config/.opencode/command/\(slug).md"] = true + } + for (path, _ in opencode.skillDocuments) { + ["config/.opencode/skills/\(path)"] = true + } + ["config/.opencode/lib/bash-policy-presets.json"] = true + ["config/.opencode/plugins/sce-bash-policy.ts"] = true + ["config/.opencode/plugins/sce-agent-trace.ts"] = true + ["config/.opencode/opencode.json"] = true + + for (slug, _ in claude.commands) { + ["config/.claude/commands/\(slug).md"] = true + } + for (path, _ in claude.skillDocuments) { + ["config/.claude/skills/\(path)"] = true + } + ["config/.claude/settings.json"] = true + ["config/.claude/hooks/run-sce-or-show-install-guidance.sh"] = true + + for (slug, _ in pi.commands) { + ["config/.pi/prompts/\(slug).md"] = true + } + for (path, _ in pi.skillDocuments) { + ["config/.pi/skills/\(path)"] = true + } + ["config/.pi/extensions/sce/index.ts"] = true + + ["config/schema/sce-config.schema.json"] = true +} + +hidden generatedArtifacts = new Mapping { + for (path, artifact in generated.output.files) { + [path] = artifact.text + } +} + +hidden workflowDocuments = new Mapping { + for (path, document in opencode.skillDocuments) { + ["config/.opencode/skills/\(path)"] = document.text + } + for (path, document in claude.skillDocuments) { + ["config/.claude/skills/\(path)"] = document.text + } + for (path, document in pi.skillDocuments) { + ["config/.pi/skills/\(path)"] = document.text + } +} + +local forbiddenWorkflowReferenceTokens = new Listing { + "sce-context-load" + "sce-plan-authoring" + "sce-plan-review" + "sce-task-execution" + "sce-task-context-sync" + "sce-validation" + "sce-plan-context-sync" + "sce-atomic-commit" + "references/context-brief.yaml" + "references/authoring-contract.yaml" + "references/readiness-contract.yaml" + "references/execution-contract.yaml" + "references/commit-contract.yaml" + "references/implementation-gate.md" + "references/plan-summary.md" + "references/validation-result.md" + "references/sync-report.md" + "references/commit-message-style.md" +} + +local assertExactArtifactPaths = (actual: Mapping) -> + if ( + actual.length == expectedArtifactPaths.length + && expectedArtifactPaths.every((path, _) -> actual.containsKey(path)) + ) "generated artifact inventory: exactly \(expectedArtifactPaths.length) paths" + else error("generated artifact inventory does not match the exact expected path contract") + +local assertWorkflowReferences = (documents: Mapping) -> + if ( + documents.every((_, text) -> + forbiddenWorkflowReferenceTokens.every((token) -> !text.contains(token)) + ) + ) "generated workflow references: fully internalized" + else error("generated workflow document contains a forbidden sibling-package reference or unresolved internalization token") + +contractChecks { + ["artifact-paths"] = assertExactArtifactPaths.apply(generatedArtifacts) + ["workflow-references"] = assertWorkflowReferences.apply(workflowDocuments) +} diff --git a/config/pkl/renderers/metadata-coverage-check.pkl b/config/pkl/renderers/metadata-coverage-check.pkl index bbc0c2a6..21494662 100644 --- a/config/pkl/renderers/metadata-coverage-check.pkl +++ b/config/pkl/renderers/metadata-coverage-check.pkl @@ -1,35 +1,34 @@ +import "../base/workflow-catalog.pkl" as catalog import "opencode-content.pkl" as opencode import "claude-content.pkl" as claude -import "claude-metadata.pkl" as claudeMetadata import "pi-content.pkl" as pi -local expectedCommandSlugs = Set( - "change-to-plan", - "next-task", - "validate", - "commit" -) +local expectedCommandSlugs = new Mapping { + for (slug, _ in catalog.workflows) { + [slug] = true + } +} -local expectedAgentSlugs = Set( - "shared-context-plan", - "shared-context-code" -) +local expectedAgentSlugs = new Mapping { + ["shared-context-plan"] = true + ["shared-context-code"] = true +} -local expectedWorkflowSkillByCommand = claudeMetadata.workflowSkillSlugByCommand +local expectedWorkflowSkillByCommand = new Mapping { + for (slug, workflow in catalog.workflows) { + [slug] = workflow.skillSlug + } +} /// A collapsed target renders each workflow as one package with one entrypoint /// and one user-visible Markdown output reference. Exact coverage rejects stale /// phase packages and any additional package-local references. -local expectedWorkflowSkillDocumentPaths = Set( - "sce-change-to-plan/SKILL.md", - "sce-change-to-plan/references/output.md", - "sce-next-task/SKILL.md", - "sce-next-task/references/output.md", - "sce-validate/SKILL.md", - "sce-validate/references/output.md", - "sce-commit/SKILL.md", - "sce-commit/references/output.md" -) +local expectedWorkflowSkillDocumentPaths = new Mapping { + for (_, workflow in catalog.workflows) { + ["\(workflow.skillSlug)/SKILL.md"] = true + ["\(workflow.skillSlug)/references/output.md"] = true + } +} local opencodeAgents = new Mapping { for (slug, document in opencode.agents) { @@ -67,10 +66,10 @@ local piSkillDocuments = new Mapping { } } -local assertExactKeys = (actual: Mapping, expected: Set, label: String) -> +local assertExactKeys = (actual: Mapping, expected: Mapping, label: String) -> if ( actual.length == expected.length - && expected.every((key) -> actual.containsKey(key)) + && expected.every((key, _) -> actual.containsKey(key)) ) "\(label): complete" else error("\(label) inventory does not match the canonical workflow matrix") diff --git a/config/pkl/renderers/opencode-content.pkl b/config/pkl/renderers/opencode-content.pkl index 5ebe5a10..b9b5ac84 100644 --- a/config/pkl/renderers/opencode-content.pkl +++ b/config/pkl/renderers/opencode-content.pkl @@ -1,25 +1,19 @@ +import "../base/workflow-catalog.pkl" as catalog import "common.pkl" as common import "opencode-metadata.pkl" as metadata import "workflow-composite.pkl" as workflowResults local generatedOpenCodePluginPathsJson = common.sceGeneratedOpenCodePluginPathsJson -/// Commands routed by a thin agent declare it here. -local commandAgentBySlug = new Mapping { - ["change-to-plan"] = "Shared Context Plan" - ["next-task"] = "Shared Context Code" - ["validate"] = "Shared Context Code" - ["commit"] = "Shared Context Code" -} - local commandAgentLine = (slug: String) -> - if (commandAgentBySlug.containsKey(slug)) "agent: \"\(commandAgentBySlug[slug])\"\n" else "" + let (agentSlug = catalog.workflows[slug].openCodeAgentSlug) + "agent: \"\(metadata.agentDisplayNames[agentSlug])\"\n" /// One command declares one workflow skill as both its entry skill and its whole /// skill chain. The skill owns every phase, so there is no sibling package to /// hand off to. local commandSkillLines = (slug: String) -> - let (skillSlug = workflowResults.workflowSkillSlugByCommand[slug]) + let (skillSlug = catalog.workflows[slug].skillSlug) "entry-skill: \"\(skillSlug)\"\nskills:\n - \"\(skillSlug)\"\n" local agentFrontmatterBySlug = new Mapping { diff --git a/config/pkl/renderers/opencode-metadata.pkl b/config/pkl/renderers/opencode-metadata.pkl index 16cbf3f1..6808949a 100644 --- a/config/pkl/renderers/opencode-metadata.pkl +++ b/config/pkl/renderers/opencode-metadata.pkl @@ -1,3 +1,14 @@ +import "../base/workflow-catalog.pkl" as catalog + +local workflowSkillPermissionLines = (agentSlug: String) -> + (new Listing { + for (_, workflow in catalog.workflows) { + when (workflow.openCodeAgentSlug == agentSlug) { + " \"\(workflow.skillSlug)\": allow" + } + } + }).join("\n") + agentDescriptions = new Mapping { ["shared-context-plan"] = "Plans a change into atomic tasks in context/plans without touching application code." ["shared-context-code"] = "Executes one approved SCE task, validates behavior, and syncs context." @@ -40,7 +51,7 @@ permission: doom_loop: ask skill: "*": ask - "sce-change-to-plan": allow +\(workflowSkillPermissionLines.apply("shared-context-plan")) """ ["shared-context-code"] = """ permission: @@ -63,9 +74,7 @@ permission: doom_loop: ask skill: "*": ask - "sce-next-task": allow - "sce-validate": allow - "sce-commit": allow +\(workflowSkillPermissionLines.apply("shared-context-code")) """ } diff --git a/config/pkl/renderers/workflow-composite.pkl b/config/pkl/renderers/workflow-composite.pkl index 60489951..7fe53666 100644 --- a/config/pkl/renderers/workflow-composite.pkl +++ b/config/pkl/renderers/workflow-composite.pkl @@ -2,6 +2,7 @@ import "../base/workflow-change-to-plan.pkl" as changeToPlan import "../base/workflow-next-task.pkl" as nextTask import "../base/workflow-validate.pkl" as validate import "../base/workflow-commit.pkl" as commit +import "../base/workflow-catalog.pkl" as catalog import "../base/workflow-content.pkl" as model /// A skill is the unit of durable control flow. Compose the canonical phase @@ -9,11 +10,12 @@ import "../base/workflow-content.pkl" as model /// phase results between sibling skills. Composition is target-neutral: targets /// differ only in the frontmatter lines their skills and commands support. class CompositeWorkflow { - slug: String - skillSlug: String - title: String - description: String - argumentHint: String + identity: catalog.WorkflowRecord + slug: String = identity.commandSlug + skillSlug: String = identity.skillSlug + title: String = identity.title + description: String = identity.description + argumentHint: String = identity.argumentHint command: model.WorkflowDocument phaseDocuments: Listing internalDocuments: Listing @@ -443,21 +445,8 @@ Committed {commit-hash} Present Git's failure unchanged and stop without retrying. """ -/// One command routes to one workflow-level package. Phase-skill names are not -/// part of any target's generated inventory. -workflowSkillSlugByCommand = new Mapping { - ["change-to-plan"] = "sce-change-to-plan" - ["next-task"] = "sce-next-task" - ["validate"] = "sce-validate" - ["commit"] = "sce-commit" -} - local changeWorkflow = new CompositeWorkflow { - slug = "change-to-plan" - skillSlug = workflowSkillSlugByCommand["change-to-plan"] - title = "SCE Change to Plan" - description = "Turn one change request into a scoped SCE plan in one self-contained workflow" - argumentHint = "" + identity = catalog.workflows["change-to-plan"] command = changeToPlan.workflow.command.document phaseDocuments = new Listing { new model.WorkflowDocument { path = "sce-context-load"; text = changeToPlan.workflow.skills["sce-context-load"].documents["SKILL.md"].text } @@ -470,11 +459,7 @@ local changeWorkflow = new CompositeWorkflow { } local nextWorkflow = new CompositeWorkflow { - slug = "next-task" - skillSlug = workflowSkillSlugByCommand["next-task"] - title = "SCE Next Task" - description = "Review, approve, implement, verify, and synchronize one SCE plan task" - argumentHint = " [T0X] [approved]" + identity = catalog.workflows["next-task"] command = nextTask.workflow.command.document phaseDocuments = new Listing { new model.WorkflowDocument { path = "sce-plan-review"; text = nextTask.workflow.skills["sce-plan-review"].documents["SKILL.md"].text } @@ -486,11 +471,7 @@ local nextWorkflow = new CompositeWorkflow { } local validateWorkflow = new CompositeWorkflow { - slug = "validate" - skillSlug = workflowSkillSlugByCommand["validate"] - title = "SCE Validate" - description = "Validate one completed SCE plan and synchronize its durable context" - argumentHint = "" + identity = catalog.workflows["validate"] command = validate.workflow.command.document phaseDocuments = new Listing { new model.WorkflowDocument { path = "sce-validation"; text = validate.workflow.skills["sce-validation"].documents["SKILL.md"].text } @@ -503,11 +484,7 @@ local validateWorkflow = new CompositeWorkflow { } local commitWorkflow = new CompositeWorkflow { - slug = "commit" - skillSlug = workflowSkillSlugByCommand["commit"] - title = "SCE Commit" - description = "Analyze staged changes and run the regular or explicit bypass commit workflow" - argumentHint = "[oneshot|skip] [commit context]" + identity = catalog.workflows["commit"] command = commit.workflow.command.document phaseDocuments = new Listing { new model.WorkflowDocument { path = "sce-atomic-commit"; text = commit.workflow.skills["sce-atomic-commit"].documents["SKILL.md"].text } diff --git a/context/architecture.md b/context/architecture.md index 77cb5dfa..85fcf79a 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -9,6 +9,7 @@ Authored config content is standardized around one canonical Pkl source model wi Current location for canonical workflow content primitives: - `config/pkl/base/workflow-content.pkl` (workflow command and self-contained skill-package document model, including deterministic package-relative nested references) +- `config/pkl/base/workflow-catalog.pkl` (typed four-workflow catalog owning command and skill slugs, titles, descriptions, argument hints, OpenCode routing roles, and Claude allowed-tool metadata) - `config/pkl/base/workflow-change-to-plan.pkl` (canonical `/change-to-plan` package with the command plus self-contained `sce-context-load` and `sce-plan-authoring` skill/reference documents mirrored from the project-root `.pi/` baseline) - `config/pkl/base/workflow-next-task.pkl` (canonical `/next-task` package with self-contained `sce-plan-review` and `sce-task-execution` documents plus the task instance from the shared context-sync skeleton) - `config/pkl/base/workflow-validate.pkl` (canonical `/validate` package with the self-contained `sce-validation` documents plus the plan instance from the shared context-sync skeleton) @@ -27,8 +28,9 @@ Current target renderer helper modules: - `config/pkl/renderers/opencode-metadata.pkl` - `config/pkl/renderers/claude-metadata.pkl` - `config/pkl/renderers/metadata-coverage-check.pkl` +- `config/pkl/renderers/generation-contract-check.pkl` - `config/pkl/generate.pkl` (single multi-file generation entrypoint) -- `config/pkl/check-generated.sh` (dev-shell integration check for two-pass deterministic temporary inventories, required outputs, and forbidden repository generated paths) +- `config/pkl/check-generated.sh` (dev-shell integration check for two-pass deterministic temporary inventories, required outputs, forbidden repository generated paths, and the stray repository-local `config/pkl/rendered` evaluation artifact) - `nix flake check` / `checks..{cli-tests,cli-clippy,cli-fmt,pkl-generated,npm-bun-tests,npm-biome-check,npm-biome-format,config-lib-bun-tests,config-lib-biome-check,config-lib-biome-format,workflow-actionlint}` plus Linux-only `flatpak-static-validation`, `cargo-sources-parity`, and `flatpak-manifest-parity` (root-flake checks for CLI behavior, ephemeral Pkl generation, JS validation, workflow linting, and lightweight Flatpak validation) - `config-lib-bun-tests` executes from `config/lib/` while using a repo-shaped copied source subset that also includes `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden fixture coverage (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). @@ -39,15 +41,16 @@ Renderer modules apply target-specific metadata/frontmatter rules while reusing - All three renderers consume the four canonical workflow packages as behavior sources and emit the same four workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Each thin command or prompt invokes exactly one corresponding workflow skill. - Per-target differences are confined to frontmatter and the surrounding non-workflow outputs. The manual OpenCode renderer adds `agent`, `entry-skill`, and a one-entry `skills` list to command frontmatter, adds `compatibility: opencode` to each package entrypoint, and emits two thin routing agents whose `skill:` permission allowlists name only the four workflow slugs. The Claude renderer adds `compatibility: claude` plus `allowed-tools:` and emits no agents; Claude settings and the hook helper remain separate retained outputs. The Pi renderer adds no frontmatter to either prompts or skills. - Pi renderer consumes the same shared workflow composition as OpenCode and Claude. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). -- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions, the phase-internalization substitution tables, the four output layouts, and the target-neutral command-to-workflow-skill slug mapping. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and its `allowed-tools` line for commands. +- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow behavior definitions, phase-internalization substitution tables, and four output layouts, while each composite looks up its typed identity in `config/pkl/base/workflow-catalog.pkl`. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and a catalog-derived `allowed-tools` line for commands. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). -- Target-specific metadata tables remain isolated in their renderer modules. OpenCode metadata owns only thin-agent presentation, permissions, and compatibility; Claude metadata owns command tools and re-exports the shared command-to-workflow-skill slug mapping from `workflow-composite.pkl`. Pi has no metadata module because it adds no target-specific frontmatter. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts each target's exact current inventory—four commands (Pi: prompts), four two-file workflow packages per target, and two OpenCode agents—through the target-neutral `expectedWorkflowSkillDocumentPaths`, then verifies every command's one-to-one workflow-skill route for all three targets through the target-labelled `assertCommandRoute(target, slug, document)`, and forces every rendered document and target metadata lookup to evaluate. +- Target renderers remain responsible for formatting target-supported metadata. OpenCode metadata owns thin-agent presentation and compatibility while deriving workflow permission lines from catalog role assignments; OpenCode command routing derives the same role and skill identity from the catalog. Claude metadata derives command tools from catalog records. Pi has no metadata module because it adds no target-specific frontmatter. +- `config/pkl/renderers/metadata-coverage-check.pkl` derives command and two-file workflow-package expectations from the typed catalog, asserts each target's exact current inventory—four commands (Pi: prompts), four two-file workflow packages per target, and two OpenCode agents—then verifies every command's one-to-one workflow-skill route for all three targets through the target-labelled `assertCommandRoute(target, slug, document)`, and forces every rendered document and target metadata lookup to evaluate. +- `config/pkl/renderers/generation-contract-check.pkl` independently derives the complete expected artifact paths from those target document inventories plus explicitly retained non-workflow assets, compares them with `generate.pkl`'s `output.files`, and requires exactly 46 paths. It also scans every generated workflow package document for stale phase-skill slugs and package-local reference tokens that should have been removed by composite internalization. Checked-in negative fixtures prove that deterministic extra and missing artifacts and a forbidden workflow reference fail the contract. - OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; every target's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. - `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, four two-file workflow skill packages, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four thin workflow prompts, four two-file workflow skill packages, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. -- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks cover each target surface and the SCE schema; forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. +- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects the repository-local `config/pkl/rendered` evaluation artifact before generation, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata and generation contracts, confirms the extra/missing/reference negative fixtures fail with their contract diagnostics, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks remain fast surface diagnostics; the Pkl contract owns exact complete-path coverage, while forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. Generated authored classes: diff --git a/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md b/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md index 52062cc3..2c882547 100644 --- a/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md +++ b/context/decisions/2026-07-29-cross-target-workflow-skill-packages.md @@ -27,8 +27,8 @@ Keeping the collapse in the renderer rather than the canonical base preserves th - No target emits `sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, or `sce-atomic-commit` as a package. Those names now denote canonical authoring modules and internal phases only. - Per-target generated workflow inventory is four entrypoints plus eight skill Markdown files across four packages. OpenCode adds its two routing agents; Pi retains its extension; Claude retains settings and hooks. -- `config/pkl/renderers/workflow-composite.pkl` owns `workflowSkillSlugByCommand` for all targets; `claude-metadata.pkl` re-exports it. -- `config/pkl/renderers/metadata-coverage-check.pkl` asserts the workflow-package inventory and single-skill command route for all three targets through the target-neutral `expectedWorkflowSkillByCommand`, `expectedWorkflowSkillDocumentPaths`, and `assertCommandRoute(target, slug, document)`. +- `config/pkl/base/workflow-catalog.pkl` owns the four workflows' shared identity plus OpenCode role and Claude allowed-tool metadata; composite, target-routing, permission, and coverage modules derive their workflow matrices from it. +- `config/pkl/renderers/metadata-coverage-check.pkl` derives `expectedWorkflowSkillByCommand` and `expectedWorkflowSkillDocumentPaths` from that catalog, then asserts the workflow-package inventory and single-skill command route for all three targets through `assertCommandRoute(target, slug, document)`. - OpenCode command frontmatter still carries `entry-skill` and `skills`, now naming one skill in both. - Claude's generated output is unchanged by this decision; its byte-identity was verified across the change. - Stale installed phase-skill directories in existing checkouts are handled by the existing setup remove-and-replace policy for the whole target directory (`context/sce/setup-no-backup-policy-seam.md`). No migration code exists. diff --git a/context/glossary.md b/context/glossary.md index 4ffda693..ca3e9c49 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -1,6 +1,6 @@ # Glossary -- `pkl-check-generated`: Flake app exposed as `nix run .#pkl-check-generated`; canonical ephemeral-generation check that rejects committed target/schema/mirror outputs, evaluates exact workflow-document coverage, generates twice into temporary roots, and compares sorted SHA-256 inventories. +- `pkl-check-generated`: Flake app exposed as `nix run .#pkl-check-generated`; canonical ephemeral-generation check that rejects committed target/schema/mirror outputs, evaluates exact workflow metadata and the complete 46-path generated artifact contract, rejects stale sibling-package references or unresolved internalization tokens, proves extra/missing/reference failures through negative fixtures, generates twice into temporary roots, and compares sorted SHA-256 inventories. - `repo-level verification preference`: Current repository guidance that contributor-facing validation/check flows should prefer `nix flake check`; direct Cargo verification commands are secondary and used only when explicitly requested or for narrow targeted debugging, while `cargo fmt` remains the explicit autofix path. - lightweight post-task verification baseline: Required quick checks after each completed task in this repo: `nix run .#pkl-check-generated` and `nix flake check`. - disposable plan lifecycle: Policy where `context/plans/` holds active execution artifacts only; completed plans are disposable and durable outcomes must be reflected in current-state context files and/or `context/decisions/`. @@ -10,7 +10,8 @@ - `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. - `Pi workflow package`: Generated Pi workflow surface consisting of one thin prompt in `config/.pi/prompts/` plus the one workflow skill package under `config/.pi/skills/` that the prompt routes to, containing exactly `SKILL.md` and `references/output.md`. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. - `workflow skill package`: One of the four renderer-composed packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`) emitted for every target. Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Its only other file is `references/output.md`. The canonical phase modules remain authoring inputs to composition and are not generated as packages for any target. -- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite workflow definitions, the phase-internalization substitution tables, and the command-to-workflow-skill slug mapping. All three targets render through it, parameterized only by the extra frontmatter each supports. +- `workflow catalog`: The typed mapping in `config/pkl/base/workflow-catalog.pkl` that declares each of the four workflows once and owns its command slug, skill slug, title, description, argument hint, OpenCode routing role, and Claude allowed tools. Composite identity, OpenCode routing/permissions, Claude tool frontmatter, and metadata coverage derive from these records; behavior remains in canonical phase modules and formatting remains renderer-owned. +- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite behavior definitions and phase-internalization substitution tables while looking up shared workflow identity in the workflow catalog. All three targets render through it, parameterized only by the extra frontmatter each supports. - `canonical phase module`: One of the eight phase definitions in `config/pkl/base/workflow-*.pkl` (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, `sce-atomic-commit`). Each is the single behavioral source for its phase and an authoring input to the composite renderer. Since 2026-07-29 no target generates them as installable skill packages; the names denote canonical source and the internal phases inside a composed `SKILL.md`. - `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. - `workflow output reference`: The required `references/output.md` in every workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. diff --git a/context/overview.md b/context/overview.md index 8437ba97..3d7ced5e 100644 --- a/context/overview.md +++ b/context/overview.md @@ -1,6 +1,6 @@ # Overview -This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. Generated target layouts are ephemeral: repository builds consume a pre-Cargo generated payload through `SCE_CLI_GENERATED_INPUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` validates exact metadata coverage plus repeatable temporary inventories, and `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. +This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. One typed workflow catalog owns the four workflows' shared identity and target routing metadata, while canonical phase modules own behavior and target renderers own formatting. Generated target layouts are ephemeral: repository builds consume a pre-Cargo generated payload through `SCE_CLI_GENERATED_INPUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` enforces the exact 46-path artifact contract, exact workflow metadata/package coverage, fully internalized workflow references, and repeatable temporary inventories; `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. It also includes a Rust CLI (`sce`) for Shared Context Engineering workflows: auth, config inspection, setup, doctor, agent-trace hooks, bash-policy evaluation, and trace database inspection. See `context/architecture.md` for module-level boundaries and `context/context-map.md` for the full domain file index. @@ -54,7 +54,7 @@ The current supported automated release target matrix is `x86_64-unknown-linux-m The downstream publish-stage implementation is now complete for both registries: `.github/workflows/publish-crates.yml` publishes the checked-in crate version after `.version`/tag/Cargo parity checks, and `.github/workflows/publish-npm.yml` publishes the checked-in npm package after `.version`/tag/npm parity checks plus verification of the canonical `sce-v-npm.tgz` GitHub release asset. The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. -Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four workflow entrypoints and their four skill packages rather than in agent bodies. Each agent's `skill:` permission allowlist names exactly the workflow slugs for its role: `sce-change-to-plan` for Plan; `sce-next-task`, `sce-validate`, and `sce-commit` for Code. +Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four workflow entrypoints and their four skill packages rather than in agent bodies. `config/pkl/base/workflow-catalog.pkl` assigns each workflow to its role, and OpenCode command routing plus each agent's `skill:` permission allowlist derive from those records: `sce-change-to-plan` for Plan; `sce-next-task`, `sce-validate`, and `sce-commit` for Code. The canonical workflow definitions remain phase-decomposed as authoring source: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. No target generates those phase modules as packages. All three consume them as inputs to the shared `workflow-composite.pkl` renderer, which composes each workflow into one skill package. Every target preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command or Pi prompt invokes exactly one corresponding skill, and OpenCode command frontmatter names that single skill as both `entry-skill` and the whole `skills` chain. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. No target emits phase-skill packages or inter-skill machine contracts; phase statuses stay internal to one skill invocation. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. @@ -70,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. OpenCode, Claude, and Pi all compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer, which is parameterized only by the extra frontmatter each target supports. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Keep command slug, skill slug, title, description, argument hint, OpenCode role, and Claude allowed tools in the typed `workflow-catalog.pkl`. OpenCode, Claude, and Pi all compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer, which is parameterized only by the extra frontmatter each target supports. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. diff --git a/context/patterns.md b/context/patterns.md index c86786ba..4d9d5604 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -50,16 +50,18 @@ ## Pkl renderer layering - Keep the four target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with package primitives in `workflow-content.pkl` and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. +- Declare the four workflows' command slug, skill slug, title, description, argument hint, OpenCode routing role, and Claude allowed tools exactly once in the typed `config/pkl/base/workflow-catalog.pkl`. Composite, target-routing, permission, and coverage consumers must iterate or look up those records rather than maintain parallel four-workflow matrices. - Keep cross-target generated-config primitives in focused base modules under `config/pkl/base/` and re-export them through `config/pkl/renderers/common.pkl` when multiple renderers need the same contract. - Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. - Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Duplicating the internalization substitution tables per target would guarantee drift between targets whose composed text is meant to be identical. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. - Compose each canonical workflow into one workflow-level skill package for every generated target; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. The canonical phase packages under `config/pkl/base/` remain authoring inputs to that composition, not a generated output surface for any target. -- Keep shared renderer contracts and only truly shared description maps in `config/pkl/renderers/common.pkl`. +- Keep shared renderer document and plugin-registration contracts in `config/pkl/renderers/common.pkl`; workflow identity metadata belongs in the typed workflow catalog rather than renderer-local description or routing maps. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi needs no metadata module because it adds no target-specific frontmatter. -- Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: `agent` plus `entry-skill` and a `skills` chain, both naming that command's single workflow skill. Derive the slug from the shared `workflowSkillSlugByCommand` mapping rather than restating it per command. -- Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard for command slugs, OpenCode agents, skill entrypoints, and every package-local reference path, plus a per-target one-to-one command-to-workflow-skill route assertion; run it whenever workflow documents or target metadata change. +- Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: catalog-derived `agent`, `entry-skill`, and a `skills` chain naming that command's single workflow skill. Derive agent permission allowlists from the same catalog role assignments. +- Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard deriving command slugs, skill entrypoints, and package-local workflow paths from the typed catalog, while independently retaining the expected OpenCode agent inventory and per-target one-to-one command-to-workflow-skill route assertions; run it whenever workflow documents or target metadata change. +- Keep `config/pkl/renderers/generation-contract-check.pkl` independent of `generate.pkl` output assembly when deriving expected paths: build the exact target paths from renderer document inventories, name retained non-workflow assets explicitly, compare against all `output.files`, and reject stale phase-skill slugs or package-local reference tokens in generated workflow documents. Preserve controlled negative fixtures for extra paths, missing paths, and forbidden references. - Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Composition is the exception: a collapsed target's renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided every canonical gate, branch, write, and continuation retains exactly one owner in that skill. When a change collapses one target, the targets already collapsed must keep byte-identical output; verify by generating into temp roots before and after and diffing their subtrees. - Every target's commands (Pi: prompts) must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. - A workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. @@ -77,7 +79,7 @@ - Use `config/pkl/generate.pkl` as the single generation module for authored config outputs. Flatten self-contained workflow skill documents as `{skill slug}/{package-relative path}` so nested references are emitted deterministically without sibling-package dependencies. - Use `config/pkl/README.md` as the contributor-facing runbook for prerequisites, ownership boundaries, regeneration steps, and troubleshooting. - Run multi-file generation only into an explicit temporary output root, for example `nix run .#pkl-generate -- "$(mktemp -d)"`; never evaluate with `-m .`. -- Run ephemeral generation validation through `nix run .#pkl-check-generated`; it wraps the dev-shell script, rejects committed target/schema/mirror outputs, evaluates exact metadata coverage, generates twice into temporary directories, and compares sorted SHA-256 inventories while requiring all supported target roots. +- Run ephemeral generation validation through `nix run .#pkl-check-generated`; it wraps the dev-shell script, rejects committed target/schema/mirror outputs, evaluates exact metadata plus the complete 46-path artifact/reference contract and its negative fixtures, generates twice into temporary directories, and compares sorted SHA-256 inventories while requiring all supported target roots. - Keep this contract anchored to the root `nix flake check` `pkl-generated` derivation. Removed target paths are forbidden repository artifacts even though the same path names remain valid inside temporary payload roots. - Treat `nix run .#pkl-check-generated` and `nix flake check` as the lightweight post-task verification baseline and run both after each completed task. - Keep `output.files` limited to payload-relative paths (`config/.opencode/{agent,command,skills,lib,plugins,opencode.json}`, `config/.claude/{commands,skills,hooks,settings.json}` with no Claude agents, `config/.pi/{prompts,skills,extensions}`, and the generated schema). Do not emit `config/automated/.opencode`. diff --git a/context/plans/strengthen-pkl-structure-foundation.md b/context/plans/strengthen-pkl-structure-foundation.md new file mode 100644 index 00000000..7570f7cc --- /dev/null +++ b/context/plans/strengthen-pkl-structure-foundation.md @@ -0,0 +1,122 @@ +# Plan: strengthen-pkl-structure-foundation + +## Change summary + +Strengthen the existing Pkl generation architecture without changing the 46-file generated payload or any workflow behavior. Correct the stale contributor-facing package matrix and clarify the source hierarchy, remove the unused serialized schema evaluation from the canonical source tree, make the complete generated artifact inventory and unresolved-reference checks exact, and introduce one typed workflow catalog from which shared workflow metadata and target routing are derived. + +This is a foundation-only restructuring. The canonical phase modules, composite workflow behavior, output layouts, plugins, extension, settings, schema, and ephemeral build/package handoff remain intact. Replacing prose-based workflow internalization, restructuring the context-sync fragments, and consolidating shell/Nix generation mechanics remain later work. + +## Acceptance criteria + +- [x] AC1: Contributor documentation accurately states that OpenCode, Claude, and Pi each receive four workflow packages containing exactly `SKILL.md` and `references/output.md`, and clearly distinguishes canonical Pkl authoring ownership from the root `.pi/` behavioral reference. + - Validate: inspect `config/pkl/README.md` against `config/pkl/renderers/metadata-coverage-check.pkl`, `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md`, and a temporary generated payload. +- [x] AC2: `config/pkl/rendered` is absent, has no active consumer, and a focused generation check rejects its reintroduction as an accidental repository-local evaluation artifact. + - Validate: `test ! -e config/pkl/rendered`; search active source and tooling for consumers; run `nix run .#pkl-check-generated`. +- [x] AC3: Pkl validation asserts the exact complete 46-file generated path set, rejects deterministic extra or missing artifacts, and checks generated workflow packages for stale sibling-package references or unresolved internalization tokens. + - Validate: evaluate the focused Pkl generation-contract checks; run a negative fixture or temporary mutation check proving one extra path and one forbidden workflow reference fail validation; run `nix run .#pkl-check-generated`. +- [x] AC4: One typed workflow catalog owns the four workflows' command slug, skill slug, title, description, argument hint, and target routing/permission metadata currently repeated across composite, coverage, OpenCode, and Claude modules. + - Validate: inspect consumers to confirm they derive their workflow matrix from the catalog; focused searches find no parallel four-workflow slug or skill-path matrix outside explicit test fixtures and historical context. +- [x] AC5: The complete generated payload is byte-identical before and after the catalog refactor, and repository validation passes. + - Validate: generate pre-refactor and post-refactor temporary roots and run `diff -r `; run the full validation commands below. + +### Full validation + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, and `context/patterns.md` for the typed workflow catalog, exact artifact contract, and clarified Pkl-versus-`.pi` ownership hierarchy. +- Update `context/glossary.md` if `workflow catalog` or `generated artifact catalog` becomes canonical terminology. +- Update `context/context-map.md` only if a new focused durable context document is introduced. + +## Constraints and non-goals + +- **In scope:** `config/pkl/README.md`; removal and recurrence prevention for `config/pkl/rendered`; Pkl generation/coverage checks; a typed workflow catalog; derivation of shared composite, coverage, OpenCode routing, and Claude permission metadata; required Pkl-related Nix source-set adjustments; durable context updates describing the resulting structure. +- **Out of scope:** Rewriting `workflow-composite.pkl`'s prose-internalization pipeline; changing phase instructions, human-visible output layouts, or target frontmatter; restructuring the numbered context-sync fragments; consolidating shell/Nix/Cargo generation producers; changing plugin, extension, settings, policy, schema, CLI, setup, or packaging behavior; adding remote Pkl dependencies. +- **Constraints:** Preserve all generated bytes and all 46 generated paths; keep generation ephemeral; keep vendored dependencies compatible with Nix sandboxing; use Nix-provided Pkl and repository validation commands; keep accepted cross-target single-skill package decisions in force. +- **Non-goal:** Perform the final directory layout migration or create a general framework for hypothetical targets or workflows. + +## Assumptions + +- The root `.pi/` workflow tree remains the accepted behavioral reference named by existing decisions, while `config/pkl/**` remains the sole canonical source consumed by generation and packaging. Clarifying this hierarchy does not change either role. +- `config/pkl/rendered` is an accidental serialized evaluation result because no active generator, renderer, check, build, or package consumer references it. +- Exact artifact validation may derive expected paths from target document inventories plus explicitly named retained assets, but it must remain independent enough from `generate.pkl` output assembly to detect an accidental extra mapping. +- Target-specific routing and permission values may live on catalog records while target renderers remain responsible for formatting supported frontmatter. + +## Task stack + +- [x] T01: `Correct the Pkl ownership and package documentation` (status:complete) + - Task ID: T01 + - Goal: Make the Pkl runbook describe the current four-workflow/two-file package architecture and unambiguously explain Pkl authoring ownership versus the `.pi` behavioral reference. + - Boundaries (in/out of scope): In — `config/pkl/README.md` package counts, target matrix, coverage description, and ownership wording. Out — Pkl code, generated files, durable architecture changes owned by later implementation/context sync, and revision of accepted architecture decisions. + - Dependencies: none + - Done when: The runbook contains no claim that OpenCode or Pi generates eight phase packages, consistently describes eight workflow Markdown files across four packages per target, and explains that `.pi` is a behavioral reference rather than a second generation source. + - Verification notes (commands or checks): compare the README with `metadata-coverage-check.pkl` and `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md`; run `nix run .#pkl-check-generated`. + - Implementation evidence: Updated `config/pkl/README.md` so all three targets consistently receive four workflow packages containing exactly `SKILL.md` and `references/output.md` (eight workflow Markdown files per target). Clarified that `config/pkl/**` is the sole canonical source consumed by generation and packaging, while project-root `.pi/` is the accepted behavioral reference rather than another generation source. Replaced stale OpenCode/Pi phase-package coverage claims with the shared one-to-one workflow-package contract. + - Verification evidence: Compared the revised runbook with `config/pkl/renderers/metadata-coverage-check.pkl` and `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md`; focused search found no remaining README claim that OpenCode or Pi receives eight phase packages; `git diff --check -- config/pkl/README.md` passed; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`. + +- [x] T02: `Remove and guard against the stray rendered evaluation` (status:complete) + - Task ID: T02 + - Goal: Remove the unused `config/pkl/rendered` schema serialization from canonical inputs and prevent accidental repository-local Pkl evaluation from restoring it unnoticed. + - Boundaries (in/out of scope): In — deleting `config/pkl/rendered`, adding a focused forbidden-artifact assertion to existing Pkl generation validation, and adjusting documentation only if needed to explain safe temporary evaluation. Out — generated schema behavior, schema source changes, vendored dependencies, or broad ignore rules that could hide other source files. + - Dependencies: T01 + - Done when: The file is absent, active-source inspection confirms no consumer, repository-local validation fails if the path is recreated, and normal ephemeral generation remains unchanged. + - Verification notes (commands or checks): `test ! -e config/pkl/rendered`; focused source search for `config/pkl/rendered`; temporarily recreate the path and confirm the focused check fails, then remove it; `nix run .#pkl-check-generated`. + - Implementation evidence: Deleted the unused `config/pkl/rendered` schema serialization and added an early `forbidden_source_artifacts` assertion to `config/pkl/check-generated.sh` that rejects the exact repository-local evaluation path without introducing an ignore rule or changing generated schema behavior. + - Verification evidence: `test ! -e config/pkl/rendered` and `git diff --check -- config/pkl/check-generated.sh config/pkl/rendered` passed; focused active-source search found the exact path only in the new validation guard; temporarily recreating `config/pkl/rendered` made `nix develop -c ./config/pkl/check-generated.sh` fail with the expected artifact diagnostic, after which the fixture was removed; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`. + +- [x] T03: `Enforce the exact generated artifact and reference contract` (status:complete) + - Task ID: T03 + - Goal: Upgrade generation coverage from target-root presence plus partial document inventories to an exact complete artifact-path contract with semantic guards against stale composite references. + - Boundaries (in/out of scope): In — focused Pkl check modules, `metadata-coverage-check.pkl` organization if needed, `check-generated.sh` invocation wiring, the exact expected OpenCode/Claude/Pi/schema path derivation, JSON/frontmatter evaluation where supported directly, and forbidden stale phase-package/reference tokens in generated workflow documents. Out — changing generated text, replacing the internalization implementation, testing plugin runtime behavior, or consolidating generation producers. + - Dependencies: T02 + - Done when: Validation accounts for exactly 46 generated files by path; an extra or missing deterministic output fails; every generated workflow package still has exactly two files; commands retain one-to-one routes; and generated workflow text contains no forbidden sibling-package reference path or unconverted routing token defined by the check. + - Verification notes (commands or checks): evaluate each focused Pkl check through `nix develop -c pkl eval ...`; perform controlled negative checks for one extra artifact and one forbidden reference; run `nix run .#pkl-check-generated` and confirm its reported inventory is 46 files. + - Implementation evidence: Added `generation-contract-check.pkl` with an independently derived exact artifact-path inventory spanning OpenCode, Claude, Pi, retained assets, and the schema. The check compares that contract with `generate.pkl` output and rejects stale phase-skill slugs and package-local reference tokens in all generated workflow documents. Added explicit extra-artifact, missing-artifact, and forbidden-reference Pkl fixtures, and wired their expected failures into `check-generated.sh` alongside the existing exact package and command-route coverage. + - Verification evidence: `nix develop -c pkl eval config/pkl/renderers/generation-contract-check.pkl` passed and reported exactly 46 artifact paths plus fully internalized workflow references; all three negative fixtures failed with their expected contract diagnostics through `nix develop -c ./config/pkl/check-generated.sh`; `nix run .#pkl-check-generated` passed with 46 files and unchanged inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + +- [x] T04: `Centralize the typed workflow catalog` (status:complete) + - Task ID: T04 + - Goal: Introduce one catalog for the four workflow identities and derive composite metadata, coverage expectations, OpenCode agent routing, and Claude allowed-tool metadata from it without changing output. + - Boundaries (in/out of scope): In — a focused catalog/model module; command slug, skill slug, title, description, argument hint, OpenCode routing role, and Claude allowed-tools fields; updates to `workflow-composite.pkl`, target metadata/content modules, and coverage checks; removal of superseded duplicate maps. Out — phase content and order, output layout strings, internalization substitutions, context-sync source structure, target rendering syntax, and general artifact-domain directory reorganization. + - Dependencies: T03 + - Done when: All four workflow records are declared once; relevant consumers iterate or look up those records rather than restating the matrix; duplicate constructors or maps made obsolete by the catalog are removed; direct module evaluations pass; and a complete before/after generated-tree diff is empty. + - Verification notes (commands or checks): generate and retain a temporary baseline before editing; evaluate the catalog and all target renderers directly; generate a second temporary payload and run `diff -r`; run focused searches for duplicate workflow matrices; run `nix run .#pkl-check-generated` and `nix flake check`. + - Implementation evidence: Added `config/pkl/base/workflow-catalog.pkl` with one typed record for each of the four workflows, owning command and skill slugs, title, description, argument hint, OpenCode agent routing role, and Claude allowed tools. Composite workflow construction now looks up shared identity records; OpenCode command routing and agent skill permissions, Claude allowed-tool mappings, and exact metadata coverage inventories are derived from the catalog. Removed the superseded command-to-skill, command-to-agent, explicit Claude tool, and explicit workflow skill-path matrices. + - Verification evidence: Direct `pkl eval` checks passed for the catalog, OpenCode and Claude metadata, all three target content renderers, metadata coverage, and the generation contract. Temporary payloads generated before and after the refactor passed `diff -r` with no differences; focused searches found workflow descriptions and Claude tool strings only in the catalog, no parallel command-to-skill matrix, and no explicit workflow package path matrix outside the negative fixture. `nix run .#pkl-check-generated` passed with 46 files and unchanged inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `nix flake check` passed after temporarily marking the plan's untracked Pkl additions intent-to-add so Git-based flake source discovery included them, then restoring the index; `git diff --check` passed. + +## Open questions + +None. The requested scope is the first four incremental improvements from the Pkl structure analysis, and existing decisions fix the generated target architecture and byte-preservation constraint. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-29 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (exact and deterministic 46-file payload passed with inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; negative contract fixtures passed by failing as expected) +- `nix flake check` -> exit 0 (all evaluated checks passed on `x86_64-linux`) +- `tmp_dir="$(mktemp -d /tmp/opencode/sce-validate-pkl.XXXXXX)" && trap 'rm -rf "$tmp_dir"' EXIT && mkdir -p "$tmp_dir/baseline" "$tmp_dir/before" "$tmp_dir/after" && git archive HEAD | tar -x -C "$tmp_dir/baseline" && nix run "path:$tmp_dir/baseline#pkl-generate" -- "$tmp_dir/before" && nix run .#pkl-generate -- "$tmp_dir/after" && diff -r "$tmp_dir/before" "$tmp_dir/after"` -> exit 0 (the `HEAD` baseline and finished generated payloads were byte-identical) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: Contributor documentation states the exact four-package/two-file target matrix and Pkl-versus-`.pi` ownership hierarchy -> inspected `config/pkl/README.md` against metadata coverage, the accepted cross-target package decision, and the temporary generated payload. +- [x] AC2: The stray serialized evaluation is absent, unconsumed, and guarded -> `config/pkl/rendered` is absent; active source/tooling inspection found the exact path only in the focused rejection guard; `nix run .#pkl-check-generated` passed. +- [x] AC3: The exact 46-path and internal-reference contracts are enforced -> inspected `generation-contract-check.pkl`; its extra-artifact, missing-artifact, and forbidden-reference fixtures failed with expected diagnostics during the focused generated-output check. +- [x] AC4: Shared workflow identity and routing metadata have one typed owner -> inspected the catalog and composite, coverage, OpenCode, and Claude consumers; focused searches confirmed those consumers derive the relevant matrix from `workflow-catalog.pkl` rather than restating it. +- [x] AC5: Generated bytes and repository validation are unchanged/green -> the baseline/current `diff -r` was empty, `nix run .#pkl-check-generated` passed, and `nix flake check` passed. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- Platform-specific flake checks for `aarch64-darwin`, `aarch64-linux`, and `x86_64-darwin` were omitted by the local `x86_64-linux` validation environment. From 800dcb4ef4bd70883900a9536e61f1972e48e92d Mon Sep 17 00:00:00 2001 From: David Abram Date: Thu, 30 Jul 2026 01:10:27 +0200 Subject: [PATCH 20/21] pkl: Refactor workflow composition and generated-input production Replace prose-based workflow internalization with structured rendering and named semantic sections. Centralize deterministic Pkl generation, input discovery, inventories, and handoff publication behind one producer contract. Co-authored-by: SCE --- config/pkl/base/workflow-change-to-plan.pkl | 238 ++- config/pkl/base/workflow-commit.pkl | 141 +- config/pkl/base/workflow-content.pkl | 64 + config/pkl/base/workflow-context-sync.pkl | 1508 +++++++---------- config/pkl/base/workflow-next-task.pkl | 264 +-- config/pkl/base/workflow-validate.pkl | 202 ++- config/pkl/check-generated.sh | 52 +- config/pkl/generator-inputs.txt | 5 + config/pkl/renderers/workflow-composite.pkl | 158 +- context/architecture.md | 28 +- context/context-map.md | 4 +- context/glossary.md | 10 +- context/overview.md | 10 +- context/patterns.md | 14 +- ...refactor-pkl-composition-and-generation.md | 216 +++ .../sce/cli-cargo-distribution-contract.md | 7 +- context/sce/flake-build-performance.md | 16 +- flake.nix | 51 +- scripts/prepare-cli-generated-assets.sh | 65 +- scripts/produce-cli-generated-input.sh | 141 ++ scripts/run-cli-cargo.sh | 88 +- scripts/test-check-generated.sh | 129 ++ scripts/test-prepare-cli-generated-assets.sh | 96 ++ scripts/test-produce-cli-generated-input.sh | 195 +++ scripts/test-run-cli-cargo.sh | 10 +- 25 files changed, 2114 insertions(+), 1598 deletions(-) create mode 100644 config/pkl/generator-inputs.txt create mode 100644 context/plans/refactor-pkl-composition-and-generation.md create mode 100755 scripts/produce-cli-generated-input.sh create mode 100755 scripts/test-check-generated.sh create mode 100755 scripts/test-prepare-cli-generated-assets.sh create mode 100755 scripts/test-produce-cli-generated-input.sh diff --git a/config/pkl/base/workflow-change-to-plan.pkl b/config/pkl/base/workflow-change-to-plan.pkl index 275c450a..d1a2efba 100644 --- a/config/pkl/base/workflow-change-to-plan.pkl +++ b/config/pkl/base/workflow-change-to-plan.pkl @@ -1,46 +1,61 @@ import "workflow-content.pkl" as model +local contextLoad = model.semanticReference.apply("`sce-context-load`", "the **Context load phase**") +local contextLoadName = model.semanticReference.apply("sce-context-load", "Context load phase") +local planAuthoring = model.semanticReference.apply("`sce-plan-authoring`", "the **Plan authoring phase**") +local planAuthoringName = model.semanticReference.apply("sce-plan-authoring", "Plan authoring phase") +local planReview = model.semanticReference.apply("`sce-plan-review`", "the **Plan review phase**") +local taskExecutionName = model.semanticReference.apply("`sce-task-execution`", "the **Task execution phase**") +local contextBrief = model.semanticReference.apply( + "`references/context-brief.yaml`", + "the internal context-load state described by this workflow" +) +local authoringContract = model.semanticReference.apply( + "`references/authoring-contract.yaml`", + "the internal authoring state described by this workflow" +) +local planTemplate = model.semanticReference.apply( + "`references/plan-template.md`", + "the **Plan template** section embedded in this file" +) +local planSummary = model.semanticReference.apply("`references/plan-summary.md`", "`references/output.md`") +local invoke = model.semanticReference.apply("Invoke", "Run") +local invokeLower = model.semanticReference.apply("invoke", "run") +local invokedSkills = model.semanticReference.apply("invoked skills", "embedded phases") +local yamlResult = model.semanticReference.apply("YAML result", "internal state") +local returnLower = model.semanticReference.apply("return", "set internal status") +local returnUpper = model.semanticReference.apply("Return", "Set internal status") +local returningContextBrief = model.semanticReference.apply("Returning one structured context brief", "Recording one structured context brief") +local returningAuthoringResult = model.semanticReference.apply("Returning one structured authoring result", "Recording one structured authoring result") +local invokeTaskExecution = model.semanticReference.apply("Invoke task execution", "Run task execution") +local returnExactlyOneStructuredResult = model.semanticReference.apply("Return exactly one structured result", "Set exactly one internal state") +local returnOnlyStructuredResult = model.semanticReference.apply("Return only the structured result", "Record only the internal state") + /// Canonical `/change-to-plan` workflow command and its self-contained skill /// packages. Text mirrors the project-root `.pi/` behavioral baseline; target /// renderers consume this model in later workflow-rendering tasks. -local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { - path = documentPath - text = documentText -} - -local packageDocuments = (documents: Listing) -> new Mapping { - for (item in documents) { - [item.path] = item - } -} - local contextLoadPackage = new model.SkillPackage { slug = "sce-context-load" title = "SCE Context Load" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", CONTEXT_SKILL) - makeDocument.apply("references/context-brief.yaml", CONTEXT_CONTRACT) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", CONTEXT_SKILL) + model.makeDocument.apply("references/context-brief.yaml", CONTEXT_CONTRACT) }) } local planAuthoringPackage = new model.SkillPackage { slug = "sce-plan-authoring" title = "SCE Plan Authoring" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", AUTHORING_SKILL) - makeDocument.apply("references/authoring-contract.yaml", AUTHORING_CONTRACT) - makeDocument.apply("references/plan-template.md", PLAN_TEMPLATE) - makeDocument.apply("references/plan-summary.md", PLAN_SUMMARY) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", AUTHORING_SKILL) + model.makeDocument.apply("references/authoring-contract.yaml", AUTHORING_CONTRACT) + model.makeDocument.apply("references/plan-template.md", PLAN_TEMPLATE) + model.makeDocument.apply("references/plan-summary.md", PLAN_SUMMARY) }) } -local COMMAND = """ - --- - description: "Run `sce-context-load` -> `sce-plan-authoring` to turn a change request into a scoped SCE plan" - argument-hint: "" - --- - +local renderCommandBody = (mode: model.WorkflowRenderMode) -> """ SCE CHANGE TO PLAN `$ARGUMENTS` ## Input @@ -48,19 +63,19 @@ local COMMAND = """ `$ARGUMENTS` is the change request, in free-form prose. - The change request is required. - - It may describe a new plan or a change to an existing plan. Do not resolve which one applies; `sce-plan-authoring` owns that decision. + - It may describe a new plan or a change to an existing plan. Do not resolve which one applies; \(planAuthoring.render.apply(mode)) owns that decision. When `$ARGUMENTS` is empty, report that a change request is required, state the expected argument, and stop. Do not infer a change request from the repository state or the conversation. - Pass the change request to `sce-plan-authoring` unmodified. Do not restate, summarize, or pre-scope it. + Pass the change request to \(planAuthoring.render.apply(mode)) unmodified. Do not restate, summarize, or pre-scope it. - Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-authoring` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by \(planAuthoring.render.apply(mode)) (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. ## Workflow ### 1. Load durable context - Invoke `sce-context-load` with the change request as the focus. + \(invoke.render.apply(mode)) \(contextLoad.render.apply(mode)) with the change request as the focus. `context/` is durable AI-first memory describing current state. Load it before planning so the plan starts from recorded truth. Where context and code disagree, the code is the source of truth. @@ -81,7 +96,7 @@ local COMMAND = """ `sce setup --bootstrap-context` ``` - Wait for the user. When they report the command ran, invoke `sce-context-load` again and continue in this session. Do not restart planning, and do not ask for the change request again. + Wait for the user. When they report the command ran, \(invokeLower.render.apply(mode)) \(contextLoad.render.apply(mode)) again and continue in this session. Do not restart planning, and do not ask for the change request again. `loaded` -> Continue to the next step. @@ -89,11 +104,11 @@ local COMMAND = """ ### 2. Author the plan - Invoke `sce-plan-authoring` with the change request and the complete `loaded` brief from `sce-context-load`. + \(invoke.render.apply(mode)) \(planAuthoring.render.apply(mode)) with the change request and the complete `loaded` brief from \(contextLoad.render.apply(mode)). Pass the brief verbatim. Do not restate, summarize, or reinterpret it. - `sce-plan-authoring` exclusively owns: + \(planAuthoring.render.apply(mode)) exclusively owns: - Resolving whether the request targets a new or an existing plan. - The clarification gate. @@ -141,9 +156,9 @@ local COMMAND = """ ### 3. Determine the continuation - Render the `plan_ready` result as the summary defined by `sce-plan-authoring` in `references/plan-summary.md`. Follow that layout exactly. Do not print the raw result. + Render the `plan_ready` result as the summary defined by \(planAuthoring.render.apply(mode)) in \(planSummary.render.apply(mode)). Follow that layout exactly. Do not print the raw result. - Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + Take the next task from `next_task`. A `plan_ready` result always names one. Do not evaluate its dependencies; \(planReview.render.apply(mode)) checks them when the emitted command runs and returns `blocked` if they are unmet. The continuation invites revision. The plan was written from one prose request, so its assumptions are guesses about what the user meant, its scope is one reading of the request, and its task boundaries are the author's judgement. The user has seen none of it until now, and every one of those is cheaper to correct here than after a task has been built on it. A user who does not know revision is on the table will implement a plan they would have changed. @@ -176,17 +191,17 @@ local COMMAND = """ When the user answers clarification questions from step 2, answers open questions listed in the summary, or answers with changes to the plan, revise it in this session. Do not ask them to rerun `/change-to-plan`, and do not ask for the original change request again. - Invoke `sce-plan-authoring` with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. + \(invoke.render.apply(mode)) \(planAuthoring.render.apply(mode)) with their answer or correction and the same `loaded` brief from step 1. The brief still holds; durable context did not change because the user disagreed with a task boundary. Do not reload it. An answer that resolves a doubt removes that open question. An answer that does not resolve it leaves the question standing; do not drop it because the user replied to it. If the reply raises a new doubt, the revised plan carries a new open question. - Pass the correction as written. Do not restate, soften, or pre-scope it. `sce-plan-authoring` owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. + Pass the correction as written. Do not restate, soften, or pre-scope it. \(planAuthoring.render.apply(mode)) owns resolving it against the existing plan, and owns preserving completed tasks and their evidence. Branch on `status` exactly as in step 2. A revision may legitimately return `needs_clarification` or `blocked`. On `plan_ready`, render the summary again and the continuation exactly as in step 3, replacing `is ready` with `revised` in the heading. - Revise as many times as the user asks. Each revision is one invocation of `sce-plan-authoring` against the same plan. + Revise as many times as the user asks. Each revision is one invocation of \(planAuthoring.render.apply(mode)) against the same plan. When the user signals the plan is good, or asks to begin, return the handoff without re-authoring the plan. Say so plainly if questions are still open: the user may proceed over an unresolved doubt, and that is their call, but do not record it as resolved. @@ -199,8 +214,8 @@ local COMMAND = """ - Do not gate the handoff on open questions listed in the plan summary. Blocking questions return `needs_clarification` before any plan is written. Offering revision is not the same as demanding it, and inventing doubts to justify a review gate is not allowed. - Do not suppress, soften, or answer an open question or clarification question on the user's behalf. - Do not defer the user's revision to a rerun of `/change-to-plan`, and do not defer it to the implementation phase. Revise the plan here. - - Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to `sce-plan-authoring` as written. - - Do not duplicate the internal instructions of invoked skills. + - Do not narrow, expand, or reinterpret a revision the user asked for. Pass it to \(planAuthoring.render.apply(mode)) as written. + - Do not duplicate the internal instructions of \(invokedSkills.render.apply(mode)). - Do not plan before durable context is loaded. - Do not bootstrap `context/` yourself. `sce setup --bootstrap-context` owns that. - Do not modify any file under `context/` outside `context/plans/`. @@ -210,20 +225,25 @@ local COMMAND = """ - Do not emit a `/validate` command. This workflow always hands off to `/next-task`. - Do not answer the skill's clarification questions on the user's behalf. - Do not execute the continuation returned at the end. - - Do not infer success when `sce-plan-authoring` returns a non-`plan_ready` status. + - Do not infer success when \(planAuthoring.render.apply(mode)) returns a non-`plan_ready` status. """ -local CONTEXT_SKILL = """ - --- - name: sce-context-load - description: > - Internal SCE workflow skill that loads the durable context in `context/` - relevant to one focus, reports gaps and context-versus-code drift, and returns - one YAML result: loaded or bootstrap_required. Use from /change-to-plan and - any workflow that needs durable context before acting. Do not modify context, - repair drift, plan, or implement. - --- +local structuredCommand = new model.StructuredWorkflowDocument { + path = "change-to-plan.md" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "description: \"Run \(contextLoad.render.apply(mode)) -> \(planAuthoring.render.apply(mode)) to turn a change request into a scoped SCE plan\"" + "argument-hint: \"\"" + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderCommandBody.apply(mode) + } +} + +local COMMAND = structuredCommand.render.apply("package", "").text +local renderContextSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Context Load ## Purpose @@ -241,11 +261,11 @@ local CONTEXT_SKILL = """ - Selecting the domain context relevant to the focus. - Reporting focus areas with no durable context. - Reporting context that contradicts the code. - - Returning one structured context brief. + - \(returningContextBrief.render.apply(mode)). Return a result matching: - `references/context-brief.yaml` + \(contextBrief.render.apply(mode)) ## Input @@ -258,7 +278,7 @@ local CONTEXT_SKILL = """ ### 1. Confirm the context root - When `context/` does not exist, return `bootstrap_required` immediately. Read + When `context/` does not exist, \(returnLower.render.apply(mode)) `bootstrap_required` immediately. Read nothing further. Bootstrapping is the invoking workflow's decision, not this skill's. @@ -309,7 +329,7 @@ local CONTEXT_SKILL = """ ### 5. Return the brief - Return exactly one structured result: + \(returnExactlyOneStructuredResult.render.apply(mode)): - `loaded` - `bootstrap_required` @@ -317,7 +337,7 @@ local CONTEXT_SKILL = """ Report facts the invoking workflow can act on. A brief that only lists file paths has moved no knowledge. - Return only the structured result. Do not add explanatory prose before or after + \(returnOnlyStructuredResult.render.apply(mode)). Do not add explanatory prose before or after it. ## Boundaries @@ -341,9 +361,29 @@ local CONTEXT_SKILL = """ - The context root was confirmed, or `bootstrap_required` was returned. - The entry points were read, and the relevant domain context was selected and read. - - One valid result matching `references/context-brief.yaml` was returned. + - One valid result matching \(contextBrief.render.apply(mode)) was returned. """ +local structuredContextSkill = new model.StructuredWorkflowDocument { + path = "sce-context-load" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(contextLoadName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that loads the durable context in `context/`" + " relevant to one focus, reports gaps and context-versus-code drift, and returns" + " one \(yamlResult.render.apply(mode)): loaded or bootstrap_required. Use from /change-to-plan and" + " any workflow that needs durable context before acting. Do not modify context," + " repair drift, plan, or implement." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderContextSkillBody.apply(mode) + } +} + +local CONTEXT_SKILL = structuredContextSkill.render.apply("package", "").text + local CONTEXT_CONTRACT = """ version: 1 name: sce-context-load-result @@ -500,17 +540,7 @@ local CONTEXT_CONTRACT = """ to load for this focus. """ -local AUTHORING_SKILL = """ - --- - name: sce-plan-authoring - description: > - Internal SCE workflow skill that turns one change request into a scoped plan - in `context/plans/`, sliced into atomic implementation tasks, and returns one - YAML result: plan_ready, needs_clarification, or blocked. Use from - /change-to-plan. Do not implement plan tasks, request implementation approval, - synchronize context, or run final validation. - --- - +local renderAuthoringSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Plan Authoring ## Purpose @@ -528,26 +558,26 @@ local AUTHORING_SKILL = """ non-goals. - Slicing the work into atomic implementation tasks. - Writing the plan file. - - Returning one structured authoring result. + - \(returningAuthoringResult.render.apply(mode)). Use the document format defined in: - `references/plan-template.md` + \(planTemplate.render.apply(mode)) Return a result matching: - `references/authoring-contract.yaml` + \(authoringContract.render.apply(mode)) The invoking workflow renders that result as the summary defined in: - `references/plan-summary.md` + \(planSummary.render.apply(mode)) ## Input The invoking workflow provides: - One change request, in free-form prose. - - The `loaded` context brief from `sce-context-load`. + - The `loaded` context brief from \(contextLoad.render.apply(mode)). The change request may name a plan, describe a change to an existing plan, or describe entirely new work. Resolving which applies is this skill's @@ -567,7 +597,7 @@ local AUTHORING_SKILL = """ request, and it is usually terse: a task boundary the user disagrees with, an ordering they want changed, work they want added or dropped. Read it against the existing plan, which supplies the scope, criteria, and terminology it omits. - Terseness is not ambiguity. Do not return `needs_clarification` for detail the + Terseness is not ambiguity. Do not \(returnLower.render.apply(mode)) `needs_clarification` for detail the plan already carries; ask only when the revision itself is genuinely undecidable. ## Workflow @@ -637,7 +667,7 @@ local AUTHORING_SKILL = """ strategy, and risk tradeoffs. - Task ordering assumptions and prerequisite sequencing. - Return `needs_clarification` with one to three targeted questions when any of + \(returnUpper.render.apply(mode)) `needs_clarification` with one to three targeted questions when any of these would materially change the plan. Write no plan file in that case. Use repository conventions for ordinary local choices. Do not block on: @@ -693,7 +723,7 @@ local AUTHORING_SKILL = """ ### 6. Author the task stack Slice the work into sequential tasks `T01..T0N` using the task format and the - atomic slicing contract in `references/plan-template.md`. + atomic slicing contract in \(planTemplate.render.apply(mode)). Every executable task must be completable and landable as one coherent commit. Split any task that would require multiple independent commits. Convert broad @@ -712,25 +742,25 @@ local AUTHORING_SKILL = """ A finished stack always leaves at least one incomplete task, so the invoking workflow can always hand off to `/next-task`. When the request resolves to a plan but produces no incomplete task, because the change is already implemented - or already covered by completed tasks, return `blocked` with category + or already covered by completed tasks, \(returnLower.render.apply(mode)) `blocked` with category `no_actionable_work` instead of writing the plan. ### 7. Write the plan - Write `context/plans/{plan_name}.md` using `references/plan-template.md`. + Write `context/plans/{plan_name}.md` using \(planTemplate.render.apply(mode)). When updating an existing plan, keep completed tasks and their evidence intact, and append or renumber new tasks without disturbing recorded history. ### 8. Return the result - Return exactly one structured result: + \(returnExactlyOneStructuredResult.render.apply(mode)): - `plan_ready` - `needs_clarification` - `blocked` - Return only the structured result. Do not add explanatory prose before or after + \(returnOnlyStructuredResult.render.apply(mode)). Do not add explanatory prose before or after it. ## Tone @@ -763,7 +793,7 @@ local AUTHORING_SKILL = """ Do not: - - Ask the user questions directly. Return `needs_clarification` and let the + - Ask the user questions directly. \(returnUpper.render.apply(mode)) `needs_clarification` and let the invoking workflow present the questions. - Answer your own clarification questions. - Write a plan file when returning `needs_clarification` or `blocked`. @@ -773,12 +803,12 @@ local AUTHORING_SKILL = """ repair instead of performing it. - Mark any task complete. - Request implementation confirmation. - - Invoke task execution. + - \(invokeTaskExecution.render.apply(mode)). - Synchronize context. - Run final validation. - Author a validation, cleanup, or context-verification task. `/validate` owns that phase. - - Return `plan_ready` for a plan with no incomplete task. + - \(returnUpper.render.apply(mode)) `plan_ready` for a plan with no incomplete task. - Create a Git commit. - Author more than one plan. @@ -789,9 +819,29 @@ local AUTHORING_SKILL = """ - One plan target was resolved, or resolution failed and was reported. - The plan file was written, or no file was written because the result is `needs_clarification` or `blocked`. - - One valid result matching `references/authoring-contract.yaml` was returned. + - One valid result matching \(authoringContract.render.apply(mode)) was returned. """ +local structuredAuthoringSkill = new model.StructuredWorkflowDocument { + path = "sce-plan-authoring" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(planAuthoringName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that turns one change request into a scoped plan" + " in `context/plans/`, sliced into atomic implementation tasks, and returns one" + " \(yamlResult.render.apply(mode)): plan_ready, needs_clarification, or blocked. Use from" + " /change-to-plan. Do not implement plan tasks, request implementation approval," + " synchronize context, or run final validation." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderAuthoringSkillBody.apply(mode) + } +} + +local AUTHORING_SKILL = structuredAuthoringSkill.render.apply("package", "").text + local AUTHORING_CONTRACT = """ version: 1 name: sce-plan-authoring-result @@ -1051,7 +1101,7 @@ local AUTHORING_CONTRACT = """ be created. """ -local PLAN_TEMPLATE = """ +local renderPlanTemplate = (mode: model.WorkflowRenderMode) -> """ # SCE Plan Template The document format for `context/plans/{plan_name}.md`. This is the plan file @@ -1198,7 +1248,7 @@ local PLAN_TEMPLATE = """ ## Completion records - `sce-task-execution` appends evidence to a task when it completes, and flips the + \(taskExecutionName.render.apply(mode)) appends evidence to a task when it completes, and flips the checkbox and status: ```markdown @@ -1224,6 +1274,8 @@ local PLAN_TEMPLATE = """ criteria already satisfied. """ +local PLAN_TEMPLATE = renderPlanTemplate.apply("package") + local PLAN_SUMMARY = """ # SCE Plan Summary @@ -1321,12 +1373,26 @@ local PLAN_SUMMARY = """ ``` """ +structuredComposite = new model.StructuredCompositeSource { + command = structuredCommand + phases = new Listing { + structuredContextSkill + structuredAuthoringSkill + } + internalDocuments = new Listing { + model.makeDocument.apply("Plan template", renderPlanTemplate.apply("composite")) + } + outputDocuments = new Listing { + model.makeDocument.apply("Plan summary", PLAN_SUMMARY) + } +} + workflow = new model.WorkflowPackage { slug = "change-to-plan" command = new model.WorkflowCommand { slug = "change-to-plan" title = "Change to Plan" - document = makeDocument.apply("change-to-plan.md", COMMAND) + document = model.makeDocument.apply("change-to-plan.md", COMMAND) } skills = new Mapping { [contextLoadPackage.slug] = contextLoadPackage diff --git a/config/pkl/base/workflow-commit.pkl b/config/pkl/base/workflow-commit.pkl index 334ee98b..aa671727 100644 --- a/config/pkl/base/workflow-commit.pkl +++ b/config/pkl/base/workflow-commit.pkl @@ -1,36 +1,35 @@ import "workflow-content.pkl" as model +local atomicCommit = model.semanticReference.apply("`sce-atomic-commit`", "the **Atomic commit phase**") +local atomicCommitName = model.semanticReference.apply("sce-atomic-commit", "Atomic commit phase") +local commitContract = model.semanticReference.apply("`references/commit-contract.yaml`", "the internal commit state described by this workflow") +local commitMessageStyle = model.semanticReference.apply("`references/commit-message-style.md`", "`references/output.md`") +local invoke = model.semanticReference.apply("Invoke", "Run") +local invokeLower = model.semanticReference.apply("invoke", "run") +local yamlResult = model.semanticReference.apply("YAML result", "internal state") +local yaml = model.semanticReference.apply("YAML", "internal state") +local returnUpper = model.semanticReference.apply("Return", "Set internal status") +local returnLower = model.semanticReference.apply("return", "set internal status") +local returningTerminalYamlResult = model.semanticReference.apply("Returning one terminal YAML result", "Recording one terminal internal state") +local returnExactlyOneYamlDocument = model.semanticReference.apply("Return exactly one YAML document", "Set exactly one internal state") +local returnOnlyYamlDocument = model.semanticReference.apply("Return only the YAML document", "Record only the internal state") +local returnYaml = model.semanticReference.apply("Return YAML", "Return internal state") + /// Canonical `/commit` workflow command and its self-contained skill package. /// Text mirrors the project-root `.pi/` behavioral baseline; target renderers /// consume this model in later workflow-rendering tasks. -local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { - path = documentPath - text = documentText -} - -local packageDocuments = (documents: Listing) -> new Mapping { - for (item in documents) { - [item.path] = item - } -} - local atomicCommitPackage = new model.SkillPackage { slug = "sce-atomic-commit" title = "SCE Atomic Commit" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", ATOMIC_COMMIT_SKILL) - makeDocument.apply("references/commit-contract.yaml", COMMIT_CONTRACT) - makeDocument.apply("references/commit-message-style.md", COMMIT_MESSAGE_STYLE) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", ATOMIC_COMMIT_SKILL) + model.makeDocument.apply("references/commit-contract.yaml", COMMIT_CONTRACT) + model.makeDocument.apply("references/commit-message-style.md", COMMIT_MESSAGE_STYLE) }) } -local COMMAND = """ - --- - description: "Run `sce-atomic-commit` to turn staged changes into atomic commit message proposals" - argument-hint: "[oneshot|skip] [commit context]" - --- - +local renderCommandBody = (mode: model.WorkflowRenderMode) -> """ SCE COMMIT `$ARGUMENTS` ## Input @@ -52,7 +51,7 @@ local COMMAND = """ Empty `$ARGUMENTS` is valid. It selects the regular path with no commit context, and commit intent is inferred from the staged changes alone. - Pass `commit context` to `sce-atomic-commit` unmodified. Do not restate, + Pass `commit context` to \(atomicCommit.render.apply(mode)) unmodified. Do not restate, summarize, or pre-scope it. Never pass the `mode-token` as commit context. Staged changes are the source of truth for what is being committed. This @@ -76,10 +75,10 @@ local COMMAND = """ #### 2. Request one commit message - Invoke `sce-atomic-commit` with `mode: bypass` and the commit context. + \(invoke.render.apply(mode)) \(atomicCommit.render.apply(mode)) with `mode: bypass` and the commit context. Bypass mode is the skill's contract for producing exactly one message. Do not - restate its overrides here; `sce-atomic-commit` owns them. + restate its overrides here; \(atomicCommit.render.apply(mode)) owns them. The skill must return a result matching its commit contract. Branch on `status`: @@ -117,10 +116,10 @@ local COMMAND = """ #### 2. Propose commits - After confirmation, invoke `sce-atomic-commit` with `mode: regular` and the + After confirmation, \(invokeLower.render.apply(mode)) \(atomicCommit.render.apply(mode)) with `mode: regular` and the commit context. - `sce-atomic-commit` exclusively owns: + \(atomicCommit.render.apply(mode)) exclusively owns: - Reading and analyzing the staged diff. - Deciding whether staged changes form one coherent unit or several. @@ -149,25 +148,31 @@ local COMMAND = """ - Never commit on the regular path. - Recognize `oneshot` and `skip` only as an exact case-insensitive first token. They are behaviorally identical. - - Do not duplicate the internal instructions of `sce-atomic-commit`. + - Do not duplicate the internal instructions of \(atomicCommit.render.apply(mode)). - Do not stage, unstage, restore, or otherwise modify files. - Do not amend, reset, revert, rebase, or push. - Do not read unstaged or untracked changes as commit input. - - Do not infer success when `sce-atomic-commit` returns a non-success status. + - Do not infer success when \(atomicCommit.render.apply(mode)) returns a non-success status. - Do not proceed past a failed `git commit`. - Do not run plan, task, or validation workflows from this command. """ -local ATOMIC_COMMIT_SKILL = """ - --- - name: sce-atomic-commit - description: > - Internal SCE workflow skill that analyzes the staged diff and returns atomic, - repository-style commit messages: coherent-unit detection, split guidance, - scope and subject wording, and the plan-citation body rule. Returns one YAML - result (proposal, bypass_message, or blocked). Use from /commit. Do not stage - files, create commits, or ask the user to confirm staging. - --- +local structuredCommand = new model.StructuredWorkflowDocument { + path = "commit.md" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "description: \"Run \(atomicCommit.render.apply(mode)) to turn staged changes into atomic commit message proposals\"" + "argument-hint: \"[oneshot|skip] [commit context]\"" + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderCommandBody.apply(mode) + } +} + +local COMMAND = structuredCommand.render.apply("package", "").text + +local renderAtomicCommitSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Atomic Commit ## Purpose @@ -181,15 +186,15 @@ local ATOMIC_COMMIT_SKILL = """ - Choosing the scope and writing the subject and body of every message. - Applying the plan-citation body rule. - Classifying staged scope and applying context-file guidance gating. - - Returning one terminal YAML result. + - \(returningTerminalYamlResult.render.apply(mode)). Write messages matching: - `references/commit-message-style.md` + \(commitMessageStyle.render.apply(mode)) Return a result matching: - `references/commit-contract.yaml` + \(commitContract.render.apply(mode)) Committing is not this skill's job. The invoking `/commit` workflow decides whether a returned message is committed, and it is the only thing that runs @@ -221,7 +226,7 @@ local ATOMIC_COMMIT_SKILL = """ Read staged file contents only when the diff alone does not explain the change. - Return `blocked` when nothing is staged. + \(returnUpper.render.apply(mode)) `blocked` when nothing is staged. ### 2. Identify coherent units @@ -243,7 +248,7 @@ local ATOMIC_COMMIT_SKILL = """ ### 4. Write each message - Follow `references/commit-message-style.md` for the subject pattern, the body + Follow \(commitMessageStyle.render.apply(mode)) for the subject pattern, the body rules, issue references, the plan-citation rule, and the anti-patterns. ### 5. Apply the plan-citation rule @@ -254,7 +259,7 @@ local ATOMIC_COMMIT_SKILL = """ When the staged plan diff does not expose the slug or task ID clearly enough to cite faithfully: - - In `regular` mode, return `blocked` and ask for the reference to be stated or + - In `regular` mode, \(returnLower.render.apply(mode)) `blocked` and ask for the reference to be stated or staged explicitly. - In `bypass` mode, infer the citation when the diff supports it, and otherwise omit it. Never stop, and never invent a slug or task ID. @@ -290,15 +295,15 @@ local ATOMIC_COMMIT_SKILL = """ - No plan slug or task ID appears that the staged diff does not support. - The mode's own constraints hold. - ### 9. Return YAML + ### 9. \(returnYaml.render.apply(mode)) - Return exactly one YAML document matching `references/commit-contract.yaml`: + \(returnExactlyOneYamlDocument.render.apply(mode)) matching \(commitContract.render.apply(mode)): - `proposal` in `regular` mode, with one or more messages. - `bypass_message` in `bypass` mode, with exactly one message. - `blocked` when messages cannot be written faithfully. - Return only the YAML document. Do not add explanatory prose before or after it. + \(returnOnlyYamlDocument.render.apply(mode)). Do not add explanatory prose before or after it. ## Boundaries @@ -322,9 +327,30 @@ local ATOMIC_COMMIT_SKILL = """ - The staged diff was read, or reading it failed and was reported. - Messages were written for every staged file, or a blocker prevented it. - - One valid terminal YAML result matching `references/commit-contract.yaml` was + - One valid terminal \(yamlResult.render.apply(mode)) matching \(commitContract.render.apply(mode)) was returned. """ + +local structuredAtomicCommitSkill = new model.StructuredWorkflowDocument { + path = "sce-atomic-commit" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(atomicCommitName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that analyzes the staged diff and returns atomic," + " repository-style commit messages: coherent-unit detection, split guidance," + " scope and subject wording, and the plan-citation body rule. Returns one \(yaml.render.apply(mode))" + " result (proposal, bypass_message, or blocked). Use from /commit. Do not stage" + " files, create commits, or ask the user to confirm staging." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderAtomicCommitSkillBody.apply(mode) + } +} + +local ATOMIC_COMMIT_SKILL = structuredAtomicCommitSkill.render.apply("package", "").text + local COMMIT_CONTRACT = """ version: 1 name: sce-atomic-commit-result @@ -532,10 +558,10 @@ local COMMIT_CONTRACT = """ decision_required: > State the completed task ID, or stage only that task's plan edit. """ -local COMMIT_MESSAGE_STYLE = """ +local renderCommitMessageStyle = (mode: model.WorkflowRenderMode) -> """ # Commit message style - The wording rules for every message `sce-atomic-commit` returns, in either + The wording rules for every message \(atomicCommit.render.apply(mode)) returns, in either mode. This file is the only authority for message content and shape. Messages are carried in the result's `message` field, subject first, then one @@ -598,12 +624,25 @@ local COMMIT_MESSAGE_STYLE = """ - Describing intent the staged diff does not support. """ +local COMMIT_MESSAGE_STYLE = renderCommitMessageStyle.apply("package") + +structuredComposite = new model.StructuredCompositeSource { + command = structuredCommand + phases = new Listing { + structuredAtomicCommitSkill + } + internalDocuments = new Listing {} + outputDocuments = new Listing { + model.makeDocument.apply("Commit message style", renderCommitMessageStyle.apply("composite")) + } +} + workflow = new model.WorkflowPackage { slug = "commit" command = new model.WorkflowCommand { slug = "commit" title = "SCE Commit" - document = makeDocument.apply("commit.md", COMMAND) + document = model.makeDocument.apply("commit.md", COMMAND) } skills = new Mapping { [atomicCommitPackage.slug] = atomicCommitPackage diff --git a/config/pkl/base/workflow-content.pkl b/config/pkl/base/workflow-content.pkl index 3a55aef3..d5355970 100644 --- a/config/pkl/base/workflow-content.pkl +++ b/config/pkl/base/workflow-content.pkl @@ -9,6 +9,55 @@ class WorkflowDocument { text: String } +typealias WorkflowRenderMode = "package"|"composite" + +/// A semantic token whose spelling depends on whether a canonical package or +/// an embedded composite workflow is being rendered. +class SemanticReference { + packageText: String + compositeText: String + + hidden render = (mode: WorkflowRenderMode) -> + if (mode == "composite") compositeText else packageText +} + +/// Frontmatter is modeled separately so composite rendering can embed its +/// fields without parsing or stripping Markdown markers. +class WorkflowFrontmatter { + hidden lines: (WorkflowRenderMode) -> Listing + + hidden render = (mode: WorkflowRenderMode, extraLines: String) -> + "---\n" + lines.apply(mode).join("\n") + "\n" + extraLines + "---\n" + + hidden renderEmbedded = (mode: WorkflowRenderMode) -> "\n" + lines.apply(mode).join("\n") + "\n\n" +} + +/// A body renderer receives semantic render mode before Markdown assembly. +class WorkflowBody { + hidden render: (WorkflowRenderMode) -> String +} + +class StructuredWorkflowDocument { + path: String + frontmatter: WorkflowFrontmatter + body: WorkflowBody + + hidden render = (mode: WorkflowRenderMode, extraFrontmatterLines: String) -> new WorkflowDocument { + path = outer.path + text = if (mode == "composite") + frontmatter.renderEmbedded.apply(mode) + "\n" + body.render.apply(mode) + else + frontmatter.render.apply(mode, extraFrontmatterLines) + "\n" + body.render.apply(mode) + } +} + +class StructuredCompositeSource { + command: StructuredWorkflowDocument + phases: Listing + internalDocuments: Listing + outputDocuments: Listing +} + class WorkflowCommand { slug: String title: String @@ -29,3 +78,18 @@ class WorkflowPackage { skills: Mapping } +hidden makeDocument = (documentPath: String, documentText: String) -> new WorkflowDocument { + path = documentPath + text = documentText +} + +hidden packageDocuments = (documents: Listing) -> new Mapping { + for (document in documents) { + [document.path] = document + } +} + +hidden semanticReference = (packageValue: String, compositeValue: String) -> new SemanticReference { + packageText = packageValue + compositeText = compositeValue +} diff --git a/config/pkl/base/workflow-context-sync.pkl b/config/pkl/base/workflow-context-sync.pkl index 78b6c615..24fcc78c 100644 --- a/config/pkl/base/workflow-context-sync.pkl +++ b/config/pkl/base/workflow-context-sync.pkl @@ -1,270 +1,141 @@ import "workflow-content.pkl" as workflow -/// One canonical source for both context-sync packages. Exact shared blocks are -/// stored once; SyncRole supplies only lifecycle-specific handoff, workflow, -/// boundary, and report fragments. Each generated package remains -/// self-contained and never references its sibling package. +local taskExecution = workflow.semanticReference.apply("`sce-task-execution`", "the **Task execution phase**") +local taskExecutionName = workflow.semanticReference.apply("sce-task-execution", "Task execution phase") +local validation = workflow.semanticReference.apply("`sce-validation`", "the **Validation phase**") +local validationName = workflow.semanticReference.apply("sce-validation", "Validation phase") +local taskContextSync = workflow.semanticReference.apply("`sce-task-context-sync`", "the **Task context synchronization phase**") +local taskContextSyncName = workflow.semanticReference.apply("sce-task-context-sync", "Task context synchronization phase") +local planContextSyncName = workflow.semanticReference.apply("sce-plan-context-sync", "Plan context synchronization phase") +local syncReport = workflow.semanticReference.apply("`references/sync-report.md`", "`references/output.md`") +local invokeOnly = workflow.semanticReference.apply("Invoke only", "Run only") +local invokedFor = workflow.semanticReference.apply("invoked for", "run for") +local returningReport = workflow.semanticReference.apply("Returning one Markdown synchronization report", "Recording one Markdown synchronization report") +local yamlFence = workflow.semanticReference.apply("yaml", "text") +local yaml = workflow.semanticReference.apply("YAML", "internal state") +local returnExactlyOneReportStatus = workflow.semanticReference.apply("Return exactly one report status", "Set exactly one report status") +local returnOnlyMarkdownReport = workflow.semanticReference.apply("Return only the Markdown report", "Record only the Markdown report") +local returnExecutionStyleResult = workflow.semanticReference.apply("Return an execution-style YAML result", "Return an execution-style internal state") +local markdownResult = workflow.semanticReference.apply("Markdown result", "internal state") +local returnInternalState = workflow.semanticReference.apply("Return YAML", "Return internal state") + +/// One canonical source for both context-sync packages. Named SKILL and report +/// sections preserve semantic ordering while role data owns lifecycle-specific +/// content. +class SyncReportRole { + title: String + inputStatus: (workflow.WorkflowRenderMode) -> String + syncedIdentity: (workflow.WorkflowRenderMode) -> String + syncedSummary: (workflow.WorkflowRenderMode) -> String + syncedVerification: (workflow.WorkflowRenderMode) -> String + noContextChangeIdentity: (workflow.WorkflowRenderMode) -> String + noContextChangeSummary: (workflow.WorkflowRenderMode) -> String + noContextChangeVerification: (workflow.WorkflowRenderMode) -> String + blockedIdentity: (workflow.WorkflowRenderMode) -> String + retryCondition: (workflow.WorkflowRenderMode) -> String + rules: (workflow.WorkflowRenderMode) -> String +} + class SyncRole { slug: String title: String - skillFragments: Listing - reportFragments: Listing + frontmatter: (workflow.WorkflowRenderMode) -> String + purpose: (workflow.WorkflowRenderMode) -> String + input: (workflow.WorkflowRenderMode) -> String + workflow: (workflow.WorkflowRenderMode) -> String + boundaries: (workflow.WorkflowRenderMode) -> String + completion: (workflow.WorkflowRenderMode) -> String + report: SyncReportRole } -local skillCommon0 = """ - --- - """ - -local taskSkillRole0 = """ - name: sce-task-context-sync - """ - -local planSkillRole0 = """ - name: sce-plan-context-sync - """ - -local skillCommon1 = """ - description: > - """ - -local taskSkillRole1 = """ - Internal SCE workflow skill that accepts a successful status: complete result - from sce-task-execution, reconciles the completed implementation with durable - """ - -local planSkillRole1 = """ - Internal SCE workflow skill that accepts a successful Status: validated - Markdown result from sce-validation, reconciles the finished plan with durable - """ - -local skillCommon2 = """ - repository context, and returns a Markdown synchronization report. Invoke only - """ - -local taskSkillRole2 = """ - after one task has been implemented and verified successfully. Do not implement - application code, change plan state, determine whether the plan is complete, - run final validation, or select another task. - """ - -local planSkillRole2 = """ - after final validation has passed. Do not implement application code, change - plan validation state, rerun full validation, or select another task. - """ - -local skillCommon3 = """ - --- - - """ +local skillBody = (role: SyncRole, mode: workflow.WorkflowRenderMode) -> new Listing { + role.purpose.apply(mode) + role.input.apply(mode) + role.workflow.apply(mode) + role.boundaries.apply(mode) + role.completion.apply(mode) +}.join("\n\n") + +local skillText = (role: SyncRole, mode: workflow.WorkflowRenderMode) -> + role.frontmatter.apply(mode) + "\n\n" + skillBody.apply(role, mode) + +local taskFrontmatterLines = (mode: workflow.WorkflowRenderMode) -> new Listing { + "name: \(taskContextSyncName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that accepts a successful status: complete result" + " from \(taskExecutionName.render.apply(mode)), reconciles the completed implementation with durable" + " repository context, and returns a Markdown synchronization report. \(invokeOnly.render.apply(mode))" + " after one task has been implemented and verified successfully. Do not implement" + " application code, change plan state, determine whether the plan is complete," + " run final validation, or select another task." +} -local taskSkillRole3 = """ +local taskRoleData = new SyncRole { + slug = "sce-task-context-sync" + title = "SCE Task Context Sync" + frontmatter = (mode: workflow.WorkflowRenderMode) -> + "---\n" + taskFrontmatterLines.apply(mode).join("\n") + "\n---" + purpose = (mode: workflow.WorkflowRenderMode) -> """ # SCE Task Context Sync - """ - -local planSkillRole3 = """ - # SCE Plan Context Sync - """ - -local skillCommon4 = """ ## Purpose - """ - -local taskSkillRole4 = """ Reconcile one completed task with the repository's durable context and return a Markdown report. - """ - -local planSkillRole4 = """ - Reconcile one fully validated plan with the repository's durable context and - return a Markdown report. - """ - -local skillCommon5 = """ This skill owns: - """ - -local taskSkillRole5 = """ - Validating the execution handoff. - """ - -local planSkillRole5 = """ - - Validating the validation handoff. - """ - -local skillCommon6 = """ - Confirming the context root exists. - """ - -local taskSkillRole6 = """ - Discovering the context affected by one completed task. - """ - -local planSkillRole6 = """ - - Discovering the context required by the finished plan. - """ - -local skillCommon7 = """ - Deciding whether durable context changed. - Editing and verifying the affected context files. - - Returning one Markdown synchronization report. + - \(returningReport.render.apply(mode)). Use the report format in: - `references/sync-report.md` - - """ - -local planSkillRole7 = """ - Task-level context sync may already have run after individual tasks. This skill - is the plan-level final pass: it starts from the plan's `Context sync` - requirements and the validated implementation, and closes gaps that remain. - + \(syncReport.render.apply(mode)) """ - -local skillCommon8 = """ + input = (mode: workflow.WorkflowRenderMode) -> """ ## Input The invoking workflow provides: - """ - -local taskSkillRole8 = """ - - The complete result returned by `sce-task-execution`. - """ - -local planSkillRole8 = """ - - The complete Markdown result returned by `sce-validation`. - """ - -local skillCommon9 = """ - - """ + - The complete result returned by \(taskExecution.render.apply(mode)). -local taskSkillRole9 = """ The execution result must have: - """ - -local planSkillRole9 = """ - The validation result must report: - """ - -local skillCommon10 = """ - - """ -local taskSkillRole10 = """ - ```yaml + ```\(yamlFence.render.apply(mode)) status: complete - """ - -local planSkillRole10 = """ - ```markdown - **Status:** validated - **Plan:** {plan path} - """ - -local skillCommon11 = """ ``` - """ - -local taskSkillRole11 = """ Treat the execution result as the authoritative handoff for: - """ - -local planSkillRole11 = """ - Treat that Markdown as the authoritative handoff for: - """ - -local skillCommon12 = """ - - """ -local taskSkillRole12 = """ - The resolved plan and completed task. - Files changed by implementation. - Implementation summary. - Verification evidence. - Done-check evidence. - Reported context impact. - """ - -local planSkillRole12 = """ - - The resolved plan path. - - Validation commands and outcomes. - - Acceptance-criteria evidence. - - Scaffolding removals. - - Reported context impact, required context paths, and affected areas. - """ -local skillCommon13 = """ - - """ - -local taskSkillRole13 = """ - This skill must not be invoked for `declined`, `blocked`, or `incomplete` + This skill must not be \(invokedFor.render.apply(mode)) `declined`, `blocked`, or `incomplete` execution results. - """ -local planSkillRole13 = """ - This skill must not be invoked for `failed` or `blocked` validation results. - Those are not success states. Same rule as `sce-task-context-sync`: context sync - runs only after a successful prior phase. - """ - -local skillCommon14 = """ - - """ - -local taskSkillRole14 = """ Do not reconstruct a missing execution result from conversation history. """ - -local planSkillRole14 = """ - Do not reconstruct a missing validation result from conversation history. - """ - -local skillCommon15 = """ - + workflow = (mode: workflow.WorkflowRenderMode) -> """ ## Workflow - """ - -local taskSkillRole15 = """ ### 1. Validate the execution handoff - """ - -local planSkillRole15 = """ - ### 1. Validate the validation handoff - """ - -local skillCommon16 = """ Confirm that: - """ - -local taskSkillRole16 = """ - `status` is exactly `complete`. - A `plan` object with a `path` is present. - Exactly one completed task is identified. - Changed files and an implementation summary are present. - Verification evidence is present. - Done-check evidence is present. - """ - -local planSkillRole16 = """ - - `Status:` is exactly `validated`. - - `Plan:` names an existing plan path. - - Acceptance-criteria evidence is present and every criterion is met. - - Commands run are present. - """ - -local skillCommon17 = """ - A context-impact classification is present. If the handoff is missing required information or is internally contradictory, @@ -279,70 +150,23 @@ local skillCommon17 = """ `sce setup --bootstrap-context` - """ - -local taskSkillRole17 = """ State that the task itself is complete and recorded in the plan, and that synchronization should run again once the context root exists. - """ - -local planSkillRole17 = """ - State that validation itself succeeded and is recorded in the plan, and that - plan context synchronization should run again once the context root exists. - """ - -local skillCommon18 = """ Bootstrapping is the user's action, not this skill's. ### 3. Discover applicable context - """ - -local taskSkillRole18 = """ Start with the execution result: - """ - -local planSkillRole18 = """ - Start with the validated Markdown result: - """ - -local skillCommon19 = """ - - """ -local taskSkillRole19 = """ - `context_impact.classification` - `context_impact.affected_areas` - Changed files. - Implementation summary. - Done-check evidence. - """ - -local planSkillRole19 = """ - - **Context impact** classification, required context, and affected areas. - - Acceptance-criteria evidence. - - Commands run. - """ - -local skillCommon20 = """ - - """ -local taskSkillRole20 = """ Then inspect existing repository context in this order when present: - """ - -local planSkillRole20 = """ - Then read the plan's `Context sync` section and inspect existing repository - context in this order when present: - """ - -local skillCommon21 = """ - - """ -local taskSkillRole21 = """ 1. `context/context-map.md` 2. Context files for the affected domain or subsystem 3. `context/overview.md` @@ -350,21 +174,6 @@ local taskSkillRole21 = """ 5. `context/glossary.md` 6. `context/patterns.md` 7. Operational, product, or decision records directly related to the change - """ - -local planSkillRole21 = """ - 1. Paths named by the plan's `Context sync` section - 2. `context/context-map.md` - 3. Context files for the affected domain or subsystem - 4. `context/overview.md` - 5. `context/architecture.md` - 6. `context/glossary.md` - 7. `context/patterns.md` - 8. Operational, product, or decision records directly related to the finished - change - """ - -local skillCommon22 = """ Use the context map and existing links to locate authoritative files. @@ -386,53 +195,19 @@ local skillCommon22 = """ Verifying is not editing. A classification that warrants no root edit still requires reading each of these and confirming it is not contradicted by the - """ - -local taskSkillRole22 = """ completed implementation. A file that is absent is a gap; record it in the - """ - -local planSkillRole22 = """ - finished implementation. A file that is absent is a gap; record it in the - """ - -local skillCommon23 = """ report rather than creating it to satisfy the pass. Report each of the five as verified or edited. Never declare synchronization done while one of them is unchecked. - """ - -local taskSkillRole23 = """ Do not create a new context file when an existing authoritative file can be updated coherently. - """ - -local planSkillRole23 = """ - #### Plan context requirements - - Every path or statement listed under the plan's `Context sync` section must be - accounted for in the report as already accurate or updated. A requirement the - finished code still does not satisfy is a blocker, not a note. - """ - -local skillCommon24 = """ ### 4. Determine whether durable context changed Use the reported context impact as a strong hint, then verify it against the - """ - -local taskSkillRole24 = """ implementation and existing context. - """ - -local planSkillRole24 = """ - finished implementation and existing context. - """ - -local skillCommon25 = """ Durable context includes non-obvious repository knowledge such as: @@ -449,64 +224,25 @@ local skillCommon25 = """ - Details already obvious from the implementation. - Temporary debugging information. - A file-by-file narration of the change. - """ - -local taskSkillRole25 = """ - Test output that belongs only in task evidence. - Speculation or future work not established by the completed implementation. - """ - -local planSkillRole25 = """ - - Test output that belongs only in validation evidence. - - Speculation or future work not established by the finished plan. - """ - -local skillCommon26 = """ - Generic engineering practices. Interpret impact classifications as follows. Each governs which files are - """ - -local taskSkillRole26 = """ *edited*; none of them waives the mandatory root pass. - """ - -local planSkillRole26 = """ - *edited*; none of them waives the mandatory root pass or the plan's Context - sync requirements. - """ - -local skillCommon27 = """ - - """ -local taskSkillRole27 = """ - `none`: Make no edits beyond any correction the root pass turns up. - """ - -local planSkillRole27 = """ - - `none`: Make no edits beyond any correction the root pass or unmet plan - context requirement turns up. - """ - -local skillCommon28 = """ - `local`: Update the nearest existing authoritative context only when the new behavior is not reliably discoverable from code. - `domain`: Update affected domain context and the context map when its links or summaries changed. - `root`: Update the relevant root context and any affected domain context. - """ - -local taskSkillRole28 = """ A change is `root` when it introduces cross-cutting behavior, repository-wide policy or contracts, an architecture or ownership boundary, or a change to canonical terminology. A change confined to one feature or domain, with no repository-wide behavior, architecture, or terminology impact, is `domain` or `local`: capture its detail in domain files and leave the root files unedited. - """ - -local skillCommon29 = """ If the reported classification is inconsistent with the actual change, use the verified classification and explain the difference in the report. @@ -517,44 +253,13 @@ local skillCommon29 = """ When editing context: - """ - -local taskSkillRole29 = """ - Describe the resulting behavior, not the implementation session. - """ - -local planSkillRole29 = """ - - Describe the resulting behavior, not the validation session. - """ - -local skillCommon30 = """ - Preserve repository terminology and document structure. - """ - -local taskSkillRole30 = """ - Remove or correct statements contradicted by the completed implementation. - """ - -local planSkillRole30 = """ - - Remove or correct statements contradicted by the finished implementation. - """ - -local skillCommon31 = """ - Update cross-references when files are added, moved, renamed, or superseded. - Keep one authoritative statement for each durable fact. - """ - -local taskSkillRole31 = """ - Avoid copying the execution result verbatim into context files. - Do not change application code, tests, or plan state. - """ - -local planSkillRole31 = """ - - Avoid copying the validation result verbatim into context files. - - Do not change application code, tests, or plan validation evidence. - """ - -local skillCommon32 = """ Create a new context file only when: @@ -564,68 +269,24 @@ local skillCommon32 = """ #### Feature existence - """ - -local taskSkillRole32 = """ Every feature the completed task implemented must have at least one durable - """ - -local planSkillRole32 = """ - Every feature the finished plan implemented must have at least one durable - """ - -local skillCommon33 = """ canonical description discoverable from `context/`, in a domain file under `context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - """ - -local taskSkillRole33 = """ When the task implemented a feature no context file describes, add that description. A feature that fits no existing domain file gets a new focused file; do not defer it to a later task. Prefer a small, precise domain file over overloading `overview.md` with detail. - """ - -local planSkillRole33 = """ - When the plan delivered a feature no context file describes, add that - description. Prefer a small, precise domain file over overloading - `overview.md` with detail. - """ -local skillCommon34 = """ - - """ - -local taskSkillRole34 = """ This is the one case where documentation is warranted by the change itself rather than by a gap in durable knowledge. It is not license to narrate the diff: describe what the feature is and how it behaves, not what was edited. - """ - -local planSkillRole34 = """ - This is not license to narrate the diff: describe what the feature is and how - it behaves, not what was edited during the plan. - """ - -local skillCommon35 = """ #### Glossary - """ - -local taskSkillRole35 = """ Add a `context/glossary.md` entry for any domain language the task introduced. New terminology is durable knowledge whatever the classification is: a `domain` change that names a new concept still earns its glossary entry. - """ - -local planSkillRole35 = """ - Add a `context/glossary.md` entry for any domain language the plan introduced. - New terminology is durable knowledge whatever the classification is. - """ - -local skillCommon36 = """ #### File hygiene @@ -646,33 +307,11 @@ local skillCommon36 = """ After edits, verify: - """ - -local taskSkillRole36 = """ - Every changed context file accurately reflects the completed implementation. - No edited statement contradicts the code, plan, or execution evidence. - """ - -local planSkillRole36 = """ - - Every changed context file accurately reflects the finished implementation. - - No edited statement contradicts the code, plan, or validation evidence. - """ - -local skillCommon37 = """ - Every file in the mandatory root pass was read and confirmed against code truth, whether or not it was edited. - """ - -local taskSkillRole37 = """ - Each feature implemented by the task has a durable canonical description - """ - -local planSkillRole37 = """ - - Every plan `Context sync` requirement is met. - - Each feature implemented by the plan has a durable canonical description - """ - -local skillCommon38 = """ reachable from `context/`. - Every changed file is at or below 250 lines, covers one topic, and links other context files by relative path. @@ -685,17 +324,7 @@ local skillCommon38 = """ Use focused documentation, link, or formatting checks when available. - """ - -local taskSkillRole38 = """ Do not run full application or plan validation. - """ - -local planSkillRole38 = """ - Do not rerun full-plan validation. - """ - -local skillCommon39 = """ If synchronization cannot be completed without inventing facts or resolving a material contradiction, preserve safe edits when appropriate and return a @@ -703,7 +332,7 @@ local skillCommon39 = """ ### 7. Return the Markdown report - Return exactly one report status: + \(returnExactlyOneReportStatus.render.apply(mode)): - `synced` - `no_context_change` @@ -713,71 +342,33 @@ local skillCommon39 = """ means existing context was checked and no edit was warranted. `blocked` means context could not be synchronized safely. - Return only the Markdown report. Do not add explanatory prose before or after + \(returnOnlyMarkdownReport.render.apply(mode)). Do not add explanatory prose before or after it. - """ - -local taskSkillRole39 = """ Do not determine whether the plan is complete. The invoking `/next-task` workflow owns that decision after context synchronization. - """ - -local skillCommon40 = """ + boundaries = (mode: workflow.WorkflowRenderMode) -> """ ## Boundaries Do not: - """ - -local taskSkillRole40 = """ - Accept an execution result whose status is not `complete`. - """ - -local planSkillRole40 = """ - - Accept a validation result whose status is not `validated`. - - Accept `failed` or `blocked` validation results. - """ - -local skillCommon41 = """ - Implement or modify application code. - Modify tests. - """ - -local taskSkillRole41 = """ - Change task completion status or plan evidence. - Determine whether the plan is complete. - Select or execute another task. - Run full-plan validation. - Mark the plan validated, closed, or archived. - """ - -local planSkillRole41 = """ - - Change task completion status, acceptance-criteria marks, or the Validation - Report. - - Rerun full-plan validation. - - Select or execute an implementation task. - """ - -local skillCommon42 = """ - Create a Git commit or push changes. - Create the context root. `sce setup --bootstrap-context` owns that. - Narrate changed files as documentation. Feature existence is the only reason to document a change that introduced no other durable knowledge. - Delete a context file that has uncommitted changes. + - \(returnExecutionStyleResult.render.apply(mode)). """ - -local taskSkillRole42 = """ - - Return an execution-style YAML result. - """ - -local planSkillRole42 = """ - - Return YAML. - """ - -local skillCommon43 = """ - + completion = (mode: workflow.WorkflowRenderMode) -> """ ## Completion The skill is complete after: @@ -785,278 +376,396 @@ local skillCommon43 = """ - The context root was confirmed, or a `blocked` report named `sce setup --bootstrap-context` as the required action. - The mandatory root pass was run. - """ - -local planSkillRole43 = """ - - Plan context requirements were checked. - """ - -local skillCommon44 = """ - Applicable durable context was synchronized and verified, no context change was warranted, or a synchronization blocker was reported. - - One Markdown report matching `references/sync-report.md` was returned. + - One Markdown report matching \(syncReport.render.apply(mode)) was returned. """ +} -local taskReportRole0 = """ - # Context Sync Report - """ +local planFrontmatterLines = (mode: workflow.WorkflowRenderMode) -> new Listing { + "name: \(planContextSyncName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that accepts a successful Status: validated" + " \(markdownResult.render.apply(mode)) from \(validationName.render.apply(mode)), reconciles the finished plan with durable" + " repository context, and returns a Markdown synchronization report. \(invokeOnly.render.apply(mode))" + " after final validation has passed. Do not implement application code, change" + " plan validation state, rerun full validation, or select another task." +} -local planReportRole0 = """ - # Plan Context Sync Report - """ +local planRoleData = new SyncRole { + slug = "sce-plan-context-sync" + title = "SCE Plan Context Sync" + frontmatter = (mode: workflow.WorkflowRenderMode) -> + "---\n" + planFrontmatterLines.apply(mode).join("\n") + "\n---" + purpose = (mode: workflow.WorkflowRenderMode) -> """ + # SCE Plan Context Sync -local reportCommon0 = """ + ## Purpose - Return only one completed Markdown report using the applicable variant below. - Do not include unused sections, placeholders, YAML, or a fenced code block. + Reconcile one fully validated plan with the repository's durable context and + return a Markdown report. - The `Status` value must be exactly one of: + This skill owns: - - `synced` - - `no_context_change` - - `blocked` + - Validating the validation handoff. + - Confirming the context root exists. + - Discovering the context required by the finished plan. + - Deciding whether durable context changed. + - Editing and verifying the affected context files. + - \(returningReport.render.apply(mode)). - """ + Use the report format in: -local taskReportRole1 = """ - The input execution status is always `complete` and does not need to be repeated - as a separate workflow state. - """ + \(syncReport.render.apply(mode)) -local planReportRole1 = """ - The input validation status is always `validated` and does not need to be - repeated as a separate workflow state. This skill is not invoked for `failed` - or `blocked` validation results. + Task-level context sync may already have run after individual tasks. This skill + is the plan-level final pass: it starts from the plan's `Context sync` + requirements and the validated implementation, and closes gaps that remain. """ + input = (mode: workflow.WorkflowRenderMode) -> """ + ## Input -local reportCommon1 = """ - - ## Synced variant + The invoking workflow provides: - """ + - The complete \(markdownResult.render.apply(mode)) returned by \(validation.render.apply(mode)). -local taskReportRole2 = """ - # Context Sync Report - """ + The validation result must report: -local planReportRole2 = """ - # Plan Context Sync Report - """ + ```markdown + **Status:** validated + **Plan:** {plan path} + ``` -local reportCommon2 = """ + Treat that Markdown as the authoritative handoff for: - **Status:** synced\(" ") - """ + - The resolved plan path. + - Validation commands and outcomes. + - Acceptance-criteria evidence. + - Scaffolding removals. + - Reported context impact, required context paths, and affected areas. -local taskReportRole3 = """ - **Plan:** `{plan path}`\(" ") - **Task:** `{task id} — {task title}` - """ + This skill must not be \(invokedFor.render.apply(mode)) `failed` or `blocked` validation results. + Those are not success states. Same rule as \(taskContextSync.render.apply(mode)): context sync + runs only after a successful prior phase. -local planReportRole3 = """ - **Plan:** `{plan path}` + Do not reconstruct a missing validation result from conversation history. """ + workflow = (mode: workflow.WorkflowRenderMode) -> """ + ## Workflow -local reportCommon3 = """ + ### 1. Validate the validation handoff - """ + Confirm that: -local taskReportRole4 = """ - ## Updated files + - `Status:` is exactly `validated`. + - `Plan:` names an existing plan path. + - Acceptance-criteria evidence is present and every criterion is met. + - Commands run are present. + - A context-impact classification is present. - - {List each changed file from the execution handoff except paths under - `context/`; state `None.` when no files remain.} - """ + If the handoff is missing required information or is internally contradictory, + do not modify context. Return a `blocked` Markdown report. -local planReportRole4 = """ - ## Context impact + ### 2. Confirm the context root - **Classification:** `{local | domain | root}`\(" ") - **Affected areas:** `{comma-separated areas}` + When `context/` does not exist, there is no durable memory to synchronize. + Do not create it, and do not write context files outside it. - {Explain which durable behavior, architecture, terminology, operation, or - constraint required plan-level synchronization after validation.} + Return a `blocked` report whose required action is: - ## Plan context requirements + `sce setup --bootstrap-context` - - `{required context path or statement from the plan}` — {met by edit | already accurate} - """ + State that validation itself succeeded and is recorded in the plan, and that + plan context synchronization should run again once the context root exists. -local reportCommon4 = """ + Bootstrapping is the user's action, not this skill's. - ## Updated context + ### 3. Discover applicable context - - `{context file}` — {concise description of the durable truth updated} + Start with the validated \(markdownResult.render.apply(mode)): - """ + - **Context impact** classification, required context, and affected areas. + - Acceptance-criteria evidence. + - Commands run. -local taskReportRole5 = """ - ## Feature existence + Then read the plan's `Context sync` section and inspect existing repository + context in this order when present: - - `{feature}` — `{context file that canonically describes it}` + 1. Paths named by the plan's `Context sync` section + 2. `context/context-map.md` + 3. Context files for the affected domain or subsystem + 4. `context/overview.md` + 5. `context/architecture.md` + 6. `context/glossary.md` + 7. `context/patterns.md` + 8. Operational, product, or decision records directly related to the finished + change - ## Verification + Use the context map and existing links to locate authoritative files. - - {How the edited context was checked against implementation and execution evidence.} - """ + Do not scan or rewrite the entire `context/` tree by default. -local planReportRole5 = """ - ## Root pass + Do not create a new context file when an existing authoritative file can be + updated coherently. - - `context/overview.md` — {verified | edited | absent} - - `context/architecture.md` — {verified | edited | absent} - - `context/glossary.md` — {verified | edited | absent} - - `context/patterns.md` — {verified | edited | absent} - - `context/context-map.md` — {verified | edited | absent} + #### The mandatory root pass - ## Feature existence + Every invocation verifies these five files against code truth, whatever the + reported classification is: - - `{feature}` — `{context file that canonically describes it}` + - `context/overview.md` + - `context/architecture.md` + - `context/glossary.md` + - `context/patterns.md` + - `context/context-map.md` - ## Verification + Verifying is not editing. A classification that warrants no root edit still + requires reading each of these and confirming it is not contradicted by the + finished implementation. A file that is absent is a gap; record it in the + report rather than creating it to satisfy the pass. - - {How the edited context was checked against the finished implementation and validation evidence.} - """ + Report each of the five as verified or edited. Never declare synchronization + done while one of them is unchecked. -local reportCommon5 = """ - - {File hygiene: line counts, relative links, diagrams where structure is complex.} - - {Documentation, link, or formatting checks that were run, when applicable.} + #### Plan context requirements - ## Notes + Every path or statement listed under the plan's `Context sync` section must be + accounted for in the report as already accurate or updated. A requirement the + finished code still does not satisfy is a blocker, not a note. - {Include only non-blocking information the invoking workflow should retain. - Omit this section when unnecessary.} + ### 4. Determine whether durable context changed - --- + Use the reported context impact as a strong hint, then verify it against the + finished implementation and existing context. - ## No-context-change variant + Durable context includes non-obvious repository knowledge such as: - """ + - User-visible or externally observable behavior. + - Architecture, boundaries, ownership, and dependency direction. + - Public interfaces, data contracts, and persistence behavior. + - Operational procedures and important failure modes. + - Security or privacy behavior. + - Shared terminology. + - Intentional limitations and meaningful design decisions. -local taskReportRole6 = """ - # Context Sync Report - """ + Do not document: -local planReportRole6 = """ - # Plan Context Sync Report - """ + - Details already obvious from the implementation. + - Temporary debugging information. + - A file-by-file narration of the change. + - Test output that belongs only in validation evidence. + - Speculation or future work not established by the finished plan. + - Generic engineering practices. -local reportCommon6 = """ + Interpret impact classifications as follows. Each governs which files are + *edited*; none of them waives the mandatory root pass or the plan's Context + sync requirements. - **Status:** no_context_change\(" ") - """ + - `none`: Make no edits beyond any correction the root pass or unmet plan + context requirement turns up. + - `local`: Update the nearest existing authoritative context only when the new + behavior is not reliably discoverable from code. + - `domain`: Update affected domain context and the context map when its links or + summaries changed. + - `root`: Update the relevant root context and any affected domain context. -local taskReportRole7 = """ - **Plan:** `{plan path}`\(" ") - **Task:** `{task id} — {task title}` - """ + If the reported classification is inconsistent with the actual change, use the + verified classification and explain the difference in the report. -local planReportRole7 = """ - **Plan:** `{plan path}` - """ + ### 5. Synchronize context -local reportCommon7 = """ + Make the smallest coherent documentation change that preserves repository truth. - """ + When editing context: -local taskReportRole8 = """ - ## Updated files + - Describe the resulting behavior, not the validation session. + - Preserve repository terminology and document structure. + - Remove or correct statements contradicted by the finished implementation. + - Update cross-references when files are added, moved, renamed, or superseded. + - Keep one authoritative statement for each durable fact. + - Avoid copying the validation result verbatim into context files. + - Do not change application code, tests, or plan validation evidence. - - {List each changed file from the execution handoff except paths under - `context/`; state `None.` when no files remain.} + Create a new context file only when: - ## Synchronization result + - The knowledge is durable and non-obvious. + - No existing file owns it coherently. + - The new file has a clear place in the context map. - {Explain why the completed implementation did not introduce durable, - non-obvious repository knowledge requiring an update.} - """ + #### Feature existence -local planReportRole8 = """ - ## Context impact + Every feature the finished plan implemented must have at least one durable + canonical description discoverable from `context/`, in a domain file under + `context/{domain}/` or in `context/overview.md` for a cross-cutting feature. - **Classification:** none + When the plan delivered a feature no context file describes, add that + description. Prefer a small, precise domain file over overloading + `overview.md` with detail. - {Explain why the finished plan introduced no durable, non-obvious repository - knowledge requiring an update, or why existing context already matched.} + This is not license to narrate the diff: describe what the feature is and how + it behaves, not what was edited during the plan. - ## Plan context requirements + #### Glossary - - `{required context path or statement from the plan}` — already accurate - - None listed by the plan. - """ + Add a `context/glossary.md` entry for any domain language the plan introduced. + New terminology is durable knowledge whatever the classification is. -local reportCommon8 = """ + #### File hygiene - ## Context reviewed + Every context file this skill writes must satisfy: - - `{context file or area}` — {what was checked and why it remains accurate} + - One topic per file. + - At most 250 lines. When an edit would push a file past 250 lines, split it + into focused files and link them rather than letting it grow. + - Relative paths in every link to another context file. + - A Mermaid diagram where structure, boundaries, or flows are complex enough + that prose alone would not carry them. + - Concrete code examples only where they clarify non-trivial behavior. - """ + When detail outgrows a shared file, migrate it into `context/{domain}/`, leave a + concise pointer behind, and link the new file from `context/context-map.md`. -local taskReportRole9 = """ - ## Feature existence + ### 6. Verify synchronization - - `{feature}` — `{context file that canonically describes it}`, already present. + After edits, verify: - ## Verification + - Every changed context file accurately reflects the finished implementation. + - No edited statement contradicts the code, plan, or validation evidence. + - Every file in the mandatory root pass was read and confirmed against code + truth, whether or not it was edited. + - Every plan `Context sync` requirement is met. + - Each feature implemented by the plan has a durable canonical description + reachable from `context/`. + - Every changed file is at or below 250 lines, covers one topic, and links other + context files by relative path. + - Diagrams are present where structure, boundaries, or flows are complex. + - Links and referenced paths resolve when practical to check. + - New context files are reachable from the context map or another authoritative + index. + - Root context remains concise and delegates details to domain files. + - Unrelated context was not changed. - - {How existing context was compared with implementation and execution evidence.} - """ + Use focused documentation, link, or formatting checks when available. -local planReportRole9 = """ - ## Root pass + Do not rerun full-plan validation. - - `context/overview.md` — {verified | absent} - - `context/architecture.md` — {verified | absent} - - `context/glossary.md` — {verified | absent} - - `context/patterns.md` — {verified | absent} - - `context/context-map.md` — {verified | absent} + If synchronization cannot be completed without inventing facts or resolving a + material contradiction, preserve safe edits when appropriate and return a + `blocked` report. - ## Feature existence + ### 7. Return the Markdown report - - `{feature}` — `{context file that canonically describes it}`, already present. + \(returnExactlyOneReportStatus.render.apply(mode)): - ## Verification + - `synced` + - `no_context_change` + - `blocked` - - {How existing context was compared with the finished implementation and validation evidence.} + `synced` means context files were updated and verified. `no_context_change` + means existing context was checked and no edit was warranted. `blocked` means + context could not be synchronized safely. + + \(returnOnlyMarkdownReport.render.apply(mode)). Do not add explanatory prose before or after + it. """ + boundaries = (mode: workflow.WorkflowRenderMode) -> """ + ## Boundaries -local reportCommon9 = """ + Do not: - --- + - Accept a validation result whose status is not `validated`. + - Accept `failed` or `blocked` validation results. + - Implement or modify application code. + - Modify tests. + - Change task completion status, acceptance-criteria marks, or the Validation + Report. + - Rerun full-plan validation. + - Select or execute an implementation task. + - Create a Git commit or push changes. + - Create the context root. `sce setup --bootstrap-context` owns that. + - Narrate changed files as documentation. Feature existence is the only reason + to document a change that introduced no other durable knowledge. + - Delete a context file that has uncommitted changes. + - \(returnInternalState.render.apply(mode)). + """ + completion = (mode: workflow.WorkflowRenderMode) -> """ + ## Completion - ## Blocked variant + The skill is complete after: + - The context root was confirmed, or a `blocked` report named + `sce setup --bootstrap-context` as the required action. + - The mandatory root pass was run. + - Plan context requirements were checked. + - Applicable durable context was synchronized and verified, no context change + was warranted, or a synchronization blocker was reported. + - One Markdown report matching \(syncReport.render.apply(mode)) was returned. """ +} -local taskReportRole10 = """ - # Context Sync Report - """ +local reportIntroduction = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> """ + # \(role.title) -local planReportRole10 = """ - # Plan Context Sync Report - """ + Return only one completed Markdown report using the applicable variant below. + Do not include unused sections, placeholders, \(yaml.render.apply(mode)), or a fenced code block. -local reportCommon10 = """ + The `Status` value must be exactly one of: - **Status:** blocked\(" ") + - `synced` + - `no_context_change` + - `blocked` + + \(role.inputStatus.apply(mode)) """ -local taskReportRole11 = """ - **Plan:** `{plan path}`\(" ") - **Task:** `{task id} — {task title}` +local syncedReport = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> """ + ## Synced variant - ## Updated files + # \(role.title) - - {List each changed file from the execution handoff except paths under - `context/`; state `None.` when no files remain.} + **Status:** synced\(" ") + \(role.syncedIdentity.apply(mode)) + + \(role.syncedSummary.apply(mode)) + + ## Updated context + + - `{context file}` — {concise description of the durable truth updated} + + \(role.syncedVerification.apply(mode)) + - {File hygiene: line counts, relative links, diagrams where structure is complex.} + - {Documentation, link, or formatting checks that were run, when applicable.} + + ## Notes + + {Include only non-blocking information the invoking workflow should retain. + Omit this section when unnecessary.} """ -local planReportRole11 = """ - **Plan:** `{plan path}` +local noContextChangeReport = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> """ + ## No-context-change variant + + # \(role.title) + + **Status:** no_context_change\(" ") + \(role.noContextChangeIdentity.apply(mode)) + + \(role.noContextChangeSummary.apply(mode)) + + ## Context reviewed + + - `{context file or area}` — {what was checked and why it remains accurate} + + \(role.noContextChangeVerification.apply(mode)) """ -local reportCommon11 = """ +local blockedReport = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> """ + ## Blocked variant + + # \(role.title) + + **Status:** blocked\(" ") + \(role.blockedIdentity.apply(mode)) ## Blocker @@ -1070,323 +779,240 @@ local reportCommon11 = """ ## Retry condition + \(role.retryCondition.apply(mode)) """ -local taskReportRole12 = """ - {State the concrete condition under which context synchronization should run - again.} +local reportRules = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> """ + ## Report rules + + - Name exact context files when they were changed or reviewed. + \(role.rules.apply(mode)) + """ + +local reportText = (role: SyncReportRole, mode: workflow.WorkflowRenderMode) -> new Listing { + reportIntroduction.apply(role, mode) + syncedReport.apply(role, mode) + "---" + noContextChangeReport.apply(role, mode) + "---" + blockedReport.apply(role, mode) + reportRules.apply(role, mode) +}.join("\n\n") + +local taskReport = new SyncReportRole { + title = "Context Sync Report" + inputStatus = (mode: workflow.WorkflowRenderMode) -> """ + The input execution status is always `complete` and does not need to be repeated + as a separate workflow state. + """ + syncedIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` """ + syncedSummary = (mode: workflow.WorkflowRenderMode) -> """ + ## Updated files -local planReportRole12 = """ - {State the concrete condition under which plan context synchronization should - run again.} + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} """ + syncedVerification = (mode: workflow.WorkflowRenderMode) -> """ + ## Feature existence -local reportCommon12 = """ + - `{feature}` — `{context file that canonically describes it}` - ## Report rules + ## Verification - - Name exact context files when they were changed or reviewed. + - {How the edited context was checked against implementation and execution evidence.} """ + noContextChangeIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` + """ + noContextChangeSummary = (mode: workflow.WorkflowRenderMode) -> """ + ## Updated files -local taskReportRole13 = """ - - Under **Updated files**, list every changed file from the execution handoff - except paths under `context/`. + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + + ## Synchronization result + + {Explain why the completed implementation did not introduce durable, + non-obvious repository knowledge requiring an update.} """ + noContextChangeVerification = (mode: workflow.WorkflowRenderMode) -> """ + ## Feature existence -local planReportRole13 = """ - - Report every file in the root pass, including any that is absent. + - `{feature}` — `{context file that canonically describes it}`, already present. + + ## Verification + + - {How existing context was compared with implementation and execution evidence.} """ + blockedIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}`\(" ") + **Task:** `{task id} — {task title}` -local reportCommon13 = """ + ## Updated files + + - {List each changed file from the execution handoff except paths under + `context/`; state `None.` when no files remain.} + """ + retryCondition = (mode: workflow.WorkflowRenderMode) -> """ + {State the concrete condition under which context synchronization should run + again.} + """ + rules = (mode: workflow.WorkflowRenderMode) -> """ + - Under **Updated files**, list every changed file from the execution handoff + except paths under `context/`. - Report the missing context root as `blocked`, with `sce setup --bootstrap-context` as the required action and the existence of `context/` as the retry condition. - """ - -local taskReportRole14 = """ - Omit **Feature existence** only when the task implemented no feature. - Describe durable truth, not implementation-session chronology. + - Keep evidence concise and factual. + - Do not claim final validation passed. + - Do not determine whether the plan is complete. + - Do not recommend a next implementation task. """ +} -local planReportRole14 = """ - - Cover every path or statement listed in the plan's `Context sync` section - under **Plan context requirements**. - - Omit **Feature existence** only when the plan implemented no feature. - - Describe durable truth, not validation-session chronology. +local planReport = new SyncReportRole { + title = "Plan Context Sync Report" + inputStatus = (mode: workflow.WorkflowRenderMode) -> """ + The input validation status is always `validated` and does not need to be + repeated as a separate workflow state. This skill is not \(invokedFor.render.apply(mode)) `failed` + or `blocked` validation results. """ + syncedIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}` + """ + syncedSummary = (mode: workflow.WorkflowRenderMode) -> """ + ## Context impact -local reportCommon14 = """ - - Keep evidence concise and factual. + **Classification:** `{local | domain | root}`\(" ") + **Affected areas:** `{comma-separated areas}` + + {Explain which durable behavior, architecture, terminology, operation, or + constraint required plan-level synchronization after validation.} + + ## Plan context requirements + + - `{required context path or statement from the plan}` — {met by edit | already accurate} """ + syncedVerification = (mode: workflow.WorkflowRenderMode) -> """ + ## Root pass -local taskReportRole15 = """ - - Do not claim final validation passed. - - Do not determine whether the plan is complete. - - Do not recommend a next implementation task. + - `context/overview.md` — {verified | edited | absent} + - `context/architecture.md` — {verified | edited | absent} + - `context/glossary.md` — {verified | edited | absent} + - `context/patterns.md` — {verified | edited | absent} + - `context/context-map.md` — {verified | edited | absent} + + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}` + + ## Verification + + - {How the edited context was checked against the finished implementation and validation evidence.} """ + noContextChangeIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}` + """ + noContextChangeSummary = (mode: workflow.WorkflowRenderMode) -> """ + ## Context impact + + **Classification:** none + + {Explain why the finished plan introduced no durable, non-obvious repository + knowledge requiring an update, or why existing context already matched.} + + ## Plan context requirements + + - `{required context path or statement from the plan}` — already accurate + - None listed by the plan. + """ + noContextChangeVerification = (mode: workflow.WorkflowRenderMode) -> """ + ## Root pass + + - `context/overview.md` — {verified | absent} + - `context/architecture.md` — {verified | absent} + - `context/glossary.md` — {verified | absent} + - `context/patterns.md` — {verified | absent} + - `context/context-map.md` — {verified | absent} + + ## Feature existence + + - `{feature}` — `{context file that canonically describes it}`, already present. + + ## Verification -local planReportRole15 = """ + - {How existing context was compared with the finished implementation and validation evidence.} + """ + blockedIdentity = (mode: workflow.WorkflowRenderMode) -> """ + **Plan:** `{plan path}` + """ + retryCondition = (mode: workflow.WorkflowRenderMode) -> """ + {State the concrete condition under which plan context synchronization should + run again.} + """ + rules = (mode: workflow.WorkflowRenderMode) -> """ + - Report every file in the root pass, including any that is absent. + - Report the missing context root as `blocked`, with `sce setup + --bootstrap-context` as the required action and the existence of `context/` as + the retry condition. + - Cover every path or statement listed in the plan's `Context sync` section + under **Plan context requirements**. + - Omit **Feature existence** only when the plan implemented no feature. + - Describe durable truth, not validation-session chronology. + - Keep evidence concise and factual. - Do not claim implementation tasks remain open. - Do not reopen validation checks. - Do not recommend a next implementation task unless context cannot be repaired without one, and then only as the required action. """ +} -local taskRole = new SyncRole { - slug = "sce-task-context-sync" - title = "SCE Task Context Sync" - skillFragments = new Listing { - skillCommon0 - taskSkillRole0 - skillCommon1 - taskSkillRole1 - skillCommon2 - taskSkillRole2 - skillCommon3 - taskSkillRole3 - skillCommon4 - taskSkillRole4 - skillCommon5 - taskSkillRole5 - skillCommon6 - taskSkillRole6 - skillCommon7 - skillCommon8 - taskSkillRole8 - skillCommon9 - taskSkillRole9 - skillCommon10 - taskSkillRole10 - skillCommon11 - taskSkillRole11 - skillCommon12 - taskSkillRole12 - skillCommon13 - taskSkillRole13 - skillCommon14 - taskSkillRole14 - skillCommon15 - taskSkillRole15 - skillCommon16 - taskSkillRole16 - skillCommon17 - taskSkillRole17 - skillCommon18 - taskSkillRole18 - skillCommon19 - taskSkillRole19 - skillCommon20 - taskSkillRole20 - skillCommon21 - taskSkillRole21 - skillCommon22 - taskSkillRole22 - skillCommon23 - taskSkillRole23 - skillCommon24 - taskSkillRole24 - skillCommon25 - taskSkillRole25 - skillCommon26 - taskSkillRole26 - skillCommon27 - taskSkillRole27 - skillCommon28 - taskSkillRole28 - skillCommon29 - taskSkillRole29 - skillCommon30 - taskSkillRole30 - skillCommon31 - taskSkillRole31 - skillCommon32 - taskSkillRole32 - skillCommon33 - taskSkillRole33 - skillCommon34 - taskSkillRole34 - skillCommon35 - taskSkillRole35 - skillCommon36 - taskSkillRole36 - skillCommon37 - taskSkillRole37 - skillCommon38 - taskSkillRole38 - skillCommon39 - taskSkillRole39 - skillCommon40 - taskSkillRole40 - skillCommon41 - taskSkillRole41 - skillCommon42 - taskSkillRole42 - skillCommon43 - skillCommon44 +local planOutputReportRole = (planReport) { + inputStatus = (mode: workflow.WorkflowRenderMode) -> """ + The input validation status is always `validated` and does not need to be + repeated as a separate workflow state. This skill is not run for `failed` + or `blocked` validation results. + """ +} + +local taskRole = (taskRoleData) { + report = taskReport +} + +local planRole = (planRoleData) { + report = planReport +} + +hidden taskStructuredSkill = new workflow.StructuredWorkflowDocument { + path = taskRole.slug + frontmatter = new workflow.WorkflowFrontmatter { + lines = (mode: workflow.WorkflowRenderMode) -> taskFrontmatterLines.apply(mode) } - reportFragments = new Listing { - taskReportRole0 - reportCommon0 - taskReportRole1 - reportCommon1 - taskReportRole2 - reportCommon2 - taskReportRole3 - reportCommon3 - taskReportRole4 - reportCommon4 - taskReportRole5 - reportCommon5 - taskReportRole6 - reportCommon6 - taskReportRole7 - reportCommon7 - taskReportRole8 - reportCommon8 - taskReportRole9 - reportCommon9 - taskReportRole10 - reportCommon10 - taskReportRole11 - reportCommon11 - taskReportRole12 - reportCommon12 - taskReportRole13 - reportCommon13 - taskReportRole14 - reportCommon14 - taskReportRole15 + body = new workflow.WorkflowBody { + render = (mode: workflow.WorkflowRenderMode) -> skillBody.apply(taskRole, mode) } } -local planRole = new SyncRole { - slug = "sce-plan-context-sync" - title = "SCE Plan Context Sync" - skillFragments = new Listing { - skillCommon0 - planSkillRole0 - skillCommon1 - planSkillRole1 - skillCommon2 - planSkillRole2 - skillCommon3 - planSkillRole3 - skillCommon4 - planSkillRole4 - skillCommon5 - planSkillRole5 - skillCommon6 - planSkillRole6 - skillCommon7 - planSkillRole7 - skillCommon8 - planSkillRole8 - skillCommon9 - planSkillRole9 - skillCommon10 - planSkillRole10 - skillCommon11 - planSkillRole11 - skillCommon12 - planSkillRole12 - skillCommon13 - planSkillRole13 - skillCommon14 - planSkillRole14 - skillCommon15 - planSkillRole15 - skillCommon16 - planSkillRole16 - skillCommon17 - planSkillRole17 - skillCommon18 - planSkillRole18 - skillCommon19 - planSkillRole19 - skillCommon20 - planSkillRole20 - skillCommon21 - planSkillRole21 - skillCommon22 - planSkillRole22 - skillCommon23 - planSkillRole23 - skillCommon24 - planSkillRole24 - skillCommon25 - planSkillRole25 - skillCommon26 - planSkillRole26 - skillCommon27 - planSkillRole27 - skillCommon28 - skillCommon29 - planSkillRole29 - skillCommon30 - planSkillRole30 - skillCommon31 - planSkillRole31 - skillCommon32 - planSkillRole32 - skillCommon33 - planSkillRole33 - skillCommon34 - planSkillRole34 - skillCommon35 - planSkillRole35 - skillCommon36 - planSkillRole36 - skillCommon37 - planSkillRole37 - skillCommon38 - planSkillRole38 - skillCommon39 - skillCommon40 - planSkillRole40 - skillCommon41 - planSkillRole41 - skillCommon42 - planSkillRole42 - skillCommon43 - planSkillRole43 - skillCommon44 +hidden taskOutputReport = reportText.apply(taskRole.report, "package") + +hidden planStructuredSkill = new workflow.StructuredWorkflowDocument { + path = planRole.slug + frontmatter = new workflow.WorkflowFrontmatter { + lines = (mode: workflow.WorkflowRenderMode) -> planFrontmatterLines.apply(mode) } - reportFragments = new Listing { - planReportRole0 - reportCommon0 - planReportRole1 - reportCommon1 - planReportRole2 - reportCommon2 - planReportRole3 - reportCommon3 - planReportRole4 - reportCommon4 - planReportRole5 - reportCommon5 - planReportRole6 - reportCommon6 - planReportRole7 - reportCommon7 - planReportRole8 - reportCommon8 - planReportRole9 - reportCommon9 - planReportRole10 - reportCommon10 - planReportRole11 - reportCommon11 - planReportRole12 - reportCommon12 - planReportRole13 - reportCommon13 - planReportRole14 - reportCommon14 - planReportRole15 + body = new workflow.WorkflowBody { + render = (mode: workflow.WorkflowRenderMode) -> skillBody.apply(planRole, mode) } } +hidden planOutputReport = reportText.apply(planOutputReportRole, "package") + local documentMapping = (documents: Listing) -> new Mapping { for (document in documents) { [document.path] = document @@ -1400,11 +1026,11 @@ local packageFor = (role: SyncRole) -> new workflow.SkillPackage { documents = documentMapping.apply(new Listing { new workflow.WorkflowDocument { path = "SKILL.md" - text = role.skillFragments.join("\n") + text = skillText.apply(role, "package") } new workflow.WorkflowDocument { path = "references/sync-report.md" - text = role.reportFragments.join("\n") + text = reportText.apply(role.report, "package") } }) } diff --git a/config/pkl/base/workflow-next-task.pkl b/config/pkl/base/workflow-next-task.pkl index e0876701..b35505ea 100644 --- a/config/pkl/base/workflow-next-task.pkl +++ b/config/pkl/base/workflow-next-task.pkl @@ -1,46 +1,55 @@ import "workflow-content.pkl" as model import "workflow-context-sync.pkl" as contextSync +local planReview = model.semanticReference.apply("`sce-plan-review`", "the **Plan review phase**") +local planReviewName = model.semanticReference.apply("sce-plan-review", "Plan review phase") +local taskExecution = model.semanticReference.apply("`sce-task-execution`", "the **Task execution phase**") +local taskExecutionName = model.semanticReference.apply("sce-task-execution", "Task execution phase") +local taskContextSync = model.semanticReference.apply("`sce-task-context-sync`", "the **Task context synchronization phase**") +local readinessContract = model.semanticReference.apply("`references/readiness-contract.yaml`", "the internal readiness state described by this workflow") +local executionContract = model.semanticReference.apply("`references/execution-contract.yaml`", "the internal execution state described by this workflow") +local implementationGate = model.semanticReference.apply("`references/implementation-gate.md`", "`references/output.md`") +local invoke = model.semanticReference.apply("Invoke", "Run") +local invokeLower = model.semanticReference.apply("invoke", "run") +local invokedSkills = model.semanticReference.apply("invoked skills", "embedded phases") +local invokedSkill = model.semanticReference.apply("invoked skill", "embedded phase") +local yamlResult = model.semanticReference.apply("YAML result", "internal state") +local returnLower = model.semanticReference.apply("return", "set internal status") +local returnUpper = model.semanticReference.apply("Return", "Set internal status") +local returningTerminalResult = model.semanticReference.apply("Returning one terminal YAML result", "Recording one terminal internal state") +local returnYaml = model.semanticReference.apply("Return YAML", "Return internal state") +local returnYamlLower = model.semanticReference.apply("return YAML", "return internal state") +local returnExactlyOneStructuredResult = model.semanticReference.apply("Return exactly one structured result", "Set exactly one internal state") +local returnOnlyStructuredResult = model.semanticReference.apply("Return only the structured result", "Record only the internal state") +local returnExactlyOneYamlDocument = model.semanticReference.apply("return exactly one YAML document", "set exactly one internal state") +local returnOnlyYamlDocument = model.semanticReference.apply("Return only the YAML document", "Record only the internal state") +local returningReadinessResult = model.semanticReference.apply("Returning one structured readiness result", "Recording one structured readiness result") +local invokeTaskExecution = model.semanticReference.apply("Invoke task execution", "Run task execution") + /// Canonical `/next-task` workflow command and its self-contained skill /// packages. Text mirrors the project-root `.pi/` behavioral baseline; target /// renderers consume this model in later workflow-rendering tasks. -local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { - path = documentPath - text = documentText -} - -local packageDocuments = (documents: Listing) -> new Mapping { - for (item in documents) { - [item.path] = item - } -} - local planReviewPackage = new model.SkillPackage { slug = "sce-plan-review" title = "SCE Plan Review" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", REVIEW_SKILL) - makeDocument.apply("references/readiness-contract.yaml", READINESS_CONTRACT) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", REVIEW_SKILL) + model.makeDocument.apply("references/readiness-contract.yaml", READINESS_CONTRACT) }) } local taskExecutionPackage = new model.SkillPackage { slug = "sce-task-execution" title = "SCE Task Execution" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", EXECUTION_SKILL) - makeDocument.apply("references/execution-contract.yaml", EXECUTION_CONTRACT) - makeDocument.apply("references/implementation-gate.md", IMPLEMENTATION_GATE) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", EXECUTION_SKILL) + model.makeDocument.apply("references/execution-contract.yaml", EXECUTION_CONTRACT) + model.makeDocument.apply("references/implementation-gate.md", IMPLEMENTATION_GATE) }) } -local COMMAND = """ - --- - description: "Run `sce-plan-review` -> `sce-task-execution` -> `sce-task-context-sync` for one SCE plan task" - argument-hint: " [T0X] [approved]" - --- - +local renderCommandBody = (mode: model.WorkflowRenderMode) -> """ SCE NEXT TASK `$ARGUMENTS` ## Input @@ -59,21 +68,21 @@ local COMMAND = """ Pass each part only to the phase that owns it. Do not forward the raw `$ARGUMENTS` string to a skill. - Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by `sce-plan-review` (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. + Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is the path resolved by \(planReview.render.apply(mode)) (`plan.path`, or an entry of `candidates`), so every emitted command is directly runnable. ## Workflow ### 1. Review the task - Invoke `sce-plan-review` with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. + \(invoke.render.apply(mode)) \(planReview.render.apply(mode)) with the parsed `plan-name-or-path` and, when present, the parsed `task-id`. - Do not pass the `auto-approve` token to `sce-plan-review`. + Do not pass the `auto-approve` token to \(planReview.render.apply(mode)). The skill must return a result matching its readiness contract. Branch on `status`: - `blocked` -> Do not invoke implementation. Present the result as prose. Do not print the raw result. Stop. + `blocked` -> Do not \(invokeLower.render.apply(mode)) implementation. Present the result as prose. Do not print the raw result. Stop. When `candidates` is present, the plan could not be resolved. Present: @@ -103,21 +112,21 @@ local COMMAND = """ Stop. - `ready` -> Pass the complete readiness result to `sce-task-execution`. + `ready` -> Pass the complete readiness result to \(taskExecution.render.apply(mode)). Do not reconstruct, summarize, or reinterpret the reviewed task before passing it. ### 2. Execute the task - Invoke `sce-task-execution` with the complete `ready` result from `sce-plan-review`. + \(invoke.render.apply(mode)) \(taskExecution.render.apply(mode)) with the complete `ready` result from \(planReview.render.apply(mode)). Branch on `auto-approve`: - `approved` -> Also pass the `approve` flag. `sce-task-execution` then shows its implementation gate as a summary and proceeds without asking. + `approved` -> Also pass the `approve` flag. \(taskExecution.render.apply(mode)) then shows its implementation gate as a summary and proceeds without asking. - else -> Do not pass the `approve` flag. `sce-task-execution` shows its implementation gate and waits for the user's decision. + else -> Do not pass the `approve` flag. \(taskExecution.render.apply(mode)) shows its implementation gate and waits for the user's decision. - `sce-task-execution` exclusively owns: + \(taskExecution.render.apply(mode)) exclusively owns: - Presenting the implementation summary. - Requesting implementation confirmation. @@ -129,7 +138,7 @@ local COMMAND = """ Branch on the execution result. - `declined` -> Present "You have declined to proceed with this task". Do not invoke context synchronization. Stop. + `declined` -> Present "You have declined to proceed with this task". Do not \(invokeLower.render.apply(mode)) context synchronization. Stop. `blocked` -> Present: @@ -137,7 +146,7 @@ local COMMAND = """ - Work completed before the blocker. - The decision or action required. - Do not invoke context synchronization. Stop. + Do not \(invokeLower.render.apply(mode)) context synchronization. Stop. `incomplete` -> Present: @@ -146,15 +155,15 @@ local COMMAND = """ - Remaining work. - The reason the task is incomplete. - Do not invoke context synchronization. Do not select another task. Stop. + Do not \(invokeLower.render.apply(mode)) context synchronization. Do not select another task. Stop. `complete` -> continue to the next step. ### 3. Synchronize context - Invoke `sce-task-context-sync` with the complete `complete` result returned by `sce-task-execution`. + \(invoke.render.apply(mode)) \(taskContextSync.render.apply(mode)) with the complete `complete` result returned by \(taskExecution.render.apply(mode)). - Pass that result verbatim. It is the authoritative handoff, and `sce-task-context-sync` owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. + Pass that result verbatim. It is the authoritative handoff, and \(taskContextSync.render.apply(mode)) owns reading the plan, task, changed files, verification evidence, and reported context impact out of it. Do not restate, summarize, or reconstruct any part of the execution result. @@ -172,7 +181,7 @@ local COMMAND = """ Do not select another task. Stop. - `synced` | `no_context_change` -> Print out the report `sce-task-context-sync` returned. Continue to the next step. + `synced` | `no_context_change` -> Print out the report \(taskContextSync.render.apply(mode)) returned. Continue to the next step. ### 4. Determine the continuation @@ -180,7 +189,7 @@ local COMMAND = """ Do not execute another task. Return exactly one continuation. - If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; `sce-plan-review` checks them when the emitted command runs and returns `blocked` if they are unmet. + If incomplete tasks remain, read the plan and name the first unchecked task in plan order. Do not evaluate its dependencies; \(planReview.render.apply(mode)) checks them when the emitted command runs and returns `blocked` if they are unmet. Return: @@ -220,26 +229,31 @@ local COMMAND = """ - Execute at most one plan task per invocation. - Review at most one task. - - Do not duplicate the internal instructions of invoked skills. - - Do not ask for implementation confirmation outside "sce-task-execution". + - Do not duplicate the internal instructions of \(invokedSkills.render.apply(mode)). + - Do not ask for implementation confirmation outside "\(taskExecutionName.render.apply(mode))". - Do not run full-plan validation. - Do not mark the plan complete. - Do not execute the continuation returned at the end. - - Do not infer success when an invoked skill returns a non-success status. + - Do not infer success when an \(invokedSkill.render.apply(mode)) returns a non-success status. - Preserve completed work and evidence when a later phase fails. """ -local REVIEW_SKILL = """ - --- - name: sce-plan-review - description: > - Internal SCE workflow skill that resolves one task from an existing plan and - determines whether it is ready for implementation. Returns ready, blocked, or - plan_complete with a structured payload. Use from /next-task. Do not implement - changes, request implementation approval, update the plan, synchronize - context, or run final validation. - --- - +local structuredCommand = new model.StructuredWorkflowDocument { + path = "next-task.md" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "description: \"Run \(planReview.render.apply(mode)) -> \(taskExecution.render.apply(mode)) -> \(taskContextSync.render.apply(mode)) for one SCE plan task\"" + "argument-hint: \" [T0X] [approved]\"" + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderCommandBody.apply(mode) + } +} + +local COMMAND = structuredCommand.render.apply("package", "").text + +local renderReviewSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Plan Review ## Purpose @@ -254,11 +268,11 @@ local REVIEW_SKILL = """ - Selecting at most one task. - Inspecting the context needed to judge readiness. - Determining readiness. - - Returning one structured readiness result. + - \(returningReadinessResult.render.apply(mode)). Return a result matching: - `references/readiness-contract.yaml` + \(readinessContract.render.apply(mode)) ## Input @@ -273,9 +287,9 @@ local REVIEW_SKILL = """ Resolve the supplied plan name or path to exactly one existing plan. - When no plan can be found, return `blocked`. + When no plan can be found, \(returnLower.render.apply(mode)) `blocked`. - When multiple plans match and none can be selected safely, return `blocked` with + When multiple plans match and none can be selected safely, \(returnLower.render.apply(mode)) `blocked` with the matching candidates. Read the selected plan before exploring the repository. @@ -287,9 +301,9 @@ local REVIEW_SKILL = """ Otherwise, select the first incomplete task in plan order whose declared dependencies are complete. - Return `plan_complete` when no incomplete tasks remain. + \(returnUpper.render.apply(mode)) `plan_complete` when no incomplete tasks remain. - Return `blocked` when incomplete tasks remain but none can currently be + \(returnUpper.render.apply(mode)) `blocked` when incomplete tasks remain but none can currently be executed. Review at most one task per invocation. @@ -334,7 +348,7 @@ local REVIEW_SKILL = """ Record these choices under `assumptions`. - Return `blocked` when a missing decision materially affects: + \(returnUpper.render.apply(mode)) `blocked` when a missing decision materially affects: - User-visible behavior. - Public interfaces. @@ -347,13 +361,13 @@ local REVIEW_SKILL = """ ### 5. Return the result - Return exactly one structured result: + \(returnExactlyOneStructuredResult.render.apply(mode)): - `ready` - `blocked` - `plan_complete` - Return only the structured result. Do not add explanatory prose before or after + \(returnOnlyStructuredResult.render.apply(mode)). Do not add explanatory prose before or after it. ## Boundaries @@ -365,7 +379,7 @@ local REVIEW_SKILL = """ - Update the plan. - Mark the task complete. - Request implementation confirmation. - - Invoke task execution. + - \(invokeTaskExecution.render.apply(mode)). - Synchronize context. - Run final validation. - Review more than one task. @@ -376,10 +390,30 @@ local REVIEW_SKILL = """ - One plan was resolved. - At most one task was resolved. - - One valid readiness result matching `references/readiness-contract.yaml` was + - One valid readiness result matching \(readinessContract.render.apply(mode)) was returned. """ +local structuredReviewSkill = new model.StructuredWorkflowDocument { + path = "sce-plan-review" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(planReviewName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that resolves one task from an existing plan and" + " determines whether it is ready for implementation. Returns ready, blocked, or" + " plan_complete with a structured payload. Use from /next-task. Do not implement" + " changes, request implementation approval, update the plan, synchronize" + " context, or run final validation." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderReviewSkillBody.apply(mode) + } +} + +local REVIEW_SKILL = structuredReviewSkill.render.apply("package", "").text + local READINESS_CONTRACT = """ version: 1 name: sce-plan-review-result @@ -629,19 +663,7 @@ local READINESS_CONTRACT = """ total_tasks: 5 """ -local EXECUTION_SKILL = """ - --- - name: sce-task-execution - description: > - Internal SCE workflow skill that always presents one reviewed task to the - user before editing, executes it only after approval, verifies the - task, records evidence in the plan, and returns one YAML result: declined, - blocked, incomplete, or complete. Accepts a ready result from - sce-plan-review. Do not select or execute another task, - synchronize durable context, run final plan validation, create commits, or - expand task scope. - --- - +local renderExecutionSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Task Execution ## Purpose @@ -656,21 +678,21 @@ local EXECUTION_SKILL = """ - Implementing one approved task. - Running task-level verification. - Updating that task and its evidence in the plan. - - Returning one terminal YAML result. + - \(returningTerminalResult.render.apply(mode)). Use the gate defined in: - `references/implementation-gate.md` + \(implementationGate.render.apply(mode)) Return a final result matching: - `references/execution-contract.yaml` + \(executionContract.render.apply(mode)) ## Input The invoking workflow provides: - - The complete `ready` result from `sce-plan-review`. + - The complete `ready` result from \(planReview.render.apply(mode)). - An optional `approve` flag. The `approve` flag means the user pre-approved this task when invoking the @@ -690,7 +712,7 @@ local EXECUTION_SKILL = """ If required handoff information is absent or stale, still show the gate using what is known, clearly identify the handoff problem, and do not edit files. - After the user responds, return `blocked`. + After the user responds, \(returnLower.render.apply(mode)) `blocked`. ## Workflow @@ -710,7 +732,7 @@ local EXECUTION_SKILL = """ ### 2. Always show the implementation gate At the start of the skill, before any file modification, present the task using - `references/implementation-gate.md`. + \(implementationGate.render.apply(mode)). The gate must be shown even when: @@ -724,7 +746,7 @@ local EXECUTION_SKILL = """ `Continue with implementation now? (yes/no)` - Stop and wait for the user's answer. Do not return YAML, and make no file + Stop and wait for the user's answer. Do not \(returnYamlLower.render.apply(mode)), and make no file modifications, until the user has answered. When the `approve` flag is supplied, show the gate as a summary, omit the @@ -734,16 +756,16 @@ local EXECUTION_SKILL = """ Skip this step when the `approve` flag was supplied. - When the user rejects or cancels, do not modify files and return `declined`. + When the user rejects or cancels, do not modify files and \(returnLower.render.apply(mode)) `declined`. When the user does not clearly approve, do not modify files. Ask the same approval question once more only when the response is genuinely ambiguous. - Otherwise return `blocked`. + Otherwise \(returnLower.render.apply(mode)) `blocked`. When the user approves, continue with implementation. Treat constraints supplied with approval as part of the approved task boundary. - If those constraints materially contradict the reviewed task, return `blocked` + If those constraints materially contradict the reviewed task, \(returnLower.render.apply(mode)) `blocked` before editing. ### 4. Prepare the implementation @@ -802,7 +824,7 @@ local EXECUTION_SKILL = """ - Determine whether the task caused the failure. - Fix it when the correction remains in scope. - Rerun the relevant check. - - Return `incomplete` when a done check remains unsatisfied, or `blocked` when + - \(returnUpper.render.apply(mode)) `incomplete` when a done check remains unsatisfied, or `blocked` when completing it requires an unapproved decision or scope expansion. Never report a check as passed unless it ran successfully. @@ -822,32 +844,32 @@ local EXECUTION_SKILL = """ ### 8. Determine the terminal status - Return `complete` when the task was implemented, verified, and marked complete + \(returnUpper.render.apply(mode)) `complete` when the task was implemented, verified, and marked complete in the plan with evidence. - Return `incomplete` when in-scope work was completed but one or more done checks + \(returnUpper.render.apply(mode)) `incomplete` when in-scope work was completed but one or more done checks remain unsatisfied. - Return `declined` when the user rejected implementation. + \(returnUpper.render.apply(mode)) `declined` when the user rejected implementation. - Return `blocked` for every other non-successful outcome, including: + \(returnUpper.render.apply(mode)) `blocked` for every other non-successful outcome, including: - Missing approval. - Stale or invalid handoff. - Material blocker. - A verification failure that cannot be resolved in scope. - Use a blocker category defined by `references/execution-contract.yaml`. + Use a blocker category defined by \(executionContract.render.apply(mode)). Do not determine whether the plan is complete. The invoking `/next-task` workflow owns that decision after context synchronization. - ### 9. Return YAML + ### 9. \(returnYaml.render.apply(mode)) - After the skill reaches a terminal state, return exactly one YAML document - matching `references/execution-contract.yaml`. + After the skill reaches a terminal state, \(returnExactlyOneYamlDocument.render.apply(mode)) + matching \(executionContract.render.apply(mode)). - Return only the YAML document. Do not add explanatory prose before or after it. + \(returnOnlyYamlDocument.render.apply(mode)). Do not add explanatory prose before or after it. ## Boundaries @@ -874,10 +896,32 @@ local EXECUTION_SKILL = """ - The implementation gate was shown. - The user approved or rejected the task, or approval was pre-supplied. - At most one task was executed. - - One valid terminal YAML result matching `references/execution-contract.yaml` + - One valid terminal \(yamlResult.render.apply(mode)) matching \(executionContract.render.apply(mode)) was returned. """ +local structuredExecutionSkill = new model.StructuredWorkflowDocument { + path = "sce-task-execution" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(taskExecutionName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that always presents one reviewed task to the" + " user before editing, executes it only after approval, verifies the" + " task, records evidence in the plan, and returns one \(yamlResult.render.apply(mode)): declined," + " blocked, incomplete, or complete. Accepts a ready result from" + " \(planReviewName.render.apply(mode)). Do not select or execute another task," + " synchronize durable context, run final plan validation, create commits, or" + " expand task scope." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderExecutionSkillBody.apply(mode) + } +} + +local EXECUTION_SKILL = structuredExecutionSkill.render.apply("package", "").text + local EXECUTION_CONTRACT = """ version: 1 name: sce-task-execution-result @@ -1187,10 +1231,10 @@ local EXECUTION_CONTRACT = """ reason: The task introduced durable login behavior that should be reflected in authentication context. """ -local IMPLEMENTATION_GATE = """ +local renderImplementationGate = (mode: model.WorkflowRenderMode) -> """ # Implementation gate - Always show this gate at the start of `sce-task-execution`, before editing any + Always show this gate at the start of \(taskExecution.render.apply(mode)), before editing any file. The gate is user-facing prose. It is never serialized into a YAML result. This @@ -1259,12 +1303,28 @@ local IMPLEMENTATION_GATE = """ identify the problem under **Risks or trade-offs**. """ +local IMPLEMENTATION_GATE = renderImplementationGate.apply("package") + +structuredComposite = new model.StructuredCompositeSource { + command = structuredCommand + phases = new Listing { + structuredReviewSkill + structuredExecutionSkill + contextSync.taskStructuredSkill + } + internalDocuments = new Listing {} + outputDocuments = new Listing { + model.makeDocument.apply("Implementation gate", renderImplementationGate.apply("composite")) + model.makeDocument.apply("Context sync report", contextSync.taskOutputReport) + } +} + workflow = new model.WorkflowPackage { slug = "next-task" command = new model.WorkflowCommand { slug = "next-task" title = "SCE Next Task" - document = makeDocument.apply("next-task.md", COMMAND) + document = model.makeDocument.apply("next-task.md", COMMAND) } skills = new Mapping { [planReviewPackage.slug] = planReviewPackage diff --git a/config/pkl/base/workflow-validate.pkl b/config/pkl/base/workflow-validate.pkl index 9bf49011..190e97fe 100644 --- a/config/pkl/base/workflow-validate.pkl +++ b/config/pkl/base/workflow-validate.pkl @@ -1,37 +1,41 @@ import "workflow-content.pkl" as model import "workflow-context-sync.pkl" as contextSync +local validation = model.semanticReference.apply("`sce-validation`", "the **Validation phase**") +local validationName = model.semanticReference.apply("sce-validation", "Validation phase") +local planContextSync = model.semanticReference.apply("`sce-plan-context-sync`", "the **Plan context synchronization phase**") +local validationResult = model.semanticReference.apply("`references/validation-result.md`", "`references/output.md`") +local validationReport = model.semanticReference.apply("`references/validation-report.md`", "the **Plan-file validation report** section embedded in this file") +local invoke = model.semanticReference.apply("Invoke", "Run") +local invokeLower = model.semanticReference.apply("invoke", "run") +local invokedSkills = model.semanticReference.apply("invoked skills", "embedded phases") +local invokedSkill = model.semanticReference.apply("invoked skill", "embedded phase") +local invokedFor = model.semanticReference.apply("invoked for", "run for") +local markdownResult = model.semanticReference.apply("Markdown result", "internal state") +local returningValidationResult = model.semanticReference.apply("Returning one Markdown validation result", "Recording one Markdown validation result") +local returnExactlyOneMarkdownResult = model.semanticReference.apply("Return exactly one Markdown result", "Set exactly one internal state") +local returnOnlyMarkdownReport = model.semanticReference.apply("Return only the Markdown report", "Record only the Markdown report") +local returnLower = model.semanticReference.apply("return", "set internal status") +local returnUpper = model.semanticReference.apply("Return", "Set internal status") +local returnYamlResult = model.semanticReference.apply("Return a YAML result", "Return a internal state") +local yaml = model.semanticReference.apply("YAML", "internal state") +local invokePlanContextSync = model.semanticReference.apply("Invoke plan context sync", "Run plan context synchronization") + /// Canonical `/validate` workflow command and its self-contained skill /// packages. Text mirrors the project-root `.pi/` behavioral baseline; target /// renderers consume this model in later workflow-rendering tasks. -local makeDocument = (documentPath: String, documentText: String) -> new model.WorkflowDocument { - path = documentPath - text = documentText -} - -local packageDocuments = (documents: Listing) -> new Mapping { - for (item in documents) { - [item.path] = item - } -} - local validationPackage = new model.SkillPackage { slug = "sce-validation" title = "SCE Validation" - documents = packageDocuments.apply(new Listing { - makeDocument.apply("SKILL.md", VALIDATION_SKILL) - makeDocument.apply("references/validation-report.md", VALIDATION_REPORT) - makeDocument.apply("references/validation-result.md", VALIDATION_RESULT) + documents = model.packageDocuments.apply(new Listing { + model.makeDocument.apply("SKILL.md", VALIDATION_SKILL) + model.makeDocument.apply("references/validation-report.md", VALIDATION_REPORT) + model.makeDocument.apply("references/validation-result.md", VALIDATION_RESULT) }) } -local COMMAND = """ - --- - description: "Run `sce-validation` -> `sce-plan-context-sync` to finish an SCE plan" - argument-hint: "" - --- - +local renderCommandBody = (mode: model.WorkflowRenderMode) -> """ SCE VALIDATE `$ARGUMENTS` ## Input @@ -46,20 +50,20 @@ local COMMAND = """ the expected argument, and stop. Do not infer the plan from repository state or the conversation. - Pass the plan name or path to `sce-validation` unmodified. Do not restate, + Pass the plan name or path to \(validation.render.apply(mode)) unmodified. Do not restate, summarize, or pre-scope it. Every `{plan-path}` and `{candidate-path}` emitted anywhere in this workflow is - the path carried by `sce-validation` in its Markdown result (`Plan:`, or a + the path carried by \(validation.render.apply(mode)) in its Markdown result (`Plan:`, or a candidate path), so every emitted command is directly runnable. ## Workflow ### 1. Validate the plan - Invoke `sce-validation` with the plan name or path. + \(invoke.render.apply(mode)) \(validation.render.apply(mode)) with the plan name or path. - `sce-validation` exclusively owns: + \(validation.render.apply(mode)) exclusively owns: - Resolving one plan. - Confirming every implementation task is complete. @@ -73,10 +77,10 @@ local COMMAND = """ The skill must return a Markdown result matching its validation-result contract. Branch on the report's `Status:`. - `blocked` -> Do not invoke context synchronization. Print the blocked Markdown + `blocked` -> Do not \(invokeLower.render.apply(mode)) context synchronization. Print the blocked Markdown report as returned. Do not rephrase it into a different layout. Stop. - `failed` -> Do not invoke context synchronization. Print the failed Markdown + `failed` -> Do not \(invokeLower.render.apply(mode)) context synchronization. Print the failed Markdown report as returned. It is already a session handoff: self-contained, actionable, and ending with `/validate {plan-path}` after repairs. @@ -88,21 +92,21 @@ local COMMAND = """ to continue here; the default is that the handoff can leave this session. `validated` -> Pass the complete validated Markdown result to - `sce-plan-context-sync`. + \(planContextSync.render.apply(mode)). Do not reconstruct, summarize, or reinterpret the validation result before passing it. ### 2. Synchronize plan context - Invoke `sce-plan-context-sync` only with a `Status: validated` Markdown result - from `sce-validation`. + \(invoke.render.apply(mode)) \(planContextSync.render.apply(mode)) only with a `Status: validated` Markdown result + from \(validation.render.apply(mode)). - Do not invoke `sce-plan-context-sync` for `failed` or `blocked`. Those are not + Do not \(invokeLower.render.apply(mode)) \(planContextSync.render.apply(mode)) for `failed` or `blocked`. Those are not success states. Pass the validated result verbatim. It is the authoritative handoff, and - `sce-plan-context-sync` owns reading the plan path, required context paths, + \(planContextSync.render.apply(mode)) owns reading the plan path, required context paths, validation evidence, and reported context impact out of it. Do not restate, summarize, or reconstruct any part of the validation result. @@ -127,7 +131,7 @@ local COMMAND = """ Stop. `synced` | `no_context_change` -> Print out the report - `sce-plan-context-sync` returned. Continue to the next step. + \(planContextSync.render.apply(mode)) returned. Continue to the next step. ### 3. Report completion @@ -155,11 +159,11 @@ local COMMAND = """ ## Rules - Validate at most one plan per invocation. - - Do not duplicate the internal instructions of invoked skills. - - Do not run final validation when implementation tasks remain; `sce-validation` + - Do not duplicate the internal instructions of \(invokedSkills.render.apply(mode)). + - Do not run final validation when implementation tasks remain; \(validation.render.apply(mode)) returns `blocked`, and this workflow stops. - - Invoke `sce-plan-context-sync` only when `sce-validation` returned - `Status: validated`. Do not invoke it for `failed` or `blocked`. + - \(invoke.render.apply(mode)) \(planContextSync.render.apply(mode)) only when \(validation.render.apply(mode)) returned + `Status: validated`. Do not \(invokeLower.render.apply(mode)) it for `failed` or `blocked`. - On `failed`, print the handoff Markdown as returned and stop. Preserve the retry `/validate {plan-path}` instruction. Do not synchronize context. - Do not implement remaining plan tasks from this workflow unless the user @@ -168,25 +172,27 @@ local COMMAND = """ - Do not mark the plan archived or delete the plan. - Do not execute a follow-up `/next-task`, `/change-to-plan`, or `/validate` yourself. - - Do not infer success when an invoked skill returns a non-success status. + - Do not infer success when an \(invokedSkill.render.apply(mode)) returns a non-success status. - Preserve validation evidence already written to the plan when context synchronization fails. """ -local VALIDATION_SKILL = """ - --- - name: sce-validation - description: > - Internal SCE workflow skill that runs final plan validation after all - implementation tasks are complete: full validation commands, acceptance - criteria checks, temporary scaffolding cleanup, a Validation Report written - into the plan, and one Markdown result (validated, failed, or blocked). - Failing checks are reported only; do not modify tests or product code to make - validation pass. A failed result is a session handoff that ends by retrying - /validate. Use from /validate. Do not synchronize durable context, implement - remaining plan tasks, create commits, or select another task. - --- - +local structuredCommand = new model.StructuredWorkflowDocument { + path = "validate.md" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "description: \"Run \(validation.render.apply(mode)) -> \(planContextSync.render.apply(mode)) to finish an SCE plan\"" + "argument-hint: \"\"" + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderCommandBody.apply(mode) + } +} + +local COMMAND = structuredCommand.render.apply("package", "").text + +local renderValidationSkillBody = (mode: model.WorkflowRenderMode) -> """ # SCE Validation ## Purpose @@ -204,18 +210,18 @@ local VALIDATION_SKILL = """ - Removing temporary scaffolding introduced by the change. - Writing the Validation Report into the plan. - Marking acceptance criteria against the evidence. - - Returning one Markdown validation result. + - \(returningValidationResult.render.apply(mode)). Return a result matching: - `references/validation-result.md` + \(validationResult.render.apply(mode)) Write plan-file evidence matching: - `references/validation-report.md` + \(validationReport.render.apply(mode)) Context synchronization is not this skill's job. The invoking `/validate` - workflow runs `sce-plan-context-sync` only after a `validated` result. + workflow runs \(planContextSync.render.apply(mode)) only after a `validated` result. ## Input @@ -230,16 +236,16 @@ local VALIDATION_SKILL = """ Resolve the supplied plan name or path to exactly one existing plan under `context/plans/`. - When no plan can be found, return `blocked`. + When no plan can be found, \(returnLower.render.apply(mode)) `blocked`. - When multiple plans match and none can be selected safely, return `blocked` + When multiple plans match and none can be selected safely, \(returnLower.render.apply(mode)) `blocked` with the matching candidates. Read the selected plan before exploring the repository. ### 2. Confirm implementation is finished - Return `blocked` with incomplete tasks listed when any implementation task + \(returnUpper.render.apply(mode)) `blocked` with incomplete tasks listed when any implementation task remains incomplete. Final validation measures finished work. Do not run the full suite against a @@ -253,7 +259,7 @@ local VALIDATION_SKILL = """ - The `Full validation` command list. - The `Context sync` requirements, for the context-impact handoff only. - Return `blocked` when the plan has no usable acceptance criteria, or when no + \(returnUpper.render.apply(mode)) `blocked` when the plan has no usable acceptance criteria, or when no validation commands can be determined from the plan or repository conventions. Prefer the plan's authored checks. Fall back to repository-primary test, lint, @@ -298,7 +304,7 @@ local VALIDATION_SKILL = """ - Mark each acceptance criterion checkbox to match the evidence. - Append or replace the plan's `## Validation Report` section using - `references/validation-report.md`. + \(validationReport.render.apply(mode)). - When status is `failed`, the plan-file report must include the retry command `/validate {plan path}`. @@ -309,7 +315,7 @@ local VALIDATION_SKILL = """ ### 7. Determine context impact for the handoff On `validated` only, classify the durable context impact of the finished plan - so `sce-plan-context-sync` can start from the plan's own requirements: + so \(planContextSync.render.apply(mode)) can start from the plan's own requirements: - Start from the plan's `Context sync` section. - Inspect what the completed implementation actually changed when needed. @@ -321,20 +327,20 @@ local VALIDATION_SKILL = """ On `failed` or `blocked`, omit context impact; context sync will not run. - ### 8. Return the Markdown result + ### 8. Return the \(markdownResult.render.apply(mode)) - Return exactly one Markdown result: + \(returnExactlyOneMarkdownResult.render.apply(mode)): - `validated` when every acceptance criterion is met, required full validation passed, and the Validation Report was written. - `failed` when evidence was captured but required checks or criteria remain unsatisfied. Shape it as a session handoff per - `references/validation-result.md`, ending recommended work with + \(validationResult.render.apply(mode)), ending recommended work with `/validate {plan path}`. - `blocked` when validation cannot proceed safely. - Return only the Markdown report. Do not add explanatory prose before or after - it. Do not return YAML. + \(returnOnlyMarkdownReport.render.apply(mode)). Do not add explanatory prose before or after + it. Do not return \(yaml.render.apply(mode)). ## Boundaries @@ -351,8 +357,8 @@ local VALIDATION_SKILL = """ - Create a Git commit or push changes. - Invent acceptance criteria the plan does not state. - Claim verification that was not performed. - - Return a YAML result. - - Invoke plan context sync. The workflow owns that step. + - \(returnYamlResult.render.apply(mode)). + - \(invokePlanContextSync.render.apply(mode)). The workflow owns that step. ## Completion @@ -361,14 +367,37 @@ local VALIDATION_SKILL = """ - One plan was resolved, or resolution failed and was reported. - Implementation completeness was checked. - Validation ran to a terminal state, or a blocker prevented it. - - One valid Markdown result matching `references/validation-result.md` was + - One valid \(markdownResult.render.apply(mode)) matching \(validationResult.render.apply(mode)) was returned. """ -local VALIDATION_REPORT = """ +local structuredValidationSkill = new model.StructuredWorkflowDocument { + path = "sce-validation" + frontmatter = new model.WorkflowFrontmatter { + lines = (mode: model.WorkflowRenderMode) -> new Listing { + "name: \(validationName.render.apply(mode))" + "description: >" + " Internal SCE workflow skill that runs final plan validation after all" + " implementation tasks are complete: full validation commands, acceptance" + " criteria checks, temporary scaffolding cleanup, a Validation Report written" + " into the plan, and one \(markdownResult.render.apply(mode)) (validated, failed, or blocked)." + " Failing checks are reported only; do not modify tests or product code to make" + " validation pass. A failed result is a session handoff that ends by retrying" + " /validate. Use from /validate. Do not synchronize durable context, implement" + " remaining plan tasks, create commits, or select another task." + } + } + body = new model.WorkflowBody { + render = (mode: model.WorkflowRenderMode) -> renderValidationSkillBody.apply(mode) + } +} + +local VALIDATION_SKILL = structuredValidationSkill.render.apply("package", "").text + +local renderValidationReport = (mode: model.WorkflowRenderMode) -> """ # Plan-file Validation Report - The Markdown section `sce-validation` appends to the plan file when returning + The Markdown section \(validation.render.apply(mode)) appends to the plan file when returning `validated` or `failed`. Write it at the end of `context/plans/{plan_name}.md` under exactly one `## Validation Report` heading. @@ -376,7 +405,7 @@ local VALIDATION_REPORT = """ separately in `validation-result.md`. Do not author this section while planning. Only `/validate` through - `sce-validation` writes it. + \(validation.render.apply(mode)) writes it. ## Layout @@ -452,7 +481,9 @@ local VALIDATION_REPORT = """ one rather than stacking duplicates. """ -local VALIDATION_RESULT = """ +local VALIDATION_REPORT = renderValidationReport.apply("package") + +local renderValidationResult = (mode: model.WorkflowRenderMode) -> """ # Validation Result Return only one completed Markdown report using the applicable variant below. @@ -633,20 +664,37 @@ local VALIDATION_RESULT = """ - The failed variant must be self-contained enough to hand to another session without the original chat. - Include **Context impact** only on `validated`. Omit it on `failed` and - `blocked`; plan context sync is not invoked for non-success states. + `blocked`; plan context sync is not \(invokedFor.render.apply(mode)) non-success states. - Do not include context synchronization results in this report. The invoking - workflow runs `sce-plan-context-sync` only after `validated`. + workflow runs \(planContextSync.render.apply(mode)) only after `validated`. - Do not select or describe an unrelated next implementation task when status is `validated`. - Omit empty optional sections rather than writing placeholders. """ +local VALIDATION_RESULT = renderValidationResult.apply("package") + +structuredComposite = new model.StructuredCompositeSource { + command = structuredCommand + phases = new Listing { + structuredValidationSkill + contextSync.planStructuredSkill + } + internalDocuments = new Listing { + model.makeDocument.apply("Plan-file validation report", renderValidationReport.apply("composite")) + } + outputDocuments = new Listing { + model.makeDocument.apply("Validation result", renderValidationResult.apply("composite")) + model.makeDocument.apply("Plan context sync report", contextSync.planOutputReport) + } +} + workflow = new model.WorkflowPackage { slug = "validate" command = new model.WorkflowCommand { slug = "validate" title = "SCE Validate" - document = makeDocument.apply("validate.md", COMMAND) + document = model.makeDocument.apply("validate.md", COMMAND) } skills = new Mapping { [validationPackage.slug] = validationPackage diff --git a/config/pkl/check-generated.sh b/config/pkl/check-generated.sh index 894108aa..67c27287 100755 --- a/config/pkl/check-generated.sh +++ b/config/pkl/check-generated.sh @@ -52,9 +52,14 @@ cleanup() { } trap cleanup EXIT -first_root="$tmp_dir/first" -second_root="$tmp_dir/second" -mkdir -p "$first_root" "$second_root" +producer="$repo_root/scripts/produce-cli-generated-input.sh" +if [[ ! -x "$producer" ]]; then + printf 'CLI generated-input producer is missing or not executable: %s\n' \ + "$producer" >&2 + exit 1 +fi + +generated_input_root="$tmp_dir/generated-input" pkl eval config/pkl/renderers/metadata-coverage-check.pkl >/dev/null pkl eval config/pkl/renderers/generation-contract-check.pkl >/dev/null @@ -86,8 +91,8 @@ expect_pkl_fixture_failure \ "config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl" \ "generated workflow document contains a forbidden sibling-package reference or unresolved internalization token" -pkl eval -m "$first_root" config/pkl/generate.pkl >/dev/null -pkl eval -m "$second_root" config/pkl/generate.pkl >/dev/null +"$producer" "$repo_root" "$generated_input_root" +generated_root="$generated_input_root/pkl-generated" required_paths=( "config/.opencode/agent" @@ -108,7 +113,7 @@ required_paths=( ) for path in "${required_paths[@]}"; do - if [[ ! -e "$first_root/$path" ]]; then + if [[ ! -e "$generated_root/$path" ]]; then printf 'Generator did not emit required output at %s\n' "$path" >&2 exit 1 fi @@ -120,37 +125,18 @@ forbidden_outputs=( ) for path in "${forbidden_outputs[@]}"; do - if [[ -e "$first_root/$path" ]]; then + if [[ -e "$generated_root/$path" ]]; then printf 'Generator emitted removed output at %s\n' "$path" >&2 exit 1 fi done -write_inventory() { - local generated_root="$1" - local inventory_path="$2" - - ( - cd "$generated_root" - find config -type f -print \ - | LC_ALL=C sort \ - | while IFS= read -r path; do - sha256sum "$path" - done - ) > "$inventory_path" -} - -first_inventory="$tmp_dir/first.SHA256SUMS" -second_inventory="$tmp_dir/second.SHA256SUMS" -write_inventory "$first_root" "$first_inventory" -write_inventory "$second_root" "$second_inventory" - -if ! diff -u "$first_inventory" "$second_inventory"; then - printf 'Pkl generation is not deterministic.\n' >&2 - exit 1 -fi - -inventory_digest="$(sha256sum "$first_inventory" | cut -d ' ' -f 1)" -inventory_count="$(wc -l < "$first_inventory" | tr -d ' ')" +inventory_path="$generated_input_root/SHA256SUMS" +check_inventory="$tmp_dir/SHA256SUMS" +while read -r checksum path; do + printf '%s %s\n' "$checksum" "${path#pkl-generated/}" +done < "$inventory_path" > "$check_inventory" +inventory_digest="$(sha256sum "$check_inventory" | cut -d ' ' -f 1)" +inventory_count="$(wc -l < "$check_inventory" | tr -d ' ')" printf 'Ephemeral Pkl generation passed: %s files, inventory sha256 %s.\n' \ "$inventory_count" "$inventory_digest" diff --git a/config/pkl/generator-inputs.txt b/config/pkl/generator-inputs.txt new file mode 100644 index 00000000..3b23492e --- /dev/null +++ b/config/pkl/generator-inputs.txt @@ -0,0 +1,5 @@ +# Repository-relative files and directories that determine generate.pkl output. +config/pkl +config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts +config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts +config/lib/pi-plugin/sce-pi-extension.ts diff --git a/config/pkl/renderers/workflow-composite.pkl b/config/pkl/renderers/workflow-composite.pkl index 7fe53666..0c162125 100644 --- a/config/pkl/renderers/workflow-composite.pkl +++ b/config/pkl/renderers/workflow-composite.pkl @@ -17,14 +17,10 @@ class CompositeWorkflow { description: String = identity.description argumentHint: String = identity.argumentHint command: model.WorkflowDocument - phaseDocuments: Listing - internalDocuments: Listing outputText: String + structuredSource: model.StructuredCompositeSource } -local stripFrontmatterMarkers = (text: String) -> - text.replaceFirst("---", "").replaceFirst("---", "") - local phaseNameBySlug = new Mapping { ["sce-context-load"] = "Context load phase" ["sce-plan-authoring"] = "Plan authoring phase" @@ -36,74 +32,28 @@ local phaseNameBySlug = new Mapping { ["sce-atomic-commit"] = "Atomic commit phase" } -/// Remove sibling-package routing language while preserving canonical phase -/// semantics. Status values become internal workflow state inside the composite -/// skill; only layouts in references/output.md are rendered to the user. -local internalize = (text: String) -> - text - .replaceAll("`sce-context-load`", "the **Context load phase**") - .replaceAll("`sce-plan-authoring`", "the **Plan authoring phase**") - .replaceAll("`sce-plan-review`", "the **Plan review phase**") - .replaceAll("`sce-task-execution`", "the **Task execution phase**") - .replaceAll("`sce-task-context-sync`", "the **Task context synchronization phase**") - .replaceAll("`sce-validation`", "the **Validation phase**") - .replaceAll("`sce-plan-context-sync`", "the **Plan context synchronization phase**") - .replaceAll("`sce-atomic-commit`", "the **Atomic commit phase**") - .replaceAll("sce-context-load", "Context load phase") - .replaceAll("sce-plan-authoring", "Plan authoring phase") - .replaceAll("sce-plan-review", "Plan review phase") - .replaceAll("sce-task-execution", "Task execution phase") - .replaceAll("sce-task-context-sync", "Task context synchronization phase") - .replaceAll("sce-validation", "Validation phase") - .replaceAll("sce-plan-context-sync", "Plan context synchronization phase") - .replaceAll("sce-atomic-commit", "Atomic commit phase") - .replaceAll("`references/context-brief.yaml`", "the internal context-load state described by this workflow") - .replaceAll("`references/authoring-contract.yaml`", "the internal authoring state described by this workflow") - .replaceAll("`references/readiness-contract.yaml`", "the internal readiness state described by this workflow") - .replaceAll("`references/execution-contract.yaml`", "the internal execution state described by this workflow") - .replaceAll("`references/commit-contract.yaml`", "the internal commit state described by this workflow") - .replaceAll("`references/implementation-gate.md`", "`references/output.md`") - .replaceAll("`references/plan-summary.md`", "`references/output.md`") - .replaceAll("`references/validation-result.md`", "`references/output.md`") - .replaceAll("`references/sync-report.md`", "`references/output.md`") - .replaceAll("`references/commit-message-style.md`", "`references/output.md`") - .replaceAll("Invoke the **", "Run the **") - .replaceAll("invoke the **", "run the **") - .replaceAll("invoked skills", "embedded phases") - .replaceAll("invoked skill", "embedded phase") - .replaceAll("Invoke task execution", "Run task execution") - .replaceAll("Invoke plan context sync", "Run plan context synchronization") - .replaceAll("invoke implementation", "run implementation") - .replaceAll("invoke context synchronization", "run context synchronization") - .replaceAll("invoke it", "run it") - .replaceAll("Invoke only", "Run only") - .replaceAll("invoked for", "run for") - -local internalizePhase = (text: String) -> - internalize.apply(text) - .replaceAll("`references/plan-template.md`", "the **Plan template** section embedded in this file") - .replaceAll("`references/validation-report.md`", "the **Plan-file validation report** section embedded in this file") - .replaceAll("YAML result", "internal state") - .replaceAll("YAML document", "internal state") - .replaceAll("```yaml", "```text") - .replaceAll("YAML", "internal state") - .replaceAll("structured result", "internal state") - .replaceAll("terminal Markdown result", "terminal internal state") - .replaceAll("Markdown result", "internal state") - .replaceAll("Return exactly one", "Set exactly one") - .replaceAll("return exactly one", "set exactly one") - .replaceAll("Return only the", "Record only the") - .replaceAll("return only the", "record only the") - .replaceAll("Return `", "Set internal status `") - .replaceAll("return `", "set internal status `") - .replaceAll("Returning one", "Recording one") - .replaceAll("returning one", "recording one") - -local renderPhase = (slug: String, document: model.WorkflowDocument) -> - "## Internal phase: \(phaseNameBySlug[slug])\n\n" + internalizePhase.apply(stripFrontmatterMarkers.apply(document.text)) - -local renderInternalDocument = (title: String, document: model.WorkflowDocument) -> - "## Internal persisted-document format: \(title)\n\n" + internalize.apply(document.text) +local renderStructuredPhase = (document: model.StructuredWorkflowDocument) -> + "## Internal phase: \(phaseNameBySlug[document.path])\n\n" + document.render.apply("composite", "").text + +local renderStructuredInternalDocument = (document: model.WorkflowDocument) -> + "## Internal persisted-document format: \(document.path)\n\n" + document.text + +local renderCanonicalWorkflow = (workflow: CompositeWorkflow) -> + workflow.structuredSource.command.render.apply("composite", "").text + +local renderPhases = (workflow: CompositeWorkflow) -> + new Listing { + for (document in workflow.structuredSource.phases) { + renderStructuredPhase.apply(document) + } + }.join("\n\n") + +local renderInternalDocuments = (workflow: CompositeWorkflow) -> + new Listing { + for (document in workflow.structuredSource.internalDocuments) { + renderStructuredInternalDocument.apply(document) + } + }.join("\n\n") /// `extraFrontmatterLines` carries the target-specific frontmatter a skill /// entrypoint supports. Each line ends with a newline; a target that adds none @@ -133,13 +83,13 @@ internal state. The reference contains only human-visible Markdown layouts. ## Canonical workflow -\(internalize.apply(stripFrontmatterMarkers.apply(workflow.command.text))) +\(renderCanonicalWorkflow.apply(workflow)) ## Embedded phase behavior -\(new Listing { for (document in workflow.phaseDocuments) { renderPhase.apply(document.path, document) } }.join("\n\n")) +\(renderPhases.apply(workflow)) -\(new Listing { for (document in workflow.internalDocuments) { renderInternalDocument.apply(document.path, document) } }.join("\n\n")) +\(renderInternalDocuments.apply(workflow)) ## Composite control flow @@ -154,7 +104,7 @@ as the workflow's final response. /// `extraFrontmatterLines` carries the target-specific routing frontmatter a /// command supports, under the same newline-terminated convention as /// `renderSkill`. -renderCommand = (workflow: CompositeWorkflow, extraFrontmatterLines: String) -> new model.WorkflowDocument { +hidden renderCommand = (workflow: CompositeWorkflow, extraFrontmatterLines: String) -> new model.WorkflowDocument { path = workflow.command.path text = """ --- @@ -448,49 +398,45 @@ Present Git's failure unchanged and stop without retrying. local changeWorkflow = new CompositeWorkflow { identity = catalog.workflows["change-to-plan"] command = changeToPlan.workflow.command.document - phaseDocuments = new Listing { - new model.WorkflowDocument { path = "sce-context-load"; text = changeToPlan.workflow.skills["sce-context-load"].documents["SKILL.md"].text } - new model.WorkflowDocument { path = "sce-plan-authoring"; text = changeToPlan.workflow.skills["sce-plan-authoring"].documents["SKILL.md"].text } - } - internalDocuments = new Listing { - new model.WorkflowDocument { path = "Plan template"; text = changeToPlan.workflow.skills["sce-plan-authoring"].documents["references/plan-template.md"].text } - } - outputText = internalize.apply(CHANGE_OUTPUT + "\n\n" + changeToPlan.workflow.skills["sce-plan-authoring"].documents["references/plan-summary.md"].text) + structuredSource = changeToPlan.structuredComposite + outputText = CHANGE_OUTPUT + "\n\n" + new Listing { + for (document in changeToPlan.structuredComposite.outputDocuments) { + document.text + } + }.join("\n\n") } local nextWorkflow = new CompositeWorkflow { identity = catalog.workflows["next-task"] command = nextTask.workflow.command.document - phaseDocuments = new Listing { - new model.WorkflowDocument { path = "sce-plan-review"; text = nextTask.workflow.skills["sce-plan-review"].documents["SKILL.md"].text } - new model.WorkflowDocument { path = "sce-task-execution"; text = nextTask.workflow.skills["sce-task-execution"].documents["SKILL.md"].text } - new model.WorkflowDocument { path = "sce-task-context-sync"; text = nextTask.workflow.skills["sce-task-context-sync"].documents["SKILL.md"].text } - } - internalDocuments = new Listing {} - outputText = internalize.apply(NEXT_OUTPUT + "\n\n" + nextTask.workflow.skills["sce-task-execution"].documents["references/implementation-gate.md"].text + "\n\n" + nextTask.workflow.skills["sce-task-context-sync"].documents["references/sync-report.md"].text) + structuredSource = nextTask.structuredComposite + outputText = NEXT_OUTPUT + "\n\n" + new Listing { + for (document in nextTask.structuredComposite.outputDocuments) { + document.text + } + }.join("\n\n") } local validateWorkflow = new CompositeWorkflow { identity = catalog.workflows["validate"] command = validate.workflow.command.document - phaseDocuments = new Listing { - new model.WorkflowDocument { path = "sce-validation"; text = validate.workflow.skills["sce-validation"].documents["SKILL.md"].text } - new model.WorkflowDocument { path = "sce-plan-context-sync"; text = validate.workflow.skills["sce-plan-context-sync"].documents["SKILL.md"].text } - } - internalDocuments = new Listing { - new model.WorkflowDocument { path = "Plan-file validation report"; text = validate.workflow.skills["sce-validation"].documents["references/validation-report.md"].text } - } - outputText = internalize.apply(VALIDATE_OUTPUT + "\n\n" + validate.workflow.skills["sce-validation"].documents["references/validation-result.md"].text + "\n\n" + validate.workflow.skills["sce-plan-context-sync"].documents["references/sync-report.md"].text) + structuredSource = validate.structuredComposite + outputText = VALIDATE_OUTPUT + "\n\n" + new Listing { + for (document in validate.structuredComposite.outputDocuments) { + document.text + } + }.join("\n\n") } local commitWorkflow = new CompositeWorkflow { identity = catalog.workflows["commit"] command = commit.workflow.command.document - phaseDocuments = new Listing { - new model.WorkflowDocument { path = "sce-atomic-commit"; text = commit.workflow.skills["sce-atomic-commit"].documents["SKILL.md"].text } - } - internalDocuments = new Listing {} - outputText = internalize.apply(COMMIT_OUTPUT + "\n\n" + commit.workflow.skills["sce-atomic-commit"].documents["references/commit-message-style.md"].text) + structuredSource = commit.structuredComposite + outputText = COMMIT_OUTPUT + "\n\n" + new Listing { + for (document in commit.structuredComposite.outputDocuments) { + document.text + } + }.join("\n\n") } workflows = new Mapping { @@ -502,7 +448,7 @@ workflows = new Mapping { /// Each target renders the same two documents per workflow package and differs /// only in the frontmatter its skill entrypoint carries. -skillDocuments = (extraSkillFrontmatterLines: String) -> new Mapping { +hidden skillDocuments = (extraSkillFrontmatterLines: String) -> new Mapping { for (_, workflow in workflows) { ["\(workflow.skillSlug)/SKILL.md"] = renderSkill.apply(workflow, extraSkillFrontmatterLines) ["\(workflow.skillSlug)/references/output.md"] = new model.WorkflowDocument { diff --git a/context/architecture.md b/context/architecture.md index 85fcf79a..0ecdd12b 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -8,13 +8,13 @@ Authored config content is standardized around one canonical Pkl source model wi Current location for canonical workflow content primitives: -- `config/pkl/base/workflow-content.pkl` (workflow command and self-contained skill-package document model, including deterministic package-relative nested references) +- `config/pkl/base/workflow-content.pkl` (workflow command and self-contained skill-package document model, including shared document/package constructors plus typed package-vs-composite render modes, frontmatter, bodies, semantic references, structured documents, and structured composite sources) - `config/pkl/base/workflow-catalog.pkl` (typed four-workflow catalog owning command and skill slugs, titles, descriptions, argument hints, OpenCode routing roles, and Claude allowed-tool metadata) -- `config/pkl/base/workflow-change-to-plan.pkl` (canonical `/change-to-plan` package with the command plus self-contained `sce-context-load` and `sce-plan-authoring` skill/reference documents mirrored from the project-root `.pi/` baseline) -- `config/pkl/base/workflow-next-task.pkl` (canonical `/next-task` package with self-contained `sce-plan-review` and `sce-task-execution` documents plus the task instance from the shared context-sync skeleton) -- `config/pkl/base/workflow-validate.pkl` (canonical `/validate` package with the self-contained `sce-validation` documents plus the plan instance from the shared context-sync skeleton) -- `config/pkl/base/workflow-commit.pkl` (canonical `/commit` package with the self-contained `sce-atomic-commit` skill and references) -- `config/pkl/base/workflow-context-sync.pkl` (one role-parameterized shared-fragment skeleton that emits exact, self-contained task and plan context-sync packages) +- `config/pkl/base/workflow-change-to-plan.pkl` (canonical `/change-to-plan` package with the command plus self-contained `sce-context-load` and `sce-plan-authoring` skill/reference documents mirrored from the project-root `.pi/` baseline, and the first structured composite source rendering its command, phases, persisted plan template, and output references directly) +- `config/pkl/base/workflow-next-task.pkl` (canonical `/next-task` package with self-contained `sce-plan-review` and `sce-task-execution` documents plus the task instance from the shared context-sync skeleton, and a structured composite source rendering its command, phases, state-contract and implementation-gate references, and output references directly) +- `config/pkl/base/workflow-validate.pkl` (canonical `/validate` package with the self-contained `sce-validation` documents plus the plan instance from the shared context-sync skeleton, and a structured composite source rendering its command, validation and plan-sync phases, persisted validation-report format, failed-validation state, and output references directly) +- `config/pkl/base/workflow-commit.pkl` (canonical `/commit` package with the self-contained `sce-atomic-commit` skill and references, plus a structured composite source rendering its command, atomic-commit phase, internal-state vocabulary, and message-style output directly) +- `config/pkl/base/workflow-context-sync.pkl` (one role-parameterized source that renders exact, self-contained task and plan context-sync skills in named semantic section order, renders their synced, no-context-change, and blocked report layouts through shared named section renderers from typed lifecycle-role data, and exposes both skills as mode-aware structured phases for next-task and validate composition) - `config/pkl/base/opencode.pkl` - `config/pkl/base/sce-config-schema.pkl` @@ -22,7 +22,7 @@ Current target renderer helper modules: - `config/pkl/renderers/opencode-content.pkl` - `config/pkl/renderers/claude-content.pkl` -- `config/pkl/renderers/workflow-composite.pkl` (target-neutral composition of canonical phases into four workflow-level skills and their single `references/output.md` presentation documents, parameterized by the frontmatter lines each target supports) +- `config/pkl/renderers/workflow-composite.pkl` (target-neutral composition of canonical phases into four workflow-level skills and their single `references/output.md` presentation documents; requires and consumes structured composite sources directly without prose-wide rewriting) - `config/pkl/renderers/pi-content.pkl` - `config/pkl/renderers/common.pkl` - `config/pkl/renderers/opencode-metadata.pkl` @@ -30,7 +30,9 @@ Current target renderer helper modules: - `config/pkl/renderers/metadata-coverage-check.pkl` - `config/pkl/renderers/generation-contract-check.pkl` - `config/pkl/generate.pkl` (single multi-file generation entrypoint) -- `config/pkl/check-generated.sh` (dev-shell integration check for two-pass deterministic temporary inventories, required outputs, forbidden repository generated paths, and the stray repository-local `config/pkl/rendered` evaluation artifact) +- `config/pkl/generator-inputs.txt` (machine-readable repository-relative declaration of canonical Pkl and referenced plugin/extension inputs) +- `scripts/produce-cli-generated-input.sh` (canonical generated-input producer for input discovery, two-pass evaluation, determinism and input-mutation checks, exact payload/input inventories, atomic publication, and temporary-state cleanup; consumed by the repository Cargo wrapper, generated-output check, package-fallback preparation, and Nix `cliGeneratedInput` derivation) +- `config/pkl/check-generated.sh` (dev-shell integration check that delegates deterministic generation and inventories to the producer while retaining metadata/contract fixtures, required outputs, forbidden repository generated paths, and the stray repository-local `config/pkl/rendered` evaluation artifact) - `nix flake check` / `checks..{cli-tests,cli-clippy,cli-fmt,pkl-generated,npm-bun-tests,npm-biome-check,npm-biome-format,config-lib-bun-tests,config-lib-biome-check,config-lib-biome-format,workflow-actionlint}` plus Linux-only `flatpak-static-validation`, `cargo-sources-parity`, and `flatpak-manifest-parity` (root-flake checks for CLI behavior, ephemeral Pkl generation, JS validation, workflow linting, and lightweight Flatpak validation) - `config-lib-bun-tests` executes from `config/lib/` while using a repo-shaped copied source subset that also includes `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden fixture coverage (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). @@ -41,16 +43,16 @@ Renderer modules apply target-specific metadata/frontmatter rules while reusing - All three renderers consume the four canonical workflow packages as behavior sources and emit the same four workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Each thin command or prompt invokes exactly one corresponding workflow skill. - Per-target differences are confined to frontmatter and the surrounding non-workflow outputs. The manual OpenCode renderer adds `agent`, `entry-skill`, and a one-entry `skills` list to command frontmatter, adds `compatibility: opencode` to each package entrypoint, and emits two thin routing agents whose `skill:` permission allowlists name only the four workflow slugs. The Claude renderer adds `compatibility: claude` plus `allowed-tools:` and emits no agents; Claude settings and the hook helper remain separate retained outputs. The Pi renderer adds no frontmatter to either prompts or skills. - Pi renderer consumes the same shared workflow composition as OpenCode and Claude. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). -- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow behavior definitions, phase-internalization substitution tables, and four output layouts, while each composite looks up its typed identity in `config/pkl/base/workflow-catalog.pkl`. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a given target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and a catalog-derived `allowed-tools` line for commands. +- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions and output layouts, while each composite looks up its typed identity in `config/pkl/base/workflow-catalog.pkl`. Every workflow supplies a required `StructuredCompositeSource`, so commands, phase documents, persisted-document formats, and output references render in package or composite mode before Markdown assembly. The renderer has no nullable legacy adapter, frontmatter stripping, or prose-wide replacement chain. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and a catalog-derived `allowed-tools` line for commands. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). - Target renderers remain responsible for formatting target-supported metadata. OpenCode metadata owns thin-agent presentation and compatibility while deriving workflow permission lines from catalog role assignments; OpenCode command routing derives the same role and skill identity from the catalog. Claude metadata derives command tools from catalog records. Pi has no metadata module because it adds no target-specific frontmatter. - `config/pkl/renderers/metadata-coverage-check.pkl` derives command and two-file workflow-package expectations from the typed catalog, asserts each target's exact current inventory—four commands (Pi: prompts), four two-file workflow packages per target, and two OpenCode agents—then verifies every command's one-to-one workflow-skill route for all three targets through the target-labelled `assertCommandRoute(target, slug, document)`, and forces every rendered document and target metadata lookup to evaluate. -- `config/pkl/renderers/generation-contract-check.pkl` independently derives the complete expected artifact paths from those target document inventories plus explicitly retained non-workflow assets, compares them with `generate.pkl`'s `output.files`, and requires exactly 46 paths. It also scans every generated workflow package document for stale phase-skill slugs and package-local reference tokens that should have been removed by composite internalization. Checked-in negative fixtures prove that deterministic extra and missing artifacts and a forbidden workflow reference fail the contract. +- `config/pkl/renderers/generation-contract-check.pkl` independently derives the complete expected artifact paths from those target document inventories plus explicitly retained non-workflow assets, compares them with `generate.pkl`'s `output.files`, and requires exactly 46 paths. It also scans every generated workflow package document for stale phase-skill slugs and unresolved package-local reference tokens. Checked-in negative fixtures prove that deterministic extra and missing artifacts and a forbidden workflow reference fail the contract. - OpenCode, Claude, and Pi renderers expose command documents plus flattened `{skill slug}/{package-relative path}` skill documents consumed by `config/pkl/generate.pkl`; every target's flattened inventory contains only `SKILL.md` and `references/output.md` for each workflow slug. - `config/pkl/generate.pkl` emits deterministic `output.files` mappings for all authored generated targets: OpenCode's four workflow commands, four two-file workflow skill packages, and two thin routing agents; Claude's four thin commands and four two-file workflow skill packages with no agents; Claude project settings and hook helper; shared bash-policy preset assets; OpenCode plugin entrypoints (`sce-bash-policy.ts` and `sce-agent-trace.ts`); generated OpenCode `opencode.json`; the Pi target tree (four thin workflow prompts, four two-file workflow skill packages, and the extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts`); and the generated `sce/config.json` schema artifact. The removed `config/automated/.opencode` profile has no generator ownership or output mappings. - Generated-file warning markers are not injected by the generator: Markdown outputs render deterministic frontmatter + body, and shared library outputs are emitted without a leading generated warning header. -- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects the repository-local `config/pkl/rendered` evaluation artifact before generation, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata and generation contracts, confirms the extra/missing/reference negative fixtures fail with their contract diagnostics, generates twice into temporary roots, and compares sorted SHA-256 inventories. Required-path checks remain fast surface diagnostics; the Pkl contract owns exact complete-path coverage, while forbidden-output checks reject removed generator surfaces. The root-flake `pkl-generated` derivation runs the same script from a focused canonical-input source set. +- `config/pkl/check-generated.sh` is intentionally dev-shell scoped (`nix develop -c ...`): it requires `IN_NIX_SHELL`, rejects the repository-local `config/pkl/rendered` evaluation artifact before generation, rejects committed target trees, the generated SCE schema, and `cli/assets/generated`, evaluates exact metadata and generation contracts, confirms the extra/missing/reference negative fixtures fail with their contract diagnostics, then delegates two-pass generation, input checks, and payload inventories to `scripts/produce-cli-generated-input.sh`. It projects the producer inventory only to preserve the established report digest path format; it does not rehash generated files. Required-path checks remain fast surface diagnostics, the Pkl contract owns exact complete-path coverage, and forbidden-output checks reject removed generator surfaces. Generated authored classes: @@ -87,7 +89,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - Repo-root `.version` is the canonical checked-in release version authority across GitHub Releases, Cargo publication, and npm publication. - GitHub Releases are the canonical publication surface for release archives, checksums, release-manifest assets, npm package assets, and approved Flatpak source-manifest and bundle assets. - Cargo/crates.io and npm registry publication belong to separate downstream publish stages that consume already-versioned checked-in package metadata rather than inventing release versions during workflow execution. -- Crates.io packaging is self-contained through ignored `cli/package-fallback/`: the preparation script generates and inventories the payload from canonical Pkl plus static inputs in a temporary clean workspace, `cli/Cargo.toml` includes only that fallback and crate sources, and unpacked-crate `build.rs` validates then copies it into `OUT_DIR` without Pkl. Repository builds use `scripts/run-cli-cargo.sh` to generate a fresh deterministic payload and both inventories before Cargo; `build.rs` requires the resulting `SCE_CLI_GENERATED_INPUT_DIR` handoff and copies it into `OUT_DIR` without invoking Pkl. +- Crates.io packaging is self-contained through ignored `cli/package-fallback/`: the preparation script delegates canonical Pkl generation and inventories to the shared producer, moves its validated payload and checksums into a temporary staged fallback, adds static hooks/schemas/migrations, and appends static checksums to the exact combined inventory. `cli/Cargo.toml` includes only that fallback and crate sources, and unpacked-crate `build.rs` validates then copies it into `OUT_DIR` without Pkl. Repository builds use `scripts/run-cli-cargo.sh`, which consumes the same producer before Cargo; `build.rs` requires the resulting `SCE_CLI_GENERATED_INPUT_DIR` handoff and copies it into `OUT_DIR` without invoking Pkl. - npm is a downstream consumer of the shared release artifact contract rather than a separate build owner. - `flake.nix` now exposes dedicated release-packaging apps for this rollout: `apps.release-artifacts` packages the current-platform `sce` archive/checksum/manifest-fragment set from the release output `packages.sce-release` (`nix build .#sce-release`), prepares/audits the staged `bin/sce` before archive creation (including macOS `libiconv` install-name rewriting plus ad-hoc re-signing when needed), and fails if `.version`, `cli/Cargo.toml`, `npm/package.json`, the built/prepared CLI version, or the native portability audit disagree; `apps.native-portability-audit` audits native binaries for forbidden `/nix/store/` runtime references using Linux ELF/string inspection or macOS `otool -L`; `apps.release-manifest` merges per-platform metadata fragments into release-level manifest/checksum outputs and signs the merged manifest with a non-repo private key provided via env/file input; `apps.release-npm-package` packs the checked-in npm launcher package into a release-ready `sce-v-npm.tgz` tarball plus npm metadata JSON while refusing mismatched checked-in version metadata; and Linux-only `apps.release-flatpak-package` emits the Flatpak source-manifest tarball/checksum/JSON metadata while refusing `.version`/Cargo/npm/AppStream version drift and non-git checkouts that cannot resolve a release commit; Linux-only `apps.release-flatpak-bundle` builds a source-built `.flatpak` bundle from the checkout and emits per-architecture bundle/checksum/JSON metadata. - CLI release automation: `.github/workflows/release-sce.yml` orchestrates `sce` GitHub release asset assembly, validates `.version`/Cargo/npm parity before tagging or releasing, calls three reusable per-platform workflow files (`release-sce-linux.yml`, `release-sce-linux-arm.yml`, `release-sce-macos-arm.yml`), assembles the signed native release manifest, builds npm and Flatpak source-manifest release packages, and uploads the CLI/npm/Flatpak asset set to the GitHub Release. Each native reusable workflow validates its generated archive before native artifact upload by extracting the target archive, smoke-running `bin/sce version --format json`, and running `nix run .#native-portability-audit` with the lane platform. Manual `workflow_dispatch` runs can set the GitHub Release-level `prerelease` flag through an explicit checkbox; tag-triggered releases keep the flag false and no tag-name prerelease inference is performed. @@ -132,7 +134,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/structured_patch.rs` defines the synchronous structured editor-hook derivation seam. It derives Claude `PostToolUse` `Write` structured-update hunks, `Write` `tool_input.content` create fallback, and `Edit` structured-patch payloads into canonical `ParsedPatch` values plus Claude session/tool metadata, returning deterministic skip reasons for unsupported events/tools/payload shapes. The module is pure and side-effect-free. It is wired into `sce hooks diff-trace` for Claude payload classification at intake (T04) and into `RepositoryAgentTraceDb::recent_diff_trace_patches` for post-commit structured payload parsing dispatch at read time (T05). - `cli/src/services/` contains module boundaries for command_registry, lifecycle, auth_command, config, setup, doctor, hooks, checkout identity, bash_policy, version, completion, help, patch, SCE web URL helpers, shared database infrastructure, local DB adapters, encrypted auth DB adapters, and Agent Trace DB adapters with explicit trait seams for future implementations. `cli/src/services/checkout/` owns checkout ID file infrastructure (the per-checkout Agent Trace DB opener/path helper was removed by the `retire-legacy-agent-trace-db` plan); active setup/hooks use `agent_trace_storage` to establish checkout identity as diagnostics and initialize/open the repository-scoped DB, while `sce doctor` surfaces checkout identity facts plus credential-safe repository Agent Trace DB metadata. There is no checkout-scoped discovery or `sce trace --legacy` surface; any pre-migration `agent-trace-*.db` files on disk are never touched and no longer inspectable via the CLI. `cli/src/services/bash_policy.rs` owns both the CLI-agnostic evaluator logic and the hidden `sce policy bash` command adapter used by OpenCode, Claude, and Pi callers. `cli/src/services/command_registry.rs` defines the static `RuntimeCommand` enum, deterministic `CommandRegistry` name catalog, and `build_default_registry()` function for command dispatch metadata. Service-owned command modules own the runtime command payload structs for help/help-text, version, completion, auth, config, setup, doctor, hooks, and policy. - `cli/README.md` is the crate-local onboarding and usage source of truth for placeholder behavior, safety limitations, and roadmap mapping back to service contracts. -- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, and reads package/check version from repo-root `.version`. Its `cliGeneratedInput` derivation evaluates the canonical Pkl model twice, rejects nondeterminism, and writes exact payload and canonical-input SHA-256 inventories. Native, release, test, and Clippy Cargo derivations receive that same store path through `SCE_CLI_GENERATED_INPUT_DIR`; their Cargo environments exclude Pkl and assert that it is unavailable. Repository-mode `cli/build.rs` validates the handoff before copying it into `OUT_DIR`; published crates use the validated packaging-only fallback. The build script stages SQL under `OUT_DIR/static/migrations` and writes `OUT_DIR/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. +- `flake.nix` applies `rust-overlay` (`oxalica/rust-overlay`) to nixpkgs, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, and reads package/check version from repo-root `.version`. Its `cliGeneratedInput` derivation invokes the shared generated-input producer from a declarative source containing the producer and canonical inputs, then publishes the producer-validated handoff as its store output. Native, release, test, and Clippy Cargo derivations receive that same store path through `SCE_CLI_GENERATED_INPUT_DIR`; their Cargo environments exclude Pkl and assert that it is unavailable. Repository-mode `cli/build.rs` validates the handoff before copying it into `OUT_DIR`; published crates use the validated packaging-only fallback. The build script stages SQL under `OUT_DIR/static/migrations` and writes `OUT_DIR/generated_migrations.rs` with deterministic migration constants sorted by numeric filename prefix. - Crane dependency-only derivations and `cli-fmt` intentionally do not receive `SCE_CLI_GENERATED_INPUT_DIR`, so canonical generation changes invalidate the producer and compiling derivations while preserving host/musl dependency artifacts and formatting. The root flake runs `cli-tests`, `cli-clippy`, and `cli-fmt` through Crane-backed paths and exposes `cli-generated-input` as the focused payload/inventory integrity check. It also exposes directory-scoped JS validation derivations for `npm/` and `config/lib/`, while `pkl-generated` uses a narrow canonical-input source set plus maybe-missing forbidden paths so reintroduced generated repository artifacts fail the check. - Git-commit embedding is release-only. `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment (`{ SCE_GIT_COMMIT = shortGitCommit; }`) merged only into the release derivations — `scePackageMusl` on Linux and a dedicated native-toolchain `sceReleasePackageNative` on Darwin — and is deliberately absent from `commonCargoArgs`. As a result native `packages.sce`/`packages.default` and the `cli-tests`/`cli-clippy`/`cli-fmt` check derivations carry no commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` reports the real commit. `cli/build.rs` `emit_git_commit` emits the `rustc-env` value only when `SCE_GIT_COMMIT` is explicitly set (with `rerun-if-env-changed=SCE_GIT_COMMIT` as its sole rerun trigger) — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` watches — and `cli/src/services/version/mod.rs` resolves the commit through `option_env!("SCE_GIT_COMMIT")` with an `"unknown"` fallback. On Darwin the release derivation therefore diverges from `.#sce` (shared deps `cargoArtifacts`, but distinct final crate carrying the commit). - `flake.nix` exposes `packages..ci-checks` (`ciChecks`) as the explicit long-running validation tier so the expensive work lives behind `nix build .#ci-checks` and never folds into `nix flake check`. It is a `runCommand` aggregate that symlinks its primary member `sceReleasePackage` into `$out/sce-release` (forcing the static-musl release build on Linux, native on Darwin) and, on Linux only, symlinks `releasePortabilityAuditCheck` into `$out/release-portability-audit`. That Linux-only `releasePortabilityAuditCheck` derivation runs `nix/release/native-portability-audit.sh --platform linux --binary ${sceReleasePackage}/bin/sce` (with `binutils`+`coreutils` on PATH) so `nix build .#ci-checks` fails when the real release binary carries forbidden `/nix/store/` references. This is distinct from `checks..native-portability-audit` (`nativePortabilityAuditCheck`), which remains a fixture-based unit test of the audit script on both platforms. CI wiring to `.#ci-checks` is owned by the separate `release-validation` matrix job in `.github/workflows/pr-ci.yml`, which builds `nix build .#ci-checks` on every PR/`main`/tag commit. diff --git a/context/context-map.md b/context/context-map.md index 14d2c967..0ee36151 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -64,8 +64,8 @@ Feature/domain context: - `context/sce/cli-first-install-channels-contract.md` (current Nix/Cargo/npm/source-built Flatpak channel contract, release authority and workflow topology, Nix-owned Flatpak manifest/cargo-source generation and validation, reduced Flatpak app surface, and host-git bridge decision) - `context/sce/cli-release-artifact-contract.md` (shared `sce` binary release artifact naming, checksum/manifest outputs, pre-archive staged-binary preparation including macOS `libiconv` install-name sanitization/ad-hoc re-signing, native portability audit app/check for forbidden `/nix/store/` runtime references, GitHub Releases as the canonical artifact publication surface, manual dispatch `prerelease` flag behavior, the current three-target Linux/macOS release workflow topology including pre-upload extracted-archive smoke/audit validation in each native lane, implemented Flatpak source-manifest and source-built `.flatpak` bundle package assets uploaded by `.github/workflows/release-sce.yml`, and Flatpak's explicit source-built non-binary exception) - `context/sce/cli-npm-distribution-contract.md` (implemented `sce` npm launcher package, release-manifest/checksum-verified native binary install flow, the supported darwin/arm64 plus linux x64+arm64 npm platform matrix, the prerequisite that npm-consumed native archives are portable and free of forbidden `/nix/store/` runtime references before upload, and dedicated `.github/workflows/publish-npm.yml` downstream npm publish-stage contract including prerelease publication via npm `next` dist-tag instead of `latest`) -- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io and wrapper-driven local-checkout install guidance, explicit unsupported `cargo install --git` boundary, dedicated crates.io publish workflow with semver prerelease guard, `scripts/run-cli-cargo.sh` ownership of the validated `SCE_CLI_GENERATED_INPUT_DIR` repository-build handoff, and the deterministic checksummed packaging-only fallback used for Pkl-free downstream crate builds) -- `context/sce/flake-build-performance.md` (current native-vs-release package split, release-only commit embedding, deterministic pre-Cargo generated-input derivation shared by native/release/test/Clippy but excluded from dependency/format derivations, slim default/database devShell contract, normal-vs-expensive CI tiers, durable before/after benchmark summary, validation evidence, and remaining cold-build trade-offs) +- `context/sce/cli-cargo-distribution-contract.md` (implemented `sce` Cargo publication posture plus supported crates.io and wrapper-driven local-checkout install guidance, explicit unsupported `cargo install --git` boundary, dedicated crates.io publish workflow with semver prerelease guard, canonical generated-input declaration/producer ownership consumed by the Cargo wrapper, generated-output check, package-fallback preparation, and Nix pre-Cargo derivation, plus the deterministic combined checksummed fallback used for Pkl-free downstream crate builds) +- `context/sce/flake-build-performance.md` (current native-vs-release package split, release-only commit embedding, shared-producer-backed pre-Cargo generated-input derivation consumed by native/release/test/Clippy but excluded from dependency/format derivations, slim default/database devShell contract, normal-vs-expensive CI tiers, durable before/after benchmark summary, validation evidence, and remaining cold-build trade-offs) - `context/sce/flatpak-distribution-patterns.md` (source-built Flatpak conventions, including Nix-side ephemeral fallback preparation for the Pkl-free build sandbox, manifest generation, local/release builds, release assets, and host-git bridge) Working areas: diff --git a/context/glossary.md b/context/glossary.md index ca3e9c49..bb609e0d 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -1,17 +1,19 @@ # Glossary -- `pkl-check-generated`: Flake app exposed as `nix run .#pkl-check-generated`; canonical ephemeral-generation check that rejects committed target/schema/mirror outputs, evaluates exact workflow metadata and the complete 46-path generated artifact contract, rejects stale sibling-package references or unresolved internalization tokens, proves extra/missing/reference failures through negative fixtures, generates twice into temporary roots, and compares sorted SHA-256 inventories. +- `pkl-check-generated`: Flake app exposed as `nix run .#pkl-check-generated`; canonical ephemeral-generation check that rejects committed target/schema/mirror outputs, evaluates exact workflow metadata and the complete 46-path generated artifact contract, rejects stale sibling-package references or unresolved internalization tokens, proves extra/missing/reference failures through negative fixtures, and delegates deterministic generation plus payload/input inventories to the generated-input producer while preserving its established inventory report. - `repo-level verification preference`: Current repository guidance that contributor-facing validation/check flows should prefer `nix flake check`; direct Cargo verification commands are secondary and used only when explicitly requested or for narrow targeted debugging, while `cargo fmt` remains the explicit autofix path. - lightweight post-task verification baseline: Required quick checks after each completed task in this repo: `nix run .#pkl-check-generated` and `nix flake check`. - disposable plan lifecycle: Policy where `context/plans/` holds active execution artifacts only; completed plans are disposable and durable outcomes must be reflected in current-state context files and/or `context/decisions/`. - important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. -- `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `scripts/run-cli-cargo.sh` generates canonical Pkl twice, rejects nondeterminism, places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` for the canonical `config/pkl` and referenced `config/lib` inputs there, then removes the handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. +- `CLI generated-input handoff`: Repository-build contract rooted at the temporary directory named by `SCE_CLI_GENERATED_INPUT_DIR`. `config/pkl/generator-inputs.txt` declares the canonical `config/pkl` and referenced `config/lib` inputs; `scripts/produce-cli-generated-input.sh` discovers those files, generates Pkl twice, rejects nondeterminism and in-flight input mutation, and atomically places `pkl-generated/`, its exact `SHA256SUMS`, and `INPUTS.SHA256SUMS` there. `scripts/run-cli-cargo.sh` delegates production and removes its temporary handoff after Cargo exits. `cli/build.rs` verifies payload integrity and input freshness before copying `pkl-generated/` into Cargo `OUT_DIR`; missing, incomplete, modified, or stale handoffs fail rather than invoking Pkl or falling back to packaged assets. +- `generated-input producer`: Repository-owned `scripts/produce-cli-generated-input.sh` contract driven by `config/pkl/generator-inputs.txt`. It is the canonical owner for expanding repository-relative generator inputs, snapshotting their inventory, two-pass Pkl evaluation, byte-tree determinism comparison, payload and canonical-input SHA-256 inventories, input-mutation rejection, atomic output publication, and private staging cleanup. The repository Cargo wrapper, generated-output check, package-fallback preparation, and Nix `cliGeneratedInput` derivation all consume it. - `Pi workflow package`: Generated Pi workflow surface consisting of one thin prompt in `config/.pi/prompts/` plus the one workflow skill package under `config/.pi/skills/` that the prompt routes to, containing exactly `SKILL.md` and `references/output.md`. Pi currently receives `/change-to-plan`, `/next-task`, `/validate`, and `/commit` this way and has no generated agent-role prompts. - `workflow skill package`: One of the four renderer-composed packages (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, `sce-commit`) emitted for every target. Its `SKILL.md` directly owns the complete canonical phase sequence, internal status branching, user waits and same-session resume behavior, writes, and continuation; it invokes no phase or sibling SCE skill. Its only other file is `references/output.md`. The canonical phase modules remain authoring inputs to composition and are not generated as packages for any target. - `workflow catalog`: The typed mapping in `config/pkl/base/workflow-catalog.pkl` that declares each of the four workflows once and owns its command slug, skill slug, title, description, argument hint, OpenCode routing role, and Claude allowed tools. Composite identity, OpenCode routing/permissions, Claude tool frontmatter, and metadata coverage derive from these records; behavior remains in canonical phase modules and formatting remains renderer-owned. -- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It owns the four composite behavior definitions and phase-internalization substitution tables while looking up shared workflow identity in the workflow catalog. All three targets render through it, parameterized only by the extra frontmatter each supports. +- `workflow composite renderer`: The shared, target-neutral Pkl module at `config/pkl/renderers/workflow-composite.pkl` that composes a canonical workflow command, its phase skills, and its persisted-document formats into one workflow-level `SKILL.md` plus that package's `references/output.md`. It requires structured composite sources for all four workflows and performs no frontmatter stripping or prose-wide internalization. All three targets render through it, parameterized only by the extra frontmatter each supports. +- `structured workflow rendering`: Canonical Pkl representation in `workflow-content.pkl` where package-vs-composite mode is selected through typed frontmatter, body, semantic-reference, structured-document, and composite-source values before Markdown assembly. All four workflows render their commands, internal phases, persisted-document formats where applicable, and output references directly in both modes without frontmatter stripping or prose-wide replacement. - `canonical phase module`: One of the eight phase definitions in `config/pkl/base/workflow-*.pkl` (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, `sce-atomic-commit`). Each is the single behavioral source for its phase and an authoring input to the composite renderer. Since 2026-07-29 no target generates them as installable skill packages; the names denote canonical source and the internal phases inside a composed `SKILL.md`. - `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. - `workflow output reference`: The required `references/output.md` in every workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. @@ -29,7 +31,7 @@ - `config-lib repo-shaped test source`: Root-flake source-layout contract where `config-lib-bun-tests`, `config-lib-biome-check`, and `config-lib-biome-format` run from `config/lib/` while their copied Nix source preserves repo-relative shared fixtures, currently `cli/src/services/structured_patch/fixtures` for Claude agent-trace golden tests (fully Rust-owned; the Claude TypeScript Bun test was removed in T07). - `config-lib shared package root`: Shared Bun/TypeScript package root at `config/lib/` for repository-owned OpenCode plugin support code. It owns `package.json`, `bun.lock`, and `tsconfig.json`, pins `@opencode-ai/plugin` to `1.15.4`, includes both `agent-trace-plugin/**/*.ts` and `bash-policy-plugin/**/*.ts` in strict TypeScript coverage, and excludes package-local `node_modules/` from both TypeScript and root Biome coverage. - `cli rust overlay toolchain`: Toolchain contract in root `flake.nix` that applies `rust-overlay.overlays.default`, pins `rust-bin.stable.1.95.0.default` with `rustfmt` + `clippy`, uses that toolchain across both Crane package and check derivations, and keeps toolchain selection explicit rather than inheriting nixpkgs defaults. -- `cli Crane package pipeline`: Root-flake packaging path where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage`. One deterministic `cliGeneratedInput` derivation evaluates canonical Pkl twice and inventories its payload and inputs; native and release compiling derivations consume the same validated `SCE_CLI_GENERATED_INPUT_DIR` store path and embed only from Cargo `OUT_DIR`. Pkl is unavailable inside Cargo derivations, and host/musl dependency-only artifacts omit the handoff so generated-input changes do not rebuild dependencies. +- `cli Crane package pipeline`: Root-flake packaging path where `packages.sce` is built through `craneLib.buildDepsOnly` plus `craneLib.buildPackage`. One deterministic `cliGeneratedInput` derivation invokes the shared generated-input producer; native and release compiling derivations consume the resulting validated `SCE_CLI_GENERATED_INPUT_DIR` store path and embed only from Cargo `OUT_DIR`. Pkl is unavailable inside Cargo derivations, and host/musl dependency-only artifacts omit the handoff so generated-input changes do not rebuild dependencies. - `cli Crane check pipeline`: Current root-flake check path in `flake.nix` where `cli-tests`, `cli-clippy`, and `cli-fmt` run through `craneLib.cargoTest`, `craneLib.cargoClippy`, and `craneLib.cargoFmt`; test and Clippy receive the shared generated-input handoff and reuse `cargoArtifacts`, while format receives neither because it does not compile the CLI. `cli-generated-input` separately verifies required target roots plus payload and canonical-input inventories. - `repo-root .version contract`: Repository packaging/version-source contract where `.version` stores the canonical semver string for flake-evaluated CLI package/check metadata and the approved release version authority for GitHub Releases, Cargo publication, and npm publication; `flake.nix` trims and reuses that value instead of hardcoding a version literal, and staged generated-config workflows must mirror it when Pkl renderers read the same path. - `Flatpak source-manifest GitHub Release asset`: Non-binary release asset set for source-built `dev.crocoder.sce`: the manifest tarball, checksum, and JSON metadata emitted by `nix run .#release-flatpak-package`. The tarball contains manifest/support files plus an ephemeral checksummed `cli-package-fallback/`; Flatpak copies that directory to `cli/package-fallback` before its offline Cargo source build, so no Pkl executable or prebuilt `sce` binary is bundled. diff --git a/context/overview.md b/context/overview.md index 3d7ced5e..a519e7e8 100644 --- a/context/overview.md +++ b/context/overview.md @@ -1,6 +1,6 @@ # Overview -This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. One typed workflow catalog owns the four workflows' shared identity and target routing metadata, while canonical phase modules own behavior and target renderers own formatting. Generated target layouts are ephemeral: repository builds consume a pre-Cargo generated payload through `SCE_CLI_GENERATED_INPUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` enforces the exact 46-path artifact contract, exact workflow metadata/package coverage, fully internalized workflow references, and repeatable temporary inventories; `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. +This repository maintains shared assistant configuration for OpenCode, Claude, and Pi from a single canonical Pkl authoring source. One typed workflow catalog owns the four workflows' shared identity and target routing metadata, while canonical phase modules own behavior and target renderers own formatting. Generated target layouts are ephemeral: repository builds consume a pre-Cargo generated payload through `SCE_CLI_GENERATED_INPUT_DIR`, crates.io and Flatpak stage packaging-only fallbacks, and `config/.opencode`, `config/.claude`, `config/.pi`, and the generated SCE config schema are not committed. `nix run .#pkl-check-generated` preserves its exact 46-path artifact, metadata/package, internal-reference, required-path, and forbidden-path checks while delegating deterministic payload production and inventories to the shared generated-input producer; `nix flake check` runs the same contract. The target matrix contains one manual OpenCode profile plus Claude and Pi; the former automated OpenCode profile has been removed. It also includes a Rust CLI (`sce`) for Shared Context Engineering workflows: auth, config inspection, setup, doctor, agent-trace hooks, bash-policy evaluation, and trace database inspection. See `context/architecture.md` for module-level boundaries and `context/context-map.md` for the full domain file index. @@ -24,7 +24,7 @@ The CLI now also enforces a shared output-format parser contract in `cli/src/ser Agent Trace lifecycle setup now resolves repository storage, creates/reuses checkout identity for diagnostics, and initializes `/sce/repos//agent-trace.db` via `RepositoryAgentTraceDb`; hook runtime lazy initialization uses the same repository storage resolver when setup has not prepared the DB or schema metadata is incomplete. The CLI now also includes a shared text styling service in `cli/src/services/style.rs` that provides deterministic color enablement via `owo-colors`, automatic TTY detection, and `NO_COLOR` compliance for human-facing text output; stdout help/text surfaces, stderr diagnostics, and interactive prompt-adjacent text now reuse that shared styling policy while JSON, completion, and other non-interactive/machine-readable flows remain unstyled. The service exports color-detection, conditional styling, help/diagnostic/label/prompt styling, and `banner_with_gradient()` helpers for use across command surfaces while preserving pipe-safe output for non-interactive environments. The `setup` command includes an `inquire`-backed target-selection flow: default interactive selection for OpenCode/Claude/Pi/All with required-hook installation in the same run, explicit non-interactive target flags (`--opencode`, `--claude`, `--pi`, `--all`), standalone `--bootstrap-context` for additive durable-context baseline creation without integration installs, deterministic mutually-exclusive validation, and non-destructive cancellation exits; the former `--both` flag was removed in favor of `--all` (opencode+claude+pi). Every normal successful setup path also ensures the same context baseline after the Git gate. -For repository Cargo builds, `scripts/run-cli-cargo.sh` evaluates the canonical `config/pkl/generate.pkl` model twice into a fresh temporary generated-input directory, rejects nondeterminism, and records SHA-256 inventories for both the payload and canonical generator inputs before invoking the requested Cargo workflow with `SCE_CLI_GENERATED_INPUT_DIR`. The wrapper cleans up after Cargo success, failure, or handled signals. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, copies the validated payload into Cargo `OUT_DIR/pkl-generated`, stages hook templates, the Agent Trace schema, and SQL migrations under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`; it never invokes Pkl. `cli/src/services/setup/mod.rs` exposes deterministic normalized relative paths, embedded bytes, and target-scoped iteration without runtime reads from `config/`; production setup, policy, config-schema, Agent Trace, and migration includes all resolve through `OUT_DIR`. Published crates instead carry an ignored, packaging-only fallback generated deterministically from the same canonical inputs before `cargo package`; unpacked downstream builds validate and copy that payload into their own `OUT_DIR` without requiring Pkl or parent repository paths. +For repository generation consumers, `config/pkl/generator-inputs.txt` declares the canonical Pkl/plugin input set and `scripts/produce-cli-generated-input.sh` owns its discovery, two-pass `config/pkl/generate.pkl` evaluation, determinism comparison, payload/input inventories, in-flight input-mutation rejection, atomic handoff publication, and staging cleanup. `scripts/run-cli-cargo.sh` creates a fresh temporary destination, delegates generation to that producer, invokes the requested Cargo workflow with `SCE_CLI_GENERATED_INPUT_DIR`, and removes the handoff after Cargo success, failure, or handled signals. `config/pkl/check-generated.sh` delegates the same production mechanics while retaining contract and path assertions. `scripts/prepare-cli-generated-assets.sh` moves the producer-validated Pkl payload and checksums into the unchanged package fallback, adds hooks, migrations, and the Agent Trace schema, and appends only those static checksums to the combined inventory. The root flake's pre-Cargo `cliGeneratedInput` derivation invokes the same producer from a declarative source containing the producer plus its declared inputs. `cli/build.rs` rejects missing, incomplete, modified, or stale repository handoffs, copies the validated payload into Cargo `OUT_DIR/pkl-generated`, stages static inputs under `OUT_DIR/static`, and writes setup-asset plus migration Rust manifests into `OUT_DIR`; it never invokes Pkl. Published crates carry the ignored packaging-only fallback, and unpacked downstream builds validate and copy it into their own `OUT_DIR` without requiring Pkl or parent repository paths. The setup service also provides repository-root install orchestration: it resolves the repository root, ensures the additive durable-context baseline, then for normal modes derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup uses a unified remove-and-replace policy for all write flows — it removes existing targets before swapping staged content and returns deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs` now separates install-flow logic from interactive prompt logic through focused support seams. The CLI now also applies baseline security hardening for reliability-driven automation: diagnostics/logging paths use deterministic secret redaction, `sce setup --hooks --repo ` canonicalizes and validates repository paths before execution, and setup write flows run explicit directory write-permission probes before staging/swap operations. The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_file`, `log_file_mode`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config_root}/sce/config.json` then `.sce/config.json` with local override, where `config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_file_mode=truncate`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by` wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as `nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json` JSON Schema generated beneath Cargo `OUT_DIR` and embedded by `cli/src/services/config/mod.rs` for both `sce config validate` and doctor-time config checks. Runtime startup config loading now keeps parity with that schema by accepting the canonical `"$schema": "https://sce.crocoder.dev/config.json"` declaration in repo-local and global config files, so startup commands such as `sce version` no longer fail before dispatch on that field. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for file logging; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/data/bash-policy-presets.json` and `context/sce/bash-tool-policy-enforcement-contract.md`. @@ -37,7 +37,7 @@ The config service split now includes `cli/src/services/config/resolver.rs` as t Generated config now includes repo-local OpenCode plugin assets: `sce-bash-policy.ts` plus `sce-agent-trace.ts` are emitted under `config/.opencode/plugins/`; the OpenCode agent-trace plugin extracts `{ sessionID, diff, time, model_id }` from user `message.updated` events with diffs, tracks per-session OpenCode client version from `session.created`/`session.updated`, and sends payloads to `sce hooks diff-trace` with `tool_name="opencode"` plus optional `tool_version`. Claude generated config now routes supported `PostToolUse Write|Edit|MultiEdit|NotebookEdit` events directly to `sce hooks diff-trace`; it no longer registers a `SessionStart` hook or calls `sce hooks session-model`. Rust handles extraction, validation, and persistence without a TypeScript intermediary; the former `config/.claude/plugins/sce-agent-trace.ts` Bun runtime was removed in T07 of the `claude-rust-diff-trace` plan. The Rust hook validates required fields, uses only direct payload `model_id` and `tool_version` (no longer resolves from `session_models`), and persists tool-prefixed `session_id` values (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi), `model_id`, `tool_name`, and nullable `tool_version` into `diff_traces` through AgentTraceDb. Bash-policy now delegates OpenCode enforcement to the Rust `sce policy bash` command: the generated OpenCode plugin at `config/.opencode/plugins/sce-bash-policy.ts` is a thin wrapper that calls `sce policy bash --input normalized --output json` via `spawnSync` and throws on deny decisions; it no longer contains independent TypeScript policy logic. The former `bash-policy/runtime.ts` TypeScript runtime has been removed. Preset... Claude bash-policy enforcement is also generated through `.claude/settings.json` as a `PreToolUse` `Bash` command hook running `sce policy bash`, so Claude and OpenCode both delegate to the Rust policy evaluator without a Claude TypeScript runtime. Pi bash-policy enforcement is delegated the same way through a project-local Pi extension (`config/lib/pi-plugin/sce-pi-extension.ts`, emitted to `config/.pi/extensions/sce/index.ts`) whose `tool_call` handler blocks denied bash commands via `sce policy bash` and fails open when the policy check cannot run (see `context/sce/pi-extension-runtime.md`). Local database bootstrap is now owned by `LocalDbLifecycle::setup` and `AgentTraceDbLifecycle::setup` aggregated by the setup command. Agent Trace setup creates/reuses the current checkout ID for diagnostics and initializes the repository-scoped `/sce/repos//agent-trace.db` with the repository schema; hook runtime lazily creates or upgrades that repository DB when setup has not run or schema metadata is incomplete. Doctor validates the repository-scoped DB path/health and can bootstrap missing parent directories; outside a Git repository it reports an actionable "requires a Git repository" diagnostic instead of probing a sentinel path. The `sce trace` group operates only on repository-scoped DBs for list/status/status-all/shell UX; the checkout-scoped `--legacy` surface was removed by the `retire-legacy-agent-trace-db` plan (see `context/decisions/2026-07-17-retire-legacy-agent-trace-db.md`). Wiring a user-invocable `sce sync` command is deferred to `0.4.0`. -The repository-root flake (`flake.nix`) applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, and builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline. One deterministic pre-Cargo Nix derivation evaluates the canonical Pkl/plugin inputs twice, inventories the payload and inputs, and supplies the same validated `SCE_CLI_GENERATED_INPUT_DIR` store path to native, release, test, and Clippy Cargo derivations. Pkl is absent from those Cargo environments; dependency-only and format derivations do not receive the handoff, so canonical generation changes invalidate compiling outputs without invalidating dependency artifacts or formatting. `cli-tests`, `cli-clippy`, and `cli-fmt` remain Crane-backed check derivations. +The repository-root flake (`flake.nix`) applies a Rust overlay-backed stable toolchain pinned to `1.95.0` (with `rustfmt` and `clippy`), reads package/check version from the repo-root `.version` file, and builds `packages.sce` through a Crane `buildDepsOnly` + `buildPackage` pipeline. One deterministic pre-Cargo Nix derivation invokes the shared generated-input producer and supplies its validated `SCE_CLI_GENERATED_INPUT_DIR` store path to native, release, test, and Clippy Cargo derivations. Pkl is absent from those Cargo environments; dependency-only and format derivations do not receive the handoff, so canonical generation changes invalidate compiling outputs without invalidating dependency artifacts or formatting. `cli-tests`, `cli-clippy`, and `cli-fmt` remain Crane-backed check derivations. The root flake splits native and release outputs: `packages.sce` and `packages.default` build the **native** development binary (`scePackage`), while `packages.sce-release` builds the release binary (`sceReleasePackage`: static musl on Linux, native on Darwin). So `nix build .#sce` / `.#default`, `nix run . -- --help`, `nix run .#sce -- --help`, and `nix profile install github:crocoder-dev/shared-context-engineering` target the native binary, and `nix build .#sce-release` / `nix run .#sce-release -- ...` (plus `nix run .#release-artifacts`, which builds `.#sce-release`) target the release binary. On Linux the native and release outputs are distinct store paths, and the release output passes the native portability audit. `packages..ci-checks` is the explicit long-running validation tier: `nix build .#ci-checks` builds the `.#sce-release` package and, on Linux, audits the real release binary for forbidden `/nix/store/` references, so the expensive work stays out of `nix flake check` (which never builds `.#sce-release`). Git-commit embedding is **release-only**: `SCE_GIT_COMMIT` is injected via a `releaseCommitArgs` fragment applied only to the release derivations (`scePackageMusl` on Linux, `sceReleasePackageNative` on Darwin), not to `commonCargoArgs`. So native `.#sce`/`.#default` and every `nix flake check` derivation (`cli-tests`, `cli-clippy`, `cli-fmt`) build without the commit in their inputs and stay cache-reusable across commits (native `sce version` reports `unknown`), while `.#sce-release` still reports the real commit via `sce version`. `cli/build.rs` `emit_git_commit` emits `SCE_GIT_COMMIT` only when the env var is explicitly set — no `git rev-parse` fallback and no `.git/HEAD`/`.git/packed-refs` rerun watches. On Darwin the release now uses a distinct native-toolchain derivation (native toolchain + commit), so it diverges from `.#sce` to carry the commit while native stays commit-independent. The default development shell is slimmed for fast iteration: `devShells.default` no longer includes `scePackage` or `tursoPackage`, so `nix develop` compiles neither the CLI package nor the Turso CLI — it provides only the Rust toolchain and JS/pkl tooling for `cargo`/`biome`/`pkl` work. Turso stays available as `packages..turso` and through a new opt-in `devShells..database` shell (default tools + `tursoPackage`), entered via `nix develop .#database`. Both shells share `defaultDevShellPackages`/`defaultDevShellHook` `let` bindings so they cannot drift. @@ -55,7 +55,7 @@ The downstream publish-stage implementation is now complete for both registries: The repository root now also owns the canonical Biome contract for the current JavaScript tooling slice: `biome.json` scopes formatting/linting to `npm/` and the shared `config/lib/` plugin package root while excluding package-local `node_modules/`, and the root Nix dev shell provides the `biome` binary so contributors do not need a host-installed formatter/linter for those areas. Flatpak validation/build orchestration is reduced to a minimal app surface: Linux flake apps expose the umbrella `sce-flatpak` (`nix run .#sce-flatpak -- ` for `validate`, `prepare-local-manifest`, etc.) plus `release-flatpak-package`, `release-flatpak-bundle`, and the `regenerate-flatpak-manifest` / `regenerate-cargo-sources` helpers; the previously separate `flatpak-validate`, `flatpak-local-manifest`, and `flatpak-build` wrapper apps are removed. Default `nix flake check` keeps the lightweight Nix-built static/AppStream validator plus the parity checks (`flatpak-manifest-parity`, `cargo-sources-parity`) and does not run a network-heavy Flatpak build. The former standalone install-channel integration runner and `install-channel-integration-tests` flake app are not active current-state surfaces. Shared Context Plan and Shared Context Code remain separate OpenCode routing roles: the generated Plan agent routes only to `/change-to-plan`, while the generated Code agent routes to `/next-task`, `/validate`, and `/commit`. Workflow behavior lives in the four workflow entrypoints and their four skill packages rather than in agent bodies. `config/pkl/base/workflow-catalog.pkl` assigns each workflow to its role, and OpenCode command routing plus each agent's `skill:` permission allowlist derive from those records: `sce-change-to-plan` for Plan; `sce-next-task`, `sce-validate`, and `sce-commit` for Code. -The canonical workflow definitions remain phase-decomposed as authoring source: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. No target generates those phase modules as packages. All three consume them as inputs to the shared `workflow-composite.pkl` renderer, which composes each workflow into one skill package. +The canonical workflow definitions remain phase-decomposed as authoring source: `/change-to-plan` sequences `sce-context-load` then `sce-plan-authoring`; `/next-task` sequences `sce-plan-review`, `sce-task-execution`, and `sce-task-context-sync`; `/validate` sequences `sce-validation` then `sce-plan-context-sync`; `/commit` delegates staged-diff analysis and message generation to `sce-atomic-commit`. No target generates those phase modules as packages. All three consume them as inputs to the shared `workflow-composite.pkl` renderer, which composes each workflow into one skill package. Every workflow supplies typed package/composite render values for frontmatter, bodies, semantic references, phases, persisted-document formats where applicable, and output references; the composite renderer performs no prose-wide internalization or frontmatter stripping. Every target preserves the same gates and lifecycle semantics through four renderer-composed workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. Each thin command or Pi prompt invokes exactly one corresponding skill, and OpenCode command frontmatter names that single skill as both `entry-skill` and the whole `skills` chain. Each package contains only `SKILL.md`, which owns all canonical phase behavior and internal status branching, plus `references/output.md`, which is the sole definition of that workflow's human-visible gates and terminal Markdown. No target emits phase-skill packages or inter-skill machine contracts; phase statuses stay internal to one skill invocation. Context sync uses an important-change gate: cross-cutting/policy/architecture/terminology changes require root shared-file edits, while localized tasks run verify-only root checks without default churn. OpenCode and Claude no longer generate commit or handover commands or legacy bootstrap/commit/handover/context-sync skills. OpenCode retains only thin routing agents, while Claude emits no agents. The superseded grouped Markdown catalog and automated OpenCode profile have been removed from Pkl ownership and generated outputs. @@ -70,7 +70,7 @@ The setup command parser/dispatch now also supports composable setup+hooks runs ## Repository model -- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package model in `workflow-content.pkl`; task and plan context-sync packages are instantiated from one role-parameterized shared-fragment source in `workflow-context-sync.pkl`. Keep command slug, skill slug, title, description, argument hint, OpenCode role, and Claude allowed tools in the typed `workflow-catalog.pkl`. OpenCode, Claude, and Pi all compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer, which is parameterized only by the extra frontmatter each target supports. +- Author the four SCE workflows in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl` using the self-contained package and structured-rendering model in `workflow-content.pkl`; all four render package and composite forms directly from typed semantic values. `workflow-context-sync.pkl` renders task and plan context-sync skills from explicit role data ordered as named frontmatter, purpose, input, workflow, boundaries, and completion sections, renders their reports through named introduction, status-variant, and rules sections driven by a typed synchronization-report role, and exposes both roles as mode-aware structured phases for their owning workflow compositions. Keep command slug, skill slug, title, description, argument hint, OpenCode role, and Claude allowed tools in the typed `workflow-catalog.pkl`. OpenCode, Claude, and Pi all compose each full workflow into one skill and one `references/output.md` through the shared `workflow-composite.pkl` renderer, which is parameterized only by the extra frontmatter each target supports. - Apply target-specific metadata/rendering in `config/pkl/renderers/`. - Use `config/pkl/generate.pkl` to emit the logical `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, and SCE schema layouts only under temporary generation roots, Cargo `OUT_DIR`, or packaging fallbacks. - Treat generated outputs as ephemeral build/package artifacts, never repository editing surfaces. diff --git a/context/patterns.md b/context/patterns.md index 4d9d5604..2a7397c2 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -49,20 +49,20 @@ ## Pkl renderer layering -- Keep the four target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with package primitives in `workflow-content.pkl` and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. +- Keep the four target-agnostic workflow packages in `config/pkl/base/workflow-{change-to-plan,next-task,validate,commit}.pkl`, with package constructors and typed package/composite frontmatter, body, semantic-reference, document, and composite-source primitives in `workflow-content.pkl`, and shared task/plan synchronization policy in `workflow-context-sync.pkl`. Render context-sync `SKILL.md` content from explicit role data in named frontmatter, purpose, input, workflow, boundaries, and completion order, and render its report introduction, synced, no-context-change, blocked, and rules sections from a typed report role. Do not use numbered fragments or positional role/common interleaving for either document. Canonical workflow modules must consume the shared constructors rather than defining local equivalents. Do not reintroduce the removed grouped shared-content catalog or automated-profile variants. - Declare the four workflows' command slug, skill slug, title, description, argument hint, OpenCode routing role, and Claude allowed tools exactly once in the typed `config/pkl/base/workflow-catalog.pkl`. Composite, target-routing, permission, and coverage consumers must iterate or look up those records rather than maintain parallel four-workflow matrices. - Keep cross-target generated-config primitives in focused base modules under `config/pkl/base/` and re-export them through `config/pkl/renderers/common.pkl` when multiple renderers need the same contract. - Model workflow skills as self-contained packages with deterministic package-relative document paths, including nested `references/` files. Shared Pkl skeletons may instantiate multiple skills, but every rendered skill must receive complete local documents and must not depend on a sibling skill package. - Use the project-root `.pi/` workflows as the behavioral baseline for canonical workflow packages; do not use generated target Markdown as an authoring source. - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. -- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Duplicating the internalization substitution tables per target would guarantee drift between targets whose composed text is meant to be identical. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. +- Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Every canonical workflow must choose package-vs-composite wording through typed semantic references before Markdown assembly, not by stripping frontmatter or post-processing prose. Require a structured composite source for each workflow and do not reintroduce a legacy rewrite path. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. - Compose each canonical workflow into one workflow-level skill package for every generated target; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. The canonical phase packages under `config/pkl/base/` remain authoring inputs to that composition, not a generated output surface for any target. - Keep shared renderer document and plugin-registration contracts in `config/pkl/renderers/common.pkl`; workflow identity metadata belongs in the typed workflow catalog rather than renderer-local description or routing maps. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi needs no metadata module because it adds no target-specific frontmatter. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: catalog-derived `agent`, `entry-skill`, and a `skills` chain naming that command's single workflow skill. Derive agent permission allowlists from the same catalog role assignments. - Keep `config/pkl/renderers/metadata-coverage-check.pkl` as a fail-fast exact-inventory guard deriving command slugs, skill entrypoints, and package-local workflow paths from the typed catalog, while independently retaining the expected OpenCode agent inventory and per-target one-to-one command-to-workflow-skill route assertions; run it whenever workflow documents or target metadata change. - Keep `config/pkl/renderers/generation-contract-check.pkl` independent of `generate.pkl` output assembly when deriving expected paths: build the exact target paths from renderer document inventories, name retained non-workflow assets explicitly, compare against all `output.files`, and reject stale phase-skill slugs or package-local reference tokens in generated workflow documents. Preserve controlled negative fixtures for extra paths, missing paths, and forbidden references. -- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Composition is the exception: a collapsed target's renderer may transform canonical command and phase documents into one complete workflow `SKILL.md`, provided every canonical gate, branch, write, and continuation retains exactly one owner in that skill. When a change collapses one target, the targets already collapsed must keep byte-identical output; verify by generating into temp roots before and after and diffing their subtrees. +- Workflow renderers may extend canonical frontmatter only with target-supported metadata, must preserve behavior, and append only the required final newline at the output mapping. Structured composition embeds frontmatter fields without parsing markers and renders semantic package/composite differences at their source, while preserving one owner for every canonical gate, branch, write, and continuation. Migrate one workflow at a time and compare its OpenCode, Claude, and Pi paths against a retained pre-task root; the complete generated payload must remain byte-identical as an additional regression guard. - Every target's commands (Pi: prompts) must stay thin and invoke exactly one corresponding workflow skill (`sce-change-to-plan`, `sce-next-task`, `sce-validate`, or `sce-commit`). They must not sequence phase skills. The workflow skill executes embedded phases directly, keeps phase statuses as internal state, and never invokes another SCE skill or sibling package. - A workflow package contains exactly two files: `SKILL.md` and `references/output.md`. Put operational phase instructions and persisted-file templates in `SKILL.md`; put every and only human-visible gate, report, and terminal response layout in `output.md`. Wait points such as bootstrap, clarification, revision, implementation approval, and failed-validation repair remain real same-session turn boundaries owned by the composite skill. - Keep the Markdown renderer contract in `config/pkl/renderers/common.pkl` limited to deterministic `frontmatter + body` assembly without injected generated-file marker text. @@ -79,7 +79,7 @@ - Use `config/pkl/generate.pkl` as the single generation module for authored config outputs. Flatten self-contained workflow skill documents as `{skill slug}/{package-relative path}` so nested references are emitted deterministically without sibling-package dependencies. - Use `config/pkl/README.md` as the contributor-facing runbook for prerequisites, ownership boundaries, regeneration steps, and troubleshooting. - Run multi-file generation only into an explicit temporary output root, for example `nix run .#pkl-generate -- "$(mktemp -d)"`; never evaluate with `-m .`. -- Run ephemeral generation validation through `nix run .#pkl-check-generated`; it wraps the dev-shell script, rejects committed target/schema/mirror outputs, evaluates exact metadata plus the complete 46-path artifact/reference contract and its negative fixtures, generates twice into temporary directories, and compares sorted SHA-256 inventories while requiring all supported target roots. +- Run ephemeral generation validation through `nix run .#pkl-check-generated`; it wraps the dev-shell script, rejects committed target/schema/mirror outputs, evaluates exact metadata plus the complete 46-path artifact/reference contract and its negative fixtures, requires all supported target roots, and delegates canonical input discovery, two-pass generation, and inventories to `scripts/produce-cli-generated-input.sh`. - Keep this contract anchored to the root `nix flake check` `pkl-generated` derivation. Removed target paths are forbidden repository artifacts even though the same path names remain valid inside temporary payload roots. - Treat `nix run .#pkl-check-generated` and `nix flake check` as the lightweight post-task verification baseline and run both after each completed task. - Keep `output.files` limited to payload-relative paths (`config/.opencode/{agent,command,skills,lib,plugins,opencode.json}`, `config/.claude/{commands,skills,hooks,settings.json}` with no Claude agents, `config/.pi/{prompts,skills,extensions}`, and the generated schema). Do not emit `config/automated/.opencode`. @@ -117,7 +117,7 @@ - For interactive setup flows, isolate prompt handling behind a service-layer prompter seam so selection mapping and cancellation behavior can be tested without a live TTY. - When setup or path-catalog modules grow dense, extract focused internal support seams (for example install-flow, prompt-flow, or root-resolution helpers) before adding new behavior so orchestration files stay navigable without changing command contracts. - Treat setup prompt cancellation/interrupt as a non-destructive exit path with explicit user messaging (no file mutations and no partial side effects). -- For repository setup-asset build prep, route build, run, targeted-test, Clippy, and local-install Cargo workflows through `scripts/run-cli-cargo.sh`. The wrapper evaluates `config/pkl/generate.pkl` twice before Cargo into a fresh temporary generated-input directory, rejects nondeterminism, records exact `SHA256SUMS` and canonical-input `INPUTS.SHA256SUMS` inventories, passes it through `SCE_CLI_GENERATED_INPUT_DIR`, and cleans up after Cargo exits. Keep `cli/build.rs` free of Pkl subprocesses: it validates the handoff, copies it into Cargo `OUT_DIR/pkl-generated`, stages non-Pkl hook/schema inputs under `OUT_DIR/static`, and generates the setup manifest in `OUT_DIR`; production Rust includes must not point back into `config/`, `cli/assets/`, or another source-tree generated mirror. +- For repository setup-asset build prep, declare canonical generator inputs in `config/pkl/generator-inputs.txt` and route input discovery, two-pass Pkl evaluation, determinism comparison, payload/input inventory creation, in-flight input checks, atomic publication, and private staging cleanup through `scripts/produce-cli-generated-input.sh`. The Cargo wrapper, generated-output check, package-fallback helper, and Nix `cliGeneratedInput` derivation must consume that producer rather than implement those mechanics independently. Keep each consumer's domain checks separate: the generated-output check owns metadata/contract/negative/path assertions; packaging owns static hook/schema/migration staging and the combined Pkl-plus-static checksum inventory; Nix owns declarative producer/input source selection and pre-Cargo handoff wiring. Route build, run, targeted-test, Clippy, and local-install Cargo workflows through `scripts/run-cli-cargo.sh`, which passes the producer handoff through `SCE_CLI_GENERATED_INPUT_DIR` and owns cleanup around Cargo. Keep `cli/build.rs` free of Pkl subprocesses and source-tree generated mirrors. - For CLI database migration prep, keep SQL files under immediate `cli/migrations//` directories named `NNN_description.sql`; `cli/build.rs` stages those files under `OUT_DIR/static/migrations`, sorts by the numeric prefix before `_`, and writes deterministic `OUT_DIR/generated_migrations.rs` constants with `include_str!` references for service `DbSpec` consumers. - For setup install execution, write selected embedded assets into a per-target staging directory first, then remove the existing target and swap staged content into place; on swap failure, clean temporary staging paths and return deterministic recovery guidance (recover from version control). No backup artifacts are created. - For required-hook setup execution, resolve repository root and effective hooks directory from git (`rev-parse --show-toplevel`, `rev-parse --git-path hooks`), then apply deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`) with staged writes, executable-bit enforcement, and remove-and-replace behavior that removes existing hooks before swapping staged content. @@ -151,12 +151,12 @@ - Keep crate-local onboarding docs in `cli/README.md` and sanity-check command examples against actual `sce` output whenever command messaging changes. - Keep Rust verification in flake checks under stable named derivations re-exported by the root flake: `checks..cli-tests`, `checks..cli-clippy`, `checks..cli-fmt`, and `checks..workflow-actionlint`. - Keep cheap flake-check sources as narrow as their behavior allows: formatting checks should not depend on generated payloads, and ephemeral/static checks should copy only the canonical inputs and forbidden paths they inspect. -- Keep Rust package/check sources as narrow as behavior allows: one deterministic pre-Cargo Nix derivation receives canonical Pkl and referenced plugin/extension sources, evaluates twice, inventories the result, and passes one validated generated-input store path to every Crane derivation that compiles the CLI (native, release, test, and Clippy). Keep Pkl out of those Cargo environments, and do not attach the handoff to dependency-only or formatting derivations so generated-input changes preserve dependency caches and formatting independence. Neither boundary may include committed generated target trees. +- Keep Rust package/check sources as narrow as behavior allows: one deterministic pre-Cargo Nix derivation receives the shared generated-input producer plus its canonical Pkl and referenced plugin/extension sources, invokes that producer once, and passes its validated generated-input store path to every Crane derivation that compiles the CLI (native, release, test, and Clippy). Keep Pkl out of those Cargo environments, and do not attach the handoff to dependency-only or formatting derivations so generated-input changes preserve dependency caches and formatting independence. Neither boundary may include committed generated target trees. - In `flake.nix`, select the Rust toolchain via an explicit Rust overlay (`rust-overlay`) and thread that toolchain through Crane package/check derivations so CLI builds and checks do not rely on implicit nixpkgs Rust defaults. - For installable CLI surfaces in the root flake, expose an explicit named package plus default alias (`packages.sce` and `packages.default = packages.sce`, the **native** development package) and pair it with a runnable app output (`apps.sce`) that points to the packaged binary path; keep the static-musl release binary a distinct output (`packages.sce-release`) rather than folding it into the default package. - For root-flake CLI release metadata, source the package/check version from repo-root `.version` and trim it at eval time so packaged outputs stay aligned without hardcoded semver strings in `flake.nix`. - For Cargo CLI distribution, keep crate metadata publication-ready and document the supported Cargo install paths in `cli/README.md`: crates.io via `cargo install shared-context-engineering --locked`, and local checkout via `./scripts/run-cli-cargo.sh install --path cli --locked`. Do not advertise direct `cargo install --git`; it cannot run the required pre-Cargo generation boundary. Verify at least the repo-local build/check path through the Nix-managed validation baseline. -- Keep Pkl-free fallback payloads packaging-only and Git-ignored: generate them from canonical Pkl in a temporary clean workspace or manifest-support directory, stage all required static inputs, reject nondeterministic generation, and include an exact checksum inventory. Crates.io embeds this payload in the crate; Flatpak stages it as a manifest `type: dir` source before entering the Pkl-free sandbox. +- Keep Pkl-free fallback payloads packaging-only and Git-ignored: obtain their Pkl tree and checksums from the canonical generated-input producer, move that validated tree into a temporary staged fallback, add all required static inputs, and append static checksums to the exact combined inventory without rerunning Pkl determinism logic. Do not publish the repository-only `INPUTS.SHA256SUMS` in the fallback. Crates.io embeds this payload in the crate; Flatpak stages it as a manifest `type: dir` source before entering the Pkl-free sandbox. - In `cli/build.rs`, require and validate `SCE_CLI_GENERATED_INPUT_DIR` whenever repository canonical sources exist; use the validated package fallback only when those sources are absent, copy either input mode into the same `OUT_DIR` shape, and fail actionably rather than silently switching repository builds to the package fallback. - Anchor Cargo `package.include` patterns at the crate root so similarly named files in obsolete source trees cannot enter the `.crate`; inspect `cargo package --list` and build the unpacked archive with Pkl absent when changing the fallback inventory. diff --git a/context/plans/refactor-pkl-composition-and-generation.md b/context/plans/refactor-pkl-composition-and-generation.md new file mode 100644 index 00000000..22c50a53 --- /dev/null +++ b/context/plans/refactor-pkl-composition-and-generation.md @@ -0,0 +1,216 @@ +# Plan: refactor-pkl-composition-and-generation + +## Change summary + +Complete the next structural Pkl improvements after `strengthen-pkl-structure-foundation`: move repeated workflow document/package constructors into the shared model, replace the positionally coupled numbered context-sync fragments with named semantic sections, replace composite workflow prose rewriting with structured rendering one workflow at a time, and centralize deterministic generation plus inventory creation behind one producer contract. + +The refactor preserves the accepted cross-target architecture and the exact 46-file generated payload. Canonical workflow semantics, target frontmatter, human-visible output, plugin and extension sources, schema behavior, Cargo `OUT_DIR` handoff, and packaging fallbacks must remain byte-compatible. The work changes how canonical content is represented and produced, not what users receive. + +## Acceptance criteria + +- [x] AC1: Workflow document construction and package-document mapping have one shared implementation, and no canonical workflow module retains a local `makeDocument` or `packageDocuments` equivalent. + - Validate: evaluate every `config/pkl/base/workflow-*.pkl` module and search those modules for duplicate constructor definitions. +- [x] AC2: Task and plan context-sync documents are assembled from named semantic sections and role data rather than numbered common/task/plan fragments or manually interleaved positional lists, while their composed generated output remains byte-identical. + - Validate: inspect `workflow-context-sync.pkl` for named sections and absence of numbered fragment identifiers; compare generated `sce-next-task` and `sce-validate` package trees before and after the refactor. +- [x] AC3: `workflow-composite.pkl` renders commands, phases, internal persisted-document formats, and output references from structured source values without `stripFrontmatterMarkers`, `internalize`, `internalizePhase`, or prose-wide replacement chains. + - Validate: focused source search finds none of the removed helpers or their rewrite tables; direct renderer checks and the forbidden-reference generation contract pass. +- [x] AC4: Change-to-plan, next-task, validate, and commit are migrated independently, and each migration preserves that workflow's generated OpenCode, Claude, and Pi command/prompt plus two-file package bytes. + - Validate: for each workflow migration, diff its paths across all three target trees against a retained pre-task temporary baseline. +- [x] AC5: One repository-owned producer contract performs Pkl evaluation, two-pass determinism comparison, generated payload inventory creation, and canonical-input inventory creation for repository Cargo builds, generated-output checks, packaging fallbacks, and the Nix generated-input derivation. + - Validate: inspect all four consumers; focused search finds no independent implementation of the producer mechanics outside the producer and its tests. +- [x] AC6: The producer rejects nondeterministic generation and missing or stale canonical inputs, emits the existing `pkl-generated/`, `SHA256SUMS`, and `INPUTS.SHA256SUMS` handoff shape where required, and cleans temporary state on success, failure, and handled signals. + - Validate: run producer/wrapper tests covering success, generation drift, input mutation, subprocess failure, and cleanup; validate the resulting handoff through `cli/build.rs` in the normal repository check path. +- [x] AC7: The finished generator emits exactly the same 46 paths and bytes as the pre-plan baseline, and all repository checks pass. + - Validate: generate complete before/after temporary roots and run `diff -r`; run the full validation commands below. + +### Full validation + +- `bash scripts/test-run-cli-cargo.sh` +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- Update `context/overview.md`, `context/architecture.md`, and `context/patterns.md` to describe shared workflow constructors, named context-sync sections, structured composite rendering, and the single generation producer contract. +- Update `context/glossary.md` with structured workflow rendering and generated-input producer terminology if those names become canonical. +- Update `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md` through a superseding decision if replacing prose internalization changes rationale that should remain durable. +- Update `context/decisions/2026-07-27-ephemeral-pkl-build-generation.md` through a superseding decision if the producer contract materially changes its ownership description. +- Update `context/context-map.md` only when a new decision or focused durable context document is added. + +## Constraints and non-goals + +- **In scope:** Shared Pkl workflow constructors; `workflow-context-sync.pkl`; structured workflow content/rendering primitives; the four canonical workflow modules and shared composite renderer; generator input declaration; deterministic Pkl producer scripts and tests; `check-generated.sh`, Cargo wrapper, packaging fallback helper, and Nix generated-input integration; directly affected documentation and durable context. +- **Out of scope:** Workflow behavior or wording changes; target inventory changes; new targets or workflows; plugin, Pi extension, settings, policy, schema, setup, or CLI runtime behavior; changing the published crate fallback shape; replacing vendored Pkl dependencies; broad Pkl directory reorganization. +- **Constraints:** Preserve all generated bytes and exact paths; migrate one workflow at a time; keep intermediate commits evaluable with already-migrated workflows using structured rendering and remaining workflows using a narrowly isolated transitional legacy path; remove that path after commit migration; run Pkl and Cargo validation through Nix-owned repository entrypoints. +- **Non-goal:** Build a general Markdown parser or a templating framework for arbitrary documents. Structured rendering needs only semantic constructs used by the four current workflows. + +## Assumptions + +- `context/plans/strengthen-pkl-structure-foundation.md` is the implemented baseline, so this plan can consume `workflow-catalog.pkl` and the exact generation-contract checks it introduced. +- Byte identity applies to the complete generated payload. Canonical source formatting may change substantially when content becomes structured. +- Structured rendering will represent semantic differences—frontmatter, phase references, internal-state contracts, output references, and directive vocabulary—as typed values or rendering functions before Markdown assembly; renaming the existing replacement helpers or replacing prose with symbolic-string substitution would not satisfy the request. +- The producer may leave Nix fileset construction declarative, but the input manifest and generation/inventory algorithm must have one machine-readable owner that shell and Nix consumers share rather than parallel hand-maintained implementations. + +## Task stack + +- [x] T01: `Move workflow constructors into the shared Pkl model` (status:done) + - Task ID: T01 + - Goal: Give `workflow-content.pkl` canonical helpers for creating documents and deterministic package-document mappings, then remove the four local helper pairs. + - Boundaries (in/out of scope): In — `workflow-content.pkl` helper API and constructor call-site updates in the four canonical workflow modules. Out — document text, package inventory, context-sync structure, composite rendering, and generation scripts. + - Dependencies: none + - Done when: All workflow modules consume the shared helpers, no local equivalent remains, direct module evaluations pass, and the complete generated payload matches a pre-task baseline. + - Verification notes (commands or checks): evaluate `workflow-content.pkl` and each `workflow-{change-to-plan,next-task,validate,commit}.pkl`; focused search for `local makeDocument|local packageDocuments`; generate and `diff -r` temporary payloads; run `nix run .#pkl-check-generated`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/base/workflow-content.pkl`, `config/pkl/base/workflow-change-to-plan.pkl`, `config/pkl/base/workflow-next-task.pkl`, `config/pkl/base/workflow-validate.pkl`, `config/pkl/base/workflow-commit.pkl` + - Evidence: Direct Pkl evaluation passed for the shared model and all four workflow modules; focused search found no local constructor definitions; `diff -r` reported no differences between complete pre-task and post-task generated payloads; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`. + - Notes: Shared helpers are hidden module members so direct model evaluation remains renderable while imported workflow modules can consume the canonical implementation. + +- [x] T02: `Replace numbered context-sync skill fragments with named sections` (status:done) + - Task ID: T02 + - Goal: Rebuild task/plan context-sync `SKILL.md` assembly around named semantic skill sections and role-owned data instead of numbered common and role fragment triples. + - Boundaries (in/out of scope): In — context-sync skill frontmatter, purpose, inputs, workflow, boundaries, and completion sections plus shared role data needed to render them. Out — sync report rendering, workflow semantics, composite renderer changes, and generated wording. + - Dependencies: T01 + - Done when: Skill assembly is ordered by named semantic sections, task/plan differences are explicit role fields or section renderers, numbered skill fragment identifiers and positional interleaving are gone, and both generated workflow package subtrees are byte-identical. + - Verification notes (commands or checks): evaluate `workflow-context-sync.pkl`; compare extracted task and plan skill text before/after; diff generated `sce-next-task` and `sce-validate` packages across all targets; run `nix run .#pkl-check-generated`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/base/workflow-context-sync.pkl`, `context/overview.md`, `context/architecture.md`, `context/patterns.md` + - Evidence: Direct Pkl JSON evaluation passed; extracted task and plan `SKILL.md` bytes matched the supplied direct-module baseline; recursive diffs for `sce-next-task` and `sce-validate` packages matched the supplied OpenCode, Claude, and Pi baseline subtrees; focused search found no numbered skill-fragment identifiers or positional skill assembly while confirming numbered report fragments remain; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: Context-sync skills now render explicit role-owned frontmatter, purpose, input, workflow, boundaries, and completion sections in semantic order. Report assembly and composite rendering remain unchanged for T03 and later tasks. + +- [x] T03: `Replace numbered context-sync report fragments with named sections` (status:done) + - Task ID: T03 + - Goal: Complete the context-sync refactor by expressing report layouts as named semantic sections driven by the same role model. + - Boundaries (in/out of scope): In — task/plan sync report headings, status layouts, changed-context summaries, verification, and continuation sections; removal of obsolete numbered report fragments and manual interleaving lists. Out — report wording, output ownership, composite rendering, or changes to task/plan synchronization policy. + - Dependencies: T02 + - Done when: No numbered common/task/plan fragment identifier remains in `workflow-context-sync.pkl`, both complete packages evaluate from named sections, and generated `sce-next-task` and `sce-validate` output bytes are unchanged. + - Verification notes (commands or checks): focused search for numeric fragment naming and positional lists; direct Pkl evaluation; before/after extraction comparison for both sync reports; generated subtree diff; `nix run .#pkl-check-generated`. + - Completed: 2026-07-29 + - Files changed: `config/pkl/base/workflow-context-sync.pkl` + - Evidence: Direct Pkl JSON evaluation matched the retained pre-task module baseline byte-for-byte; focused search found no numbered common/task/plan report fragment identifiers, `reportFragments`, or positional newline assembly while confirming named introduction, synced, no-context-change, blocked, rules, and report renderers; recursive diffs for generated `sce-next-task` and `sce-validate` packages matched retained OpenCode, Claude, and Pi baseline subtrees; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: A typed `SyncReportRole` now carries lifecycle-specific report values while shared named renderers assemble each semantic report variant and rule section without numbered interleaving. + +- [x] T04: `Introduce structured rendering with change-to-plan` (status:done) + - Task ID: T04 + - Goal: Add the minimal structured document/rendering model and migrate change-to-plan so its composite command, phases, persisted plan template, and output references render directly without prose rewriting. + - Boundaries (in/out of scope): In — typed frontmatter/body/semantic-reference primitives, a transitional composite seam supporting structured and legacy workflows, `workflow-change-to-plan.pkl`, and the change-to-plan composite definition. Out — migration of next-task, validate, or commit; removal of the transitional legacy path; any generated wording change. + - Dependencies: T03 + - Done when: Change-to-plan uses only structured rendering, its three-target command/prompt and package paths are byte-identical, and the other workflows continue evaluating through one isolated legacy adapter. + - Verification notes (commands or checks): direct model/base/composite evaluations; focused check that change-to-plan does not pass through legacy internalization; diff only change-to-plan paths for OpenCode, Claude, and Pi against a retained baseline; run generation contract and `nix run .#pkl-check-generated`. + - Completed: 2026-07-30 + - Files changed: `config/pkl/base/workflow-content.pkl`, `config/pkl/base/workflow-change-to-plan.pkl`, `config/pkl/renderers/workflow-composite.pkl` + - Evidence: Direct Pkl evaluation passed for the shared model, change-to-plan base module, composite renderer, and all three target content renderers; the generation contract passed; focused source inspection confirmed change-to-plan supplies `structuredComposite` directly while next-task, validate, and commit alone use `legacyComposite`; a recursive diff of complete pre-task and post-task generated roots reported no differences; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: The shared model now distinguishes package and composite render modes with typed frontmatter, body, semantic-reference, structured-document, and composite-source values. Change-to-plan renders its command, internal phases, persisted plan template, and output references from those values without prose internalization; the transitional rewrite path is isolated behind `legacyComposite` for the three workflows scheduled in T05–T07. + +- [x] T05: `Migrate next-task to structured rendering` (status:done) + - Task ID: T05 + - Goal: Express next-task phase sequencing, state contracts, implementation gate references, and sync output composition through the structured renderer. + - Boundaries (in/out of scope): In — `workflow-next-task.pkl`, next-task composite assembly, and structured constructs proven necessary by this workflow. Out — validate and commit migration, context-sync policy changes, and user-visible text changes. + - Dependencies: T04 + - Done when: Next-task no longer uses the legacy internalization path, all next-task generated paths across three targets are byte-identical, and change-to-plan remains unchanged. + - Verification notes (commands or checks): direct focused evaluations; compare next-task target subtrees against the pre-task baseline and recheck change-to-plan; run generation contract and `nix run .#pkl-check-generated`. + - Completed: 2026-07-30 + - Files changed: `config/pkl/base/workflow-next-task.pkl`, `config/pkl/base/workflow-context-sync.pkl`, `config/pkl/renderers/workflow-composite.pkl` + - Evidence: Direct Pkl evaluation passed for the shared model, context-sync module, next-task module, composite renderer, all three target content renderers, and the generation contract; focused source inspection confirmed next-task supplies `structuredComposite` directly while only validate and commit use `legacyComposite`; a recursive diff of complete pre-task and post-task generated roots reported no differences, including explicit change-to-plan package regression diffs across OpenCode, Claude, and Pi; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: Next-task now renders its command, plan-review and task-execution phases, state-contract and implementation-gate references, task context-sync phase, and output references from mode-aware structured values. The shared context-sync model exposes the task role as a structured phase without changing package wording or policy; the transitional legacy path remains isolated to validate and commit for T06–T07. + +- [x] T06: `Migrate validate to structured rendering` (status:done) + - Task ID: T06 + - Goal: Express validation phases, failed-validation state, persisted validation-report format, plan-sync references, and output composition through the structured renderer. + - Boundaries (in/out of scope): In — `workflow-validate.pkl`, validate composite assembly, and narrowly required structured constructs. Out — commit migration, validation behavior changes, and plan context-sync policy changes. + - Dependencies: T05 + - Done when: Validate no longer uses legacy internalization, its generated paths are byte-identical across all targets, and previously migrated workflows remain unchanged. + - Verification notes (commands or checks): direct focused evaluations; validate subtree diff plus regression diffs for change-to-plan and next-task; run generation contract and `nix run .#pkl-check-generated`. + - Completed: 2026-07-30 + - Files changed: `config/pkl/base/workflow-validate.pkl`, `config/pkl/base/workflow-context-sync.pkl`, `config/pkl/renderers/workflow-composite.pkl` + - Evidence: Direct Pkl evaluation passed for the context-sync module, validate module, composite renderer, and all three target content renderers; the generation contract passed with exactly 46 artifact paths and fully internalized workflow references; focused source inspection confirmed validate supplies `structuredComposite` directly while commit alone uses `legacyComposite`; recursive complete-root and explicit validate, change-to-plan, and next-task diffs against the retained pre-task baseline reported no differences; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: Validate now renders its command, validation phase, failed-validation state, persisted plan-file validation report, plan context-sync phase, and output references from mode-aware structured values. The shared context-sync model exposes the plan role as a structured phase without changing package wording or policy; the transitional legacy path remains isolated to commit for T07. + +- [x] T07: `Migrate commit and remove prose internalization` (status:done) + - Task ID: T07 + - Goal: Migrate commit to structured rendering and delete the transitional prose-rewrite implementation once all four workflows render structurally. + - Boundaries (in/out of scope): In — `workflow-commit.pkl`, commit composite assembly, removal of `stripFrontmatterMarkers`, `internalize`, `internalizePhase`, rewrite tables, and the legacy adapter. Out — commit workflow semantics, commit-message style content, and unrelated renderer cleanup. + - Dependencies: T06 + - Done when: Every workflow is structurally rendered; no prose-wide internalization helper or replacement chain remains; all four workflow subtrees and the complete generated payload are byte-identical. + - Verification notes (commands or checks): focused search for removed helpers and rewrite strings; direct evaluation of all workflow modules and renderers; complete before/after generated-tree diff; generation contract; `nix run .#pkl-check-generated`. + - Completed: 2026-07-30 + - Files changed: `config/pkl/base/workflow-commit.pkl`, `config/pkl/renderers/workflow-composite.pkl` + - Evidence: Direct Pkl evaluation passed for the shared model, context-sync module, all four workflow modules, composite renderer, all three target content renderers, and the generation contract; focused source inspection found no `stripFrontmatterMarkers`, `internalize`, `internalizePhase`, `legacyComposite`, or prose rewrite chain outside vendored dependency code; a recursive diff of complete pre-task and post-task generated roots reported no differences; `nix run .#pkl-check-generated` passed with 46 files and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `git diff --check` passed. + - Notes: Commit now renders its command, atomic-commit phase, contract references, internal-state vocabulary, and message-style output from mode-aware structured values. Every composite workflow requires a structured source, so the nullable legacy seam and all renderer-wide prose rewriting have been removed. + +- [x] T08: `Create the canonical generated-input producer` (status:done) + - Task ID: T08 + - Goal: Introduce one tested producer that owns canonical input discovery, two-pass Pkl generation, determinism comparison, payload inventory, input inventory, and temporary-state cleanup, then make the Cargo wrapper consume it. + - Boundaries (in/out of scope): In — one machine-readable generator-input declaration, producer script/library, focused producer tests, and simplification of `scripts/run-cli-cargo.sh`. Out — `check-generated.sh`, packaging helper, Nix migration, `cli/build.rs` handoff shape, and generated content. + - Dependencies: none + - Done when: The producer creates the existing validated generated-input directory shape; `run-cli-cargo.sh` delegates generation/inventory work to it; focused tests cover deterministic success, drift, missing/input mutation, subprocess failure, and cleanup; wrapper behavior remains stable. + - Verification notes (commands or checks): run the new producer test suite and `bash scripts/test-run-cli-cargo.sh`; inspect one handoff's `pkl-generated/`, `SHA256SUMS`, and `INPUTS.SHA256SUMS`; run a narrow wrapper-driven CLI build through the documented Nix command if needed. + - Completed: 2026-07-30 + - Files changed: `config/pkl/generator-inputs.txt`, `scripts/produce-cli-generated-input.sh`, `scripts/test-produce-cli-generated-input.sh`, `scripts/run-cli-cargo.sh`, `scripts/test-run-cli-cargo.sh` + - Evidence: `bash scripts/test-produce-cli-generated-input.sh` passed deterministic success, generation drift, missing declared input, canonical input mutation, Pkl subprocess failure, and temporary cleanup cases; `bash scripts/test-run-cli-cargo.sh` passed argument forwarding, regeneration, refreshed inventories, Cargo status propagation, and wrapper cleanup; an inspected real producer handoff contained `pkl-generated/`, `SHA256SUMS` with 46 payload entries, and `INPUTS.SHA256SUMS` with 31 canonical input entries; `nix develop -c ./scripts/run-cli-cargo.sh build --manifest-path cli/Cargo.toml` completed successfully; `nix run .#pkl-check-generated` retained the exact 46-file payload and inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; Bash syntax checks and `git diff --check` passed. + - Notes: `config/pkl/generator-inputs.txt` is the machine-readable input owner. The producer snapshots its expanded inventory before generation, evaluates twice into private staging roots, rejects payload drift or in-flight input changes, emits the existing Cargo handoff shape atomically, and cleans staging through exit and handled-signal traps. The Cargo wrapper now owns only Cargo invocation plus its temporary handoff lifetime. + +- [x] T09: `Route checks and packaging through the producer` (status:done) + - Task ID: T09 + - Goal: Remove duplicate generation/inventory mechanics from the generated-output check and package-fallback preparation while preserving each consumer's domain-specific assertions and static-asset staging. + - Boundaries (in/out of scope): In — `config/pkl/check-generated.sh`, `scripts/prepare-cli-generated-assets.sh`, producer options needed by those callers, and their focused tests. Out — Nix derivation changes, package fallback layout changes, removal of generation-contract Pkl checks, and static hook/migration/schema ownership. + - Dependencies: T08 + - Done when: Both callers delegate canonical Pkl generation and inventories to the producer; `check-generated.sh` still runs metadata/contract/negative checks and forbidden-path assertions; packaging still adds static assets and emits its combined checksum inventory without reimplementing Pkl determinism. + - Verification notes (commands or checks): run producer and wrapper tests; `nix develop -c ./config/pkl/check-generated.sh`; prepare a temporary package fallback twice and compare it; `nix run .#pkl-check-generated`. + - Completed: 2026-07-30 + - Files changed: `config/pkl/check-generated.sh`, `scripts/prepare-cli-generated-assets.sh`, `scripts/test-check-generated.sh`, `scripts/test-prepare-cli-generated-assets.sh` + - Evidence: Producer, Cargo-wrapper, generated-output delegation, and package-fallback delegation tests passed; the generated-output check delegated one producer run while retaining metadata, contract, negative-fixture, required-path, and forbidden-path assertions; two real package fallbacks prepared through the producer were recursively identical and their combined inventories verified; `nix develop -c ./config/pkl/check-generated.sh` and `nix run .#pkl-check-generated` passed with 46 files and the unchanged inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; Bash syntax checks, focused duplicate-mechanics searches, and `git diff --check` passed. + - Notes: The generated-output check projects the producer-owned payload inventory to its established report path format without rehashing generated files. Packaging moves the producer-validated Pkl tree into the unchanged fallback layout, retains the producer's Pkl checksums, adds only static-asset checksums, and does not publish the repository-only canonical-input inventory. + +- [x] T10: `Route the Nix generated-input derivation through the producer` (status:done) + - Task ID: T10 + - Goal: Make `cliGeneratedInput` invoke the same producer and input declaration as shell consumers, removing the last independent two-pass generation and inventory implementation. + - Boundaries (in/out of scope): In — producer-compatible Nix source selection/runtime inputs, `cliGeneratedInput`, focused flake checks, and removal of superseded inline generation/inventory shell. Out — Crane package topology, Cargo dependency caching policy, release packaging behavior, and unrelated flake simplification. + - Dependencies: T09 + - Done when: Nix builds the same handoff through the shared producer; Pkl remains absent from Cargo derivations; dependency-only and format derivations remain independent of generated inputs; focused search finds no duplicate producer algorithm; the 46-file payload and complete repository checks remain unchanged. + - Verification notes (commands or checks): build the focused `cli-generated-input` and `pkl-generated` checks, inspect their handoff inventories, run duplicate-mechanics searches, compare generated output with the pre-plan baseline, then run `nix run .#pkl-check-generated` and `nix flake check`. + - Completed: 2026-07-30 + - Files changed: `flake.nix` + - Evidence: `cliGeneratedInput` now invokes `scripts/produce-cli-generated-input.sh` from a producer-compatible Nix source instead of implementing generation, comparison, and inventories inline; the `pkl-generated` check source includes the producer and patches its sandbox shebang. Focused `cli-generated-input` and `pkl-generated` builds passed; the Nix handoff contained 46 valid payload checksums and 31 valid canonical-input checksums; focused source search found no duplicate producer algorithm in `flake.nix`; `nix run .#pkl-check-generated` passed with the unchanged 46-file inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; `nix flake check` and `git diff --check` passed. + - Notes: The producer publishes to a writable derivation-local staging path before the validated handoff is moved to `$out`. Pkl remains confined to the pre-Cargo producer derivation, while `cargoDepsArgs` and `cli-fmt` remain independent of the generated-input handoff. + +## Open questions + +None. The request identifies four concrete refactors, the implemented foundation plan supplies their prerequisite catalog and contract checks, and existing decisions fix the required generated behavior and handoff boundaries. + +## Validation Report + +**Status:** validated +**Date:** 2026-07-30 + +### Commands run + +- `bash scripts/test-run-cli-cargo.sh` -> exit 0 (Cargo wrapper handoff, forwarding, status propagation, and cleanup tests passed) +- `nix run .#pkl-check-generated` -> exit 0 (46 generated files matched the canonical contract; inventory SHA-256 remained `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`) +- `nix flake check` -> exit 0 (all compatible-system flake checks passed) +- `bash scripts/test-produce-cli-generated-input.sh` -> exit 0 (determinism, drift, missing input, input mutation, subprocess failure, and cleanup cases passed) +- `bash scripts/test-check-generated.sh` -> exit 0 (generated-output check delegation tests passed) +- `bash scripts/test-prepare-cli-generated-assets.sh` -> exit 0 (package-fallback producer delegation tests passed) +- `nix develop -c sh -c 'for module in config/pkl/base/workflow-content.pkl config/pkl/base/workflow-context-sync.pkl config/pkl/base/workflow-change-to-plan.pkl config/pkl/base/workflow-next-task.pkl config/pkl/base/workflow-validate.pkl config/pkl/base/workflow-commit.pkl config/pkl/renderers/workflow-composite.pkl config/pkl/renderers/opencode-content.pkl config/pkl/renderers/claude-content.pkl config/pkl/renderers/pi-content.pkl config/pkl/renderers/generation-contract-check.pkl; do pkl eval -f json "$module" >/dev/null || exit 1; done'` -> exit 0 (shared models, all workflows, all target renderers, and the generation contract evaluated directly) +- Focused source inspections for local constructors, numbered context-sync fragments, prose-internalization helpers, and producer consumers -> exit 0 (only shared constructor definitions and expected call sites remain; forbidden helpers/fragments are absent; all four producer consumers delegate to the canonical script) + +### Scaffolding removed + +- None. + +### Success-criteria verification + +- [x] AC1: Shared workflow constructors -> `workflow-content.pkl` owns `makeDocument` and `packageDocuments`; direct evaluations passed and canonical workflow modules contain only shared-model call sites. +- [x] AC2: Named context-sync composition -> `SyncRole` and `SyncReportRole` provide named semantic sections; numbered fragment searches were empty and the unchanged generated inventory confirms byte preservation. +- [x] AC3: Structured composite rendering -> renderer inspection showed direct structured command, phase, persisted-document, and output rendering; forbidden internalization helpers are absent and direct renderer/contract evaluations passed. +- [x] AC4: Independent workflow migrations -> T04-T07 retain per-workflow three-target baseline diff evidence, and final generation retained the exact accepted 46-file inventory hash. +- [x] AC5: Single producer contract -> Cargo wrapper, generated-output check, packaging fallback, and Nix generated-input derivation all invoke `scripts/produce-cli-generated-input.sh`; inspection found no second producer algorithm. +- [x] AC6: Producer rejection and cleanup behavior -> focused producer and consumer tests passed all specified success, drift, mutation, failure, handoff-shape, and cleanup cases; the normal flake path accepted the handoff. +- [x] AC7: Exact payload and repository checks -> generated output remained 46 files with baseline inventory SHA-256 `e3b340b0daae030bbcead618514fe256e7f577eb9ee2a032eba7d6045e647777`; every full-validation command passed. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- None identified. diff --git a/context/sce/cli-cargo-distribution-contract.md b/context/sce/cli-cargo-distribution-contract.md index c39fcabc..e66d561a 100644 --- a/context/sce/cli-cargo-distribution-contract.md +++ b/context/sce/cli-cargo-distribution-contract.md @@ -8,9 +8,10 @@ This file captures the implemented Cargo distribution slice from `context/plans/ - `cli/Cargo.toml` keeps crates.io-facing metadata enabled for publication. - `cli/README.md` is the crate-facing install guidance source referenced by Cargo/crates.io surfaces. - Repository Cargo builds require a pre-Cargo generated-input directory through `SCE_CLI_GENERATED_INPUT_DIR`; `cli/build.rs` never invokes Pkl and does not consume `cli/assets/generated/` or the packaging fallback when canonical repository sources are present. -- The handoff contains `pkl-generated/`, `SHA256SUMS` for that exact payload, and `INPUTS.SHA256SUMS` for canonical `config/pkl` plus referenced `config/lib` inputs. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, then copies the validated payload into `OUT_DIR/pkl-generated`. -- `scripts/run-cli-cargo.sh` is the supported repository Cargo boundary. It generates canonical Pkl twice into a fresh temporary directory, rejects nondeterminism, writes both inventories, exports the handoff only for the requested Cargo process, forwards Cargo arguments unchanged, and removes the directory after success, failure, or a handled signal. Build, targeted-test, Clippy, run, and `cargo install --path cli` workflows use this wrapper rather than direct Cargo. -- Before packaging, `scripts/prepare-cli-generated-assets.sh` evaluates canonical Pkl twice, rejects nondeterministic output, stages generated targets plus hooks, schemas, and migrations under ignored `cli/package-fallback/`, and writes `SHA256SUMS` for the exact payload. +- The handoff contains `pkl-generated/`, `SHA256SUMS` for that exact payload, and `INPUTS.SHA256SUMS` for canonical inputs declared by `config/pkl/generator-inputs.txt`. `cli/build.rs` rejects missing, incomplete, modified, or stale handoffs, then copies the validated payload into `OUT_DIR/pkl-generated`. +- `scripts/produce-cli-generated-input.sh` is the canonical repository producer for that handoff. It expands the repository-relative input declaration, snapshots and inventories the resolved files, evaluates canonical Pkl twice in private staging roots, rejects generated-tree drift and inputs changed during generation, writes both inventories, publishes only the validated result, and cleans staging after success, failure, or handled signals. The Cargo wrapper, generated-output check, package-fallback preparation, and Nix `cliGeneratedInput` derivation all consume this contract. +- `scripts/run-cli-cargo.sh` is the supported repository Cargo boundary and a consumer of the producer. It creates a fresh temporary destination, delegates generation and inventory mechanics, exports the resulting handoff only for the requested Cargo process, forwards Cargo arguments unchanged, and removes the directory after success, failure, or a handled signal. Build, targeted-test, Clippy, run, and `cargo install --path cli` workflows use this wrapper rather than direct Cargo. +- Before packaging, `scripts/prepare-cli-generated-assets.sh` invokes the producer once, moves its validated `pkl-generated/` tree into the staged ignored `cli/package-fallback/`, retains the producer's Pkl checksum entries, stages hooks, schemas, and migrations, and appends checksums for those static files to the exact combined `SHA256SUMS`. It omits the repository-only `INPUTS.SHA256SUMS` from the published fallback and does not independently evaluate or compare Pkl output. - Published crates include only the packaging fallback, Rust sources, and crate metadata. In an unpacked crate, `cli/build.rs` validates the fallback inventory and copies it into the consumer's `OUT_DIR`; downstream Cargo builds do not require Pkl or parent repository paths. - Missing or changed fallback files fail the build with guidance to recreate the package through the preparation script. When canonical repository Pkl sources exist, `build.rs` requires the generated-input handoff and does not silently use the packaging fallback. diff --git a/context/sce/flake-build-performance.md b/context/sce/flake-build-performance.md index 75c204f7..2aba4190 100644 --- a/context/sce/flake-build-performance.md +++ b/context/sce/flake-build-performance.md @@ -21,13 +21,15 @@ Git-commit embedding is release-only. Native packages and normal CLI check derivations do not receive `SCE_GIT_COMMIT`; release packages do. Generated CLI assets cross a separate pre-Cargo boundary. One deterministic -`cliGeneratedInput` derivation evaluates the canonical Pkl model twice, rejects -nondeterminism, and records exact SHA-256 inventories for both the payload and -its canonical inputs. Native, release, test, and Clippy derivations all receive -the same output through `SCE_CLI_GENERATED_INPUT_DIR`; Pkl is unavailable inside -those Cargo derivations. Host and musl dependency-only derivations and -`cli-fmt` omit the handoff, so generated-input changes invalidate generation -and compiling outputs without rebuilding dependency artifacts or formatting. +`cliGeneratedInput` derivation invokes the repository's shared generated-input +producer from a declarative source containing the producer and canonical inputs. +The producer owns two-pass evaluation, nondeterminism rejection, and exact +SHA-256 inventories for both the payload and its canonical inputs. Native, +release, test, and Clippy derivations all receive the same output through +`SCE_CLI_GENERATED_INPUT_DIR`; Pkl is unavailable inside those Cargo derivations. +Host and musl dependency-only derivations and `cli-fmt` omit the handoff, so +generated-input changes invalidate generation and compiling outputs without +rebuilding dependency artifacts or formatting. The `cli-generated-input` flake check verifies the payload roots and both inventories independently of Cargo compilation. diff --git a/flake.nix b/flake.nix index 1dab5deb..f7d7cc31 100644 --- a/flake.nix +++ b/flake.nix @@ -150,6 +150,7 @@ ./config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts ./config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts ./config/lib/pi-plugin/sce-pi-extension.ts + ./scripts/produce-cli-generated-input.sh ]; }; workspaceSrc = pkgs.lib.fileset.toSource { @@ -218,6 +219,7 @@ (pkgs.lib.fileset.maybeMissing ./config/.pi) (pkgs.lib.fileset.maybeMissing ./config/schema/sce-config.schema.json) (pkgs.lib.fileset.maybeMissing ./cli/assets/generated) + ./scripts/produce-cli-generated-input.sh ]; }; @@ -280,11 +282,11 @@ SCE_GIT_COMMIT = shortGitCommit; }; - # Generate the canonical Pkl payload before entering any Cargo - # derivation. The output is content-addressed by only the canonical - # generator inputs, so native, release, test, and Clippy builds share - # one handoff while dependency-only and formatting derivations remain - # independent of it. + # Produce the canonical Pkl payload before entering any Cargo + # derivation. The output is content-addressed by only the producer and + # its canonical generator inputs, so native, release, test, and Clippy + # builds share one handoff while dependency-only and formatting + # derivations remain independent of it. cliGeneratedInput = pkgs.runCommand "sce-cli-generated-input" { src = cliGeneratedInputSrc; @@ -300,40 +302,12 @@ cp -r "$src" ./repo chmod -R u+w ./repo - comparison_root="$(mktemp -d)" - mkdir -p "$out/pkl-generated" "$comparison_root/pkl-generated" - ( - cd ./repo - pkl eval -m "$out/pkl-generated" config/pkl/generate.pkl >/dev/null - pkl eval -m "$comparison_root/pkl-generated" config/pkl/generate.pkl >/dev/null - ) - - diff -qr "$out/pkl-generated" "$comparison_root/pkl-generated" >/dev/null - - ( - cd "$out" - find pkl-generated -type f -print \ - | LC_ALL=C sort \ - | while IFS= read -r path; do - sha256sum "$path" - done - ) > "$out/SHA256SUMS" - - ( - cd ./repo - { - find config/pkl -type f -print - printf '%s\n' \ - config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts \ - config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts \ - config/lib/pi-plugin/sce-pi-extension.ts - } \ - | LC_ALL=C sort \ - | while IFS= read -r path; do - sha256sum "$path" - done - ) > "$out/INPUTS.SHA256SUMS" + ${pkgs.bash}/bin/bash \ + ./repo/scripts/produce-cli-generated-input.sh \ + ./repo \ + ./generated-input + mv ./generated-input "$out" ''; cliGeneratedInputArgs = { @@ -1220,6 +1194,7 @@ cp -r "${pklGeneratedCheckSrc}" ./repo chmod -R u+w ./repo + patchShebangs ./repo/scripts/produce-cli-generated-input.sh cd ./repo export IN_NIX_SHELL=1 diff --git a/scripts/prepare-cli-generated-assets.sh b/scripts/prepare-cli-generated-assets.sh index 30447ac3..8e291df7 100755 --- a/scripts/prepare-cli-generated-assets.sh +++ b/scripts/prepare-cli-generated-assets.sh @@ -13,25 +13,10 @@ case "${target_root}" in *) target_root="$(pwd)/${target_root}" ;; esac -generator="${repo_root}/config/pkl/generate.pkl" -config_lib="${repo_root}/config/lib" - -if [ ! -f "${generator}" ] || [ ! -d "${config_lib}" ]; then - cat >&2 </dev/null 2>&1; then - cat >&2 <<'EOF' -pkl is required to prepare the CLI crate fallback payload. -Run this script from the repository Nix dev shell: - nix develop -c ./scripts/prepare-cli-generated-assets.sh [repo-root] [output-dir] -EOF +producer="${repo_root}/scripts/produce-cli-generated-input.sh" +if [ ! -x "${producer}" ]; then + printf 'CLI generated-input producer is missing or not executable: %s\n' \ + "${producer}" >&2 exit 1 fi @@ -51,38 +36,28 @@ cleanup() { } trap cleanup EXIT -generate_payload() { - destination="$1" - mkdir -p "${destination}/pkl-generated" "${destination}/static/schema" - ( - cd "${repo_root}" - pkl eval -m "${destination}/pkl-generated" "${generator}" >/dev/null - ) - cp -R "${repo_root}/cli/assets/hooks" "${destination}/static/hooks" - cp -R "${repo_root}/cli/migrations" "${destination}/static/migrations" - cp "${repo_root}/config/schema/agent-trace.schema.json" \ - "${destination}/static/schema/agent-trace.schema.json" -} - -generate_payload "${tmp_root}/first" -generate_payload "${tmp_root}/second" +generated_input_root="${tmp_root}/generated-input" +staged_root="${tmp_root}/package-fallback" +"${producer}" "${repo_root}" "${generated_input_root}" -if ! diff -qr "${tmp_root}/first" "${tmp_root}/second" >/dev/null; then - printf 'CLI crate fallback generation is not deterministic.\n' >&2 - diff -r "${tmp_root}/first" "${tmp_root}/second" >&2 || true - exit 1 -fi - -rm -rf "${target_root}" -mv "${tmp_root}/first" "${target_root}" +mkdir -p "${staged_root}/static/schema" +mv "${generated_input_root}/pkl-generated" "${staged_root}/pkl-generated" +cp -R "${repo_root}/cli/assets/hooks" "${staged_root}/static/hooks" +cp -R "${repo_root}/cli/migrations" "${staged_root}/static/migrations" +cp "${repo_root}/config/schema/agent-trace.schema.json" \ + "${staged_root}/static/schema/agent-trace.schema.json" +cp "${generated_input_root}/SHA256SUMS" "${staged_root}/SHA256SUMS" ( - cd "${target_root}" - find pkl-generated static -type f -print \ + cd "${staged_root}" + find static -type f -print \ | LC_ALL=C sort \ | while IFS= read -r path; do sha256sum "${path}" - done > SHA256SUMS + done >> SHA256SUMS ) +rm -rf "${target_root}" +mv "${staged_root}" "${target_root}" + printf 'Prepared deterministic packaging-only fallback at %s\n' "${target_root}" diff --git a/scripts/produce-cli-generated-input.sh b/scripts/produce-cli-generated-input.sh new file mode 100755 index 00000000..d51bf8a5 --- /dev/null +++ b/scripts/produce-cli-generated-input.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -ne 2 ]; then + cat >&2 <<'EOF' +Usage: ./scripts/produce-cli-generated-input.sh +EOF + exit 2 +fi + +repo_root="$(cd "$1" && pwd)" +output_root="$2" +case "${output_root}" in + /*) ;; + *) output_root="$(pwd)/${output_root}" ;; +esac + +generator="${repo_root}/config/pkl/generate.pkl" +input_declaration="${repo_root}/config/pkl/generator-inputs.txt" + +for command in pkl sha256sum diff find sort mktemp; do + if ! command -v "${command}" >/dev/null 2>&1; then + printf '%s is required to produce CLI generated inputs.\n' "${command}" >&2 + exit 1 + fi +done + +if [ ! -f "${generator}" ]; then + printf 'Missing canonical CLI generator: %s\n' "${generator}" >&2 + exit 1 +fi +if [ ! -f "${input_declaration}" ]; then + printf 'Missing canonical CLI generator input declaration: %s\n' "${input_declaration}" >&2 + exit 1 +fi +if [ -e "${output_root}" ]; then + printf 'Generated-input output already exists: %s\n' "${output_root}" >&2 + exit 1 +fi + +output_parent="$(dirname "${output_root}")" +mkdir -p "${output_parent}" +tmp_root="$(mktemp -d "${output_parent}/.sce-cli-generated-input.XXXXXX")" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT +trap 'exit 129' HUP +trap 'exit 130' INT +trap 'exit 143' TERM + +first_root="${tmp_root}/first" +second_root="${tmp_root}/second" +mkdir -p "${first_root}/pkl-generated" "${second_root}/pkl-generated" + +collect_input_paths() { + local declaration_entry + while IFS= read -r declaration_entry || [ -n "${declaration_entry}" ]; do + case "${declaration_entry}" in + ''|'#'*) continue ;; + /*|..|../*|*/../*|*/..) + printf 'Invalid canonical CLI generator input path: %s\n' \ + "${declaration_entry}" >&2 + return 1 + ;; + esac + + if [ -d "${repo_root}/${declaration_entry}" ]; then + ( + cd "${repo_root}" + find "${declaration_entry}" -type f -print + ) + elif [ -f "${repo_root}/${declaration_entry}" ]; then + printf '%s\n' "${declaration_entry}" + else + printf 'Missing canonical CLI generator input: %s\n' \ + "${repo_root}/${declaration_entry}" >&2 + return 1 + fi + done < "${input_declaration}" +} + +write_input_inventory() { + local destination="$1" + local paths_file="${tmp_root}/input-paths" + + collect_input_paths | LC_ALL=C sort -u > "${paths_file}" + ( + cd "${repo_root}" + while IFS= read -r path; do + sha256sum "${path}" + done < "${paths_file}" + ) > "${destination}" +} + +generate_payload() { + local destination="$1" + ( + cd "${repo_root}" + pkl eval -m "${destination}" "${generator}" >/dev/null + ) +} + +write_payload_inventory() { + local generated_input_root="$1" + ( + cd "${generated_input_root}" + find pkl-generated -type f -print \ + | LC_ALL=C sort \ + | while IFS= read -r path; do + sha256sum "${path}" + done + ) > "${generated_input_root}/SHA256SUMS" +} + +initial_input_inventory="${tmp_root}/initial.INPUTS.SHA256SUMS" +final_input_inventory="${first_root}/INPUTS.SHA256SUMS" +write_input_inventory "${initial_input_inventory}" + +generate_payload "${first_root}/pkl-generated" +generate_payload "${second_root}/pkl-generated" + +if ! diff -qr \ + "${first_root}/pkl-generated" \ + "${second_root}/pkl-generated" >/dev/null; then + printf 'Canonical Pkl generation is not deterministic.\n' >&2 + diff -r \ + "${first_root}/pkl-generated" \ + "${second_root}/pkl-generated" >&2 || true + exit 1 +fi + +write_input_inventory "${final_input_inventory}" +if ! diff -u "${initial_input_inventory}" "${final_input_inventory}" >&2; then + printf 'Canonical CLI generator inputs changed during generation.\n' >&2 + exit 1 +fi + +write_payload_inventory "${first_root}" +rm -rf "${second_root}" +mv "${first_root}" "${output_root}" diff --git a/scripts/run-cli-cargo.sh b/scripts/run-cli-cargo.sh index c7d9e1a8..851c20de 100755 --- a/scripts/run-cli-cargo.sh +++ b/scripts/run-cli-cargo.sh @@ -17,27 +17,17 @@ EOF exit 2 fi -for command in pkl cargo sha256sum; do - if ! command -v "${command}" >/dev/null 2>&1; then - printf '%s is required to generate CLI assets and run Cargo.\n' "${command}" >&2 - exit 1 - fi -done - -generator="${repo_root}/config/pkl/generate.pkl" -canonical_inputs=( - "config/pkl" - "config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts" - "config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts" - "config/lib/pi-plugin/sce-pi-extension.ts" -) +if ! command -v cargo >/dev/null 2>&1; then + printf 'cargo is required to run the CLI build.\n' >&2 + exit 1 +fi -for relative_path in "${canonical_inputs[@]}"; do - if [ ! -e "${repo_root}/${relative_path}" ]; then - printf 'Missing canonical CLI generator input: %s\n' "${repo_root}/${relative_path}" >&2 - exit 1 - fi -done +producer="${script_dir}/produce-cli-generated-input.sh" +if [ ! -x "${producer}" ]; then + printf 'CLI generated-input producer is missing or not executable: %s\n' \ + "${producer}" >&2 + exit 1 +fi tmp_root="$(mktemp -d "${TMPDIR:-/tmp}/sce-cli-generated-input.XXXXXX")" cleanup() { @@ -49,63 +39,7 @@ trap 'exit 130' INT trap 'exit 143' TERM generated_input_root="${tmp_root}/generated-input" -comparison_root="${tmp_root}/comparison" -mkdir -p \ - "${generated_input_root}/pkl-generated" \ - "${comparison_root}/pkl-generated" - -generate_payload() { - local destination="$1" - ( - cd "${repo_root}" - pkl eval -m "${destination}" "${generator}" >/dev/null - ) -} - -generate_payload "${generated_input_root}/pkl-generated" -generate_payload "${comparison_root}/pkl-generated" - -if ! diff -qr \ - "${generated_input_root}/pkl-generated" \ - "${comparison_root}/pkl-generated" >/dev/null; then - printf 'Canonical Pkl generation is not deterministic.\n' >&2 - diff -r \ - "${generated_input_root}/pkl-generated" \ - "${comparison_root}/pkl-generated" >&2 || true - exit 1 -fi - -write_payload_inventory() { - ( - cd "${generated_input_root}" - find pkl-generated -type f -print \ - | LC_ALL=C sort \ - | while IFS= read -r path; do - sha256sum "${path}" - done - ) > "${generated_input_root}/SHA256SUMS" -} - -write_canonical_input_inventory() { - ( - cd "${repo_root}" - { - find config/pkl -type f -print - printf '%s\n' \ - config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts \ - config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts \ - config/lib/pi-plugin/sce-pi-extension.ts - } \ - | LC_ALL=C sort \ - | while IFS= read -r path; do - sha256sum "${path}" - done - ) > "${generated_input_root}/INPUTS.SHA256SUMS" -} - -write_payload_inventory -write_canonical_input_inventory -rm -rf "${comparison_root}" +"${producer}" "${repo_root}" "${generated_input_root}" printf 'Prepared temporary CLI generated-input handoff at %s\n' "${generated_input_root}" ( diff --git a/scripts/test-check-generated.sh b/scripts/test-check-generated.sh new file mode 100755 index 00000000..cdee9b77 --- /dev/null +++ b/scripts/test-check-generated.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +check_script="${script_dir}/../config/pkl/check-generated.sh" +producer="${script_dir}/produce-cli-generated-input.sh" +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT + +test_repo="${tmp_root}/repo" +fake_bin="${tmp_root}/bin" +state_root="${tmp_root}/state" +mkdir -p \ + "${test_repo}/config/pkl/renderers/fixtures" \ + "${test_repo}/scripts" \ + "${fake_bin}" \ + "${state_root}" +cp "${check_script}" "${test_repo}/config/pkl/check-generated.sh" +cp "${producer}" "${test_repo}/scripts/produce-cli-generated-input.sh" +printf 'generator\n' > "${test_repo}/config/pkl/generate.pkl" +printf 'config/pkl\n' > "${test_repo}/config/pkl/generator-inputs.txt" +touch \ + "${test_repo}/config/pkl/renderers/metadata-coverage-check.pkl" \ + "${test_repo}/config/pkl/renderers/generation-contract-check.pkl" \ + "${test_repo}/config/pkl/renderers/fixtures/extra-artifact-check.pkl" \ + "${test_repo}/config/pkl/renderers/fixtures/missing-artifact-check.pkl" \ + "${test_repo}/config/pkl/renderers/fixtures/forbidden-workflow-reference-check.pkl" + +cat > "${fake_bin}/pkl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +: "${FAKE_PKL_STATE:?missing fake Pkl state directory}" +destination="" +module="" +while [ "$#" -gt 0 ]; do + case "$1" in + eval) shift ;; + -m) + destination="$2" + shift 2 + ;; + *) + module="$1" + shift + ;; + esac +done + +case "${module}" in + *extra-artifact-check.pkl|*missing-artifact-check.pkl) + printf '%s\n' \ + 'generated artifact inventory does not match the exact expected path contract' >&2 + exit 1 + ;; + *forbidden-workflow-reference-check.pkl) + printf '%s\n' \ + 'generated workflow document contains a forbidden sibling-package reference or unresolved internalization token' >&2 + exit 1 + ;; +esac + +if [ -z "${destination}" ]; then + exit 0 +fi + +count_file="${FAKE_PKL_STATE}/generation-count" +count=0 +if [ -f "${count_file}" ]; then + count="$(<"${count_file}")" +fi +printf '%s\n' "$((count + 1))" > "${count_file}" + +mkdir -p \ + "${destination}/config/.opencode/agent" \ + "${destination}/config/.opencode/command" \ + "${destination}/config/.opencode/skills" \ + "${destination}/config/.opencode/lib" \ + "${destination}/config/.opencode/plugins" \ + "${destination}/config/.claude/commands" \ + "${destination}/config/.claude/skills" \ + "${destination}/config/.claude/hooks" \ + "${destination}/config/.pi/prompts" \ + "${destination}/config/.pi/skills" \ + "${destination}/config/.pi/extensions/sce" \ + "${destination}/config/schema" +printf 'generated\n' > "${destination}/config/.opencode/agent/agent.md" +printf 'generated\n' > "${destination}/config/.opencode/command/command.md" +printf 'generated\n' > "${destination}/config/.opencode/skills/skill.md" +printf 'generated\n' > "${destination}/config/.opencode/lib/bash-policy-presets.json" +printf 'generated\n' > "${destination}/config/.opencode/plugins/sce-bash-policy.ts" +printf 'generated\n' > "${destination}/config/.opencode/plugins/sce-agent-trace.ts" +printf 'generated\n' > "${destination}/config/.opencode/opencode.json" +printf 'generated\n' > "${destination}/config/.claude/commands/command.md" +printf 'generated\n' > "${destination}/config/.claude/skills/skill.md" +printf 'generated\n' > "${destination}/config/.claude/hooks/run-sce-or-show-install-guidance.sh" +printf 'generated\n' > "${destination}/config/.claude/settings.json" +printf 'generated\n' > "${destination}/config/.pi/prompts/prompt.md" +printf 'generated\n' > "${destination}/config/.pi/skills/skill.md" +printf 'generated\n' > "${destination}/config/.pi/extensions/sce/index.ts" +printf 'generated\n' > "${destination}/config/schema/sce-config.schema.json" +EOF +chmod +x \ + "${fake_bin}/pkl" \ + "${test_repo}/config/pkl/check-generated.sh" \ + "${test_repo}/scripts/produce-cli-generated-input.sh" + +output="$({ + env \ + PATH="${fake_bin}:${PATH}" \ + IN_NIX_SHELL=1 \ + SCE_REPO_ROOT="${test_repo}" \ + FAKE_PKL_STATE="${state_root}" \ + "${test_repo}/config/pkl/check-generated.sh" +} 2>&1)" + +if [ "$(<"${state_root}/generation-count")" -ne 2 ]; then + printf 'Generated-output check did not delegate exactly one producer run.\n' >&2 + exit 1 +fi +if [[ "${output}" != *'Ephemeral Pkl generation passed:'* ]]; then + printf 'Generated-output check did not report producer inventory success.\n%s\n' \ + "${output}" >&2 + exit 1 +fi + +printf 'check-generated delegation tests passed.\n' diff --git a/scripts/test-prepare-cli-generated-assets.sh b/scripts/test-prepare-cli-generated-assets.sh new file mode 100755 index 00000000..5a77acda --- /dev/null +++ b/scripts/test-prepare-cli-generated-assets.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +helper="${script_dir}/prepare-cli-generated-assets.sh" +producer="${script_dir}/produce-cli-generated-input.sh" +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT + +test_repo="${tmp_root}/repo" +fake_bin="${tmp_root}/bin" +state_root="${tmp_root}/state" +mkdir -p \ + "${test_repo}/scripts" \ + "${test_repo}/config/pkl" \ + "${test_repo}/config/schema" \ + "${test_repo}/cli/assets/hooks" \ + "${test_repo}/cli/migrations" \ + "${fake_bin}" \ + "${state_root}" +cp "${helper}" "${test_repo}/scripts/prepare-cli-generated-assets.sh" +cp "${producer}" "${test_repo}/scripts/produce-cli-generated-input.sh" +printf 'generator\n' > "${test_repo}/config/pkl/generate.pkl" +printf 'config/pkl\n' > "${test_repo}/config/pkl/generator-inputs.txt" +printf 'schema\n' > "${test_repo}/config/schema/agent-trace.schema.json" +printf 'hook\n' > "${test_repo}/cli/assets/hooks/hook.sh" +printf 'migration\n' > "${test_repo}/cli/migrations/001.sql" + +cat > "${fake_bin}/pkl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +: "${FAKE_PKL_STATE:?missing fake Pkl state directory}" +destination="" +while [ "$#" -gt 0 ]; do + case "$1" in + eval) shift ;; + -m) + destination="$2" + shift 2 + ;; + *) shift ;; + esac +done +count_file="${FAKE_PKL_STATE}/generation-count" +count=0 +if [ -f "${count_file}" ]; then + count="$(<"${count_file}")" +fi +printf '%s\n' "$((count + 1))" > "${count_file}" +mkdir -p "${destination}/config/.opencode" +printf 'generated\n' > "${destination}/config/.opencode/generated.txt" +EOF +chmod +x \ + "${fake_bin}/pkl" \ + "${test_repo}/scripts/prepare-cli-generated-assets.sh" \ + "${test_repo}/scripts/produce-cli-generated-input.sh" + +run_helper() { + env \ + PATH="${fake_bin}:${PATH}" \ + FAKE_PKL_STATE="${state_root}" \ + "${test_repo}/scripts/prepare-cli-generated-assets.sh" \ + "${test_repo}" "$1" >/dev/null +} + +first_root="${tmp_root}/first" +second_root="${tmp_root}/second" +run_helper "${first_root}" +run_helper "${second_root}" + +if ! diff -r "${first_root}" "${second_root}" >/dev/null; then + printf 'Producer-backed package fallbacks differed across runs.\n' >&2 + exit 1 +fi +if [ "$(<"${state_root}/generation-count")" -ne 4 ]; then + printf 'Packaging helper did not delegate one producer run per fallback.\n' >&2 + exit 1 +fi +test ! -e "${first_root}/INPUTS.SHA256SUMS" +test -f "${first_root}/pkl-generated/config/.opencode/generated.txt" +test -f "${first_root}/static/hooks/hook.sh" +test -f "${first_root}/static/migrations/001.sql" +test -f "${first_root}/static/schema/agent-trace.schema.json" +( + cd "${first_root}" + sha256sum -c SHA256SUMS >/dev/null +) +if [ "$(wc -l < "${first_root}/SHA256SUMS" | tr -d ' ')" -ne 4 ]; then + printf 'Combined package fallback inventory has the wrong entry count.\n' >&2 + exit 1 +fi + +printf 'prepare-cli-generated-assets delegation tests passed.\n' diff --git a/scripts/test-produce-cli-generated-input.sh b/scripts/test-produce-cli-generated-input.sh new file mode 100755 index 00000000..d002fe5e --- /dev/null +++ b/scripts/test-produce-cli-generated-input.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +producer="${script_dir}/produce-cli-generated-input.sh" +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "${tmp_root}" +} +trap cleanup EXIT + +fake_bin="${tmp_root}/bin" +mkdir -p "${fake_bin}" +cat > "${fake_bin}/pkl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +: "${FAKE_PKL_STATE:?missing fake Pkl state directory}" +destination="" +generator="" +while [ "$#" -gt 0 ]; do + case "$1" in + eval) shift ;; + -m) + destination="$2" + shift 2 + ;; + *) + generator="$1" + shift + ;; + esac +done + +mkdir -p "${FAKE_PKL_STATE}" +count_file="${FAKE_PKL_STATE}/count" +count=0 +if [ -f "${count_file}" ]; then + count="$(<"${count_file}")" +fi +count=$((count + 1)) +printf '%s\n' "${count}" > "${count_file}" + +case "${FAKE_PKL_MODE:-success}" in + failure) + exit 37 + ;; + mutation) + if [ "${count}" -eq 1 ]; then + printf 'mutated\n' >> "${FAKE_PKL_MUTATION_TARGET:?missing mutation target}" + fi + ;; +esac + +mkdir -p "${destination}/config/.opencode" +case "${FAKE_PKL_MODE:-success}" in + drift) + printf 'generation-%s\n' "${count}" \ + > "${destination}/config/.opencode/generated.txt" + ;; + *) + sha256sum "${generator}" \ + > "${destination}/config/.opencode/generated.txt" + ;; +esac +EOF +chmod +x "${fake_bin}/pkl" + +create_repo() { + local repo="$1" + mkdir -p \ + "${repo}/config/pkl" \ + "${repo}/config/lib/agent-trace-plugin" \ + "${repo}/config/lib/bash-policy-plugin" \ + "${repo}/config/lib/pi-plugin" + printf 'generator\n' > "${repo}/config/pkl/generate.pkl" + cat > "${repo}/config/pkl/generator-inputs.txt" <<'EOF' +# Test canonical inputs. +config/pkl +config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts +config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts +config/lib/pi-plugin/sce-pi-extension.ts +EOF + printf 'agent-trace\n' \ + > "${repo}/config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts" + printf 'bash-policy\n' \ + > "${repo}/config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts" + printf 'pi-extension\n' \ + > "${repo}/config/lib/pi-plugin/sce-pi-extension.ts" +} + +assert_no_staging_dirs() { + local parent="$1" + local staging_dirs=("${parent}"/.sce-cli-generated-input.*) + if [ -e "${staging_dirs[0]}" ]; then + printf 'Producer temporary state was not cleaned up under %s.\n' "${parent}" >&2 + exit 1 + fi +} + +run_producer() { + local repo="$1" + local output="$2" + local state="$3" + local mode="$4" + env \ + PATH="${fake_bin}:${PATH}" \ + FAKE_PKL_STATE="${state}" \ + FAKE_PKL_MODE="${mode}" \ + FAKE_PKL_MUTATION_TARGET="${repo}/config/lib/pi-plugin/sce-pi-extension.ts" \ + "${producer}" "${repo}" "${output}" +} + +success_root="${tmp_root}/success" +success_repo="${success_root}/repo" +success_output="${success_root}/generated-input" +create_repo "${success_repo}" +run_producer "${success_repo}" "${success_output}" \ + "${success_root}/state" success +test "$(<"${success_root}/state/count")" -eq 2 +test -f "${success_output}/pkl-generated/config/.opencode/generated.txt" +( + cd "${success_output}" + sha256sum -c SHA256SUMS >/dev/null +) +( + cd "${success_repo}" + sha256sum -c "${success_output}/INPUTS.SHA256SUMS" >/dev/null +) +assert_no_staging_dirs "${success_root}" + +missing_root="${tmp_root}/missing" +missing_repo="${missing_root}/repo" +create_repo "${missing_repo}" +rm "${missing_repo}/config/lib/pi-plugin/sce-pi-extension.ts" +if run_producer "${missing_repo}" "${missing_root}/generated-input" \ + "${missing_root}/state" success >"${missing_root}/log" 2>&1; then + printf 'Producer accepted a missing declared input.\n' >&2 + exit 1 +fi +if ! grep -Fq 'Missing canonical CLI generator input' "${missing_root}/log"; then + printf 'Missing-input failure did not report the expected diagnostic.\n' >&2 + exit 1 +fi +test ! -e "${missing_root}/generated-input" +assert_no_staging_dirs "${missing_root}" + +mutation_root="${tmp_root}/mutation" +mutation_repo="${mutation_root}/repo" +create_repo "${mutation_repo}" +if run_producer "${mutation_repo}" "${mutation_root}/generated-input" \ + "${mutation_root}/state" mutation >"${mutation_root}/log" 2>&1; then + printf 'Producer accepted canonical input mutation during generation.\n' >&2 + exit 1 +fi +if ! grep -Fq 'Canonical CLI generator inputs changed during generation' \ + "${mutation_root}/log"; then + printf 'Input-mutation failure did not report the expected diagnostic.\n' >&2 + exit 1 +fi +test ! -e "${mutation_root}/generated-input" +assert_no_staging_dirs "${mutation_root}" + +drift_root="${tmp_root}/drift" +drift_repo="${drift_root}/repo" +create_repo "${drift_repo}" +if run_producer "${drift_repo}" "${drift_root}/generated-input" \ + "${drift_root}/state" drift >"${drift_root}/log" 2>&1; then + printf 'Producer accepted nondeterministic generated output.\n' >&2 + exit 1 +fi +if ! grep -Fq 'Canonical Pkl generation is not deterministic' \ + "${drift_root}/log"; then + printf 'Generation-drift failure did not report the expected diagnostic.\n' >&2 + exit 1 +fi +test ! -e "${drift_root}/generated-input" +assert_no_staging_dirs "${drift_root}" + +failure_root="${tmp_root}/failure" +failure_repo="${failure_root}/repo" +create_repo "${failure_repo}" +set +e +run_producer "${failure_repo}" "${failure_root}/generated-input" \ + "${failure_root}/state" failure >"${failure_root}/log" 2>&1 +failure_status=$? +set -e +if [ "${failure_status}" -ne 37 ]; then + printf 'Producer did not preserve the Pkl failure status: %s.\n' \ + "${failure_status}" >&2 + exit 1 +fi +test ! -e "${failure_root}/generated-input" +assert_no_staging_dirs "${failure_root}" + +printf 'CLI generated-input producer tests passed.\n' diff --git a/scripts/test-run-cli-cargo.sh b/scripts/test-run-cli-cargo.sh index 5321e8a8..92d9fbb3 100755 --- a/scripts/test-run-cli-cargo.sh +++ b/scripts/test-run-cli-cargo.sh @@ -3,6 +3,8 @@ set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" helper="${script_dir}/run-cli-cargo.sh" +producer="${script_dir}/produce-cli-generated-input.sh" +input_declaration="${script_dir}/../config/pkl/generator-inputs.txt" tmp_root="$(mktemp -d)" cleanup() { rm -rf "${tmp_root}" @@ -23,6 +25,8 @@ mkdir -p \ "${state_root}" \ "${tmp_dir}" cp "${helper}" "${test_repo}/scripts/run-cli-cargo.sh" +cp "${producer}" "${test_repo}/scripts/produce-cli-generated-input.sh" +cp "${input_declaration}" "${test_repo}/config/pkl/generator-inputs.txt" printf 'generator-v1\n' > "${test_repo}/config/pkl/generate.pkl" printf 'agent-trace\n' > "${test_repo}/config/lib/agent-trace-plugin/opencode-sce-agent-trace-plugin.ts" @@ -70,7 +74,11 @@ cp "${SCE_CLI_GENERATED_INPUT_DIR}/SHA256SUMS" "${FAKE_CARGO_STATE}/SHA256SUMS" cp "${SCE_CLI_GENERATED_INPUT_DIR}/INPUTS.SHA256SUMS" "${FAKE_CARGO_STATE}/INPUTS.SHA256SUMS" exit "${FAKE_CARGO_EXIT_CODE:-0}" EOF -chmod +x "${fake_bin}/pkl" "${fake_bin}/cargo" "${test_repo}/scripts/run-cli-cargo.sh" +chmod +x \ + "${fake_bin}/pkl" \ + "${fake_bin}/cargo" \ + "${test_repo}/scripts/produce-cli-generated-input.sh" \ + "${test_repo}/scripts/run-cli-cargo.sh" run_helper() { env \ From 935745fddb71a875ba4392be86ee72e141319611 Mon Sep 17 00:00:00 2001 From: David Abram Date: Thu, 30 Jul 2026 01:34:40 +0200 Subject: [PATCH 21/21] workflows: Enforce canonical execution and output layouts Prevent agents from inventing, skipping, reordering, or merging workflow steps, and from wrapping defined output layouts with extra prose. Apply the shared preamble rules across all generated target skill packages. --- .claude/skills/sce-change-to-plan/SKILL.md | 5 +- .claude/skills/sce-commit/SKILL.md | 5 +- .claude/skills/sce-next-task/SKILL.md | 5 +- .claude/skills/sce-validate/SKILL.md | 5 +- .opencode/skills/sce-change-to-plan/SKILL.md | 5 +- .opencode/skills/sce-commit/SKILL.md | 5 +- .opencode/skills/sce-next-task/SKILL.md | 5 +- .opencode/skills/sce-validate/SKILL.md | 5 +- .pi/skills/sce-change-to-plan/SKILL.md | 5 +- .pi/skills/sce-commit/SKILL.md | 5 +- .pi/skills/sce-next-task/SKILL.md | 5 +- .pi/skills/sce-validate/SKILL.md | 5 +- config/pkl/renderers/workflow-composite.pkl | 5 +- context/architecture.md | 2 +- context/glossary.md | 1 + context/patterns.md | 1 + .../plans/workflow-no-improvisation-rule.md | 133 ++++++++++++++++++ 17 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 context/plans/workflow-no-improvisation-rule.md diff --git a/.claude/skills/sce-change-to-plan/SKILL.md b/.claude/skills/sce-change-to-plan/SKILL.md index 1a504888..d48f6e1e 100644 --- a/.claude/skills/sce-change-to-plan/SKILL.md +++ b/.claude/skills/sce-change-to-plan/SKILL.md @@ -12,12 +12,15 @@ compatibility: claude Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.claude/skills/sce-commit/SKILL.md b/.claude/skills/sce-commit/SKILL.md index 1464878d..9dd1aba4 100644 --- a/.claude/skills/sce-commit/SKILL.md +++ b/.claude/skills/sce-commit/SKILL.md @@ -12,12 +12,15 @@ compatibility: claude Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.claude/skills/sce-next-task/SKILL.md b/.claude/skills/sce-next-task/SKILL.md index bfd7866d..bb419534 100644 --- a/.claude/skills/sce-next-task/SKILL.md +++ b/.claude/skills/sce-next-task/SKILL.md @@ -12,12 +12,15 @@ compatibility: claude Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.claude/skills/sce-validate/SKILL.md b/.claude/skills/sce-validate/SKILL.md index ab530f63..da142725 100644 --- a/.claude/skills/sce-validate/SKILL.md +++ b/.claude/skills/sce-validate/SKILL.md @@ -12,12 +12,15 @@ compatibility: claude Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.opencode/skills/sce-change-to-plan/SKILL.md b/.opencode/skills/sce-change-to-plan/SKILL.md index 92d48a4e..21da24ca 100644 --- a/.opencode/skills/sce-change-to-plan/SKILL.md +++ b/.opencode/skills/sce-change-to-plan/SKILL.md @@ -12,12 +12,15 @@ compatibility: opencode Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.opencode/skills/sce-commit/SKILL.md b/.opencode/skills/sce-commit/SKILL.md index 43670d17..08923114 100644 --- a/.opencode/skills/sce-commit/SKILL.md +++ b/.opencode/skills/sce-commit/SKILL.md @@ -12,12 +12,15 @@ compatibility: opencode Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.opencode/skills/sce-next-task/SKILL.md b/.opencode/skills/sce-next-task/SKILL.md index 68df5036..b63b9b7b 100644 --- a/.opencode/skills/sce-next-task/SKILL.md +++ b/.opencode/skills/sce-next-task/SKILL.md @@ -12,12 +12,15 @@ compatibility: opencode Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.opencode/skills/sce-validate/SKILL.md b/.opencode/skills/sce-validate/SKILL.md index 0d96b1df..d1300ca5 100644 --- a/.opencode/skills/sce-validate/SKILL.md +++ b/.opencode/skills/sce-validate/SKILL.md @@ -12,12 +12,15 @@ compatibility: opencode Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.pi/skills/sce-change-to-plan/SKILL.md b/.pi/skills/sce-change-to-plan/SKILL.md index a03d3b98..76cff5d1 100644 --- a/.pi/skills/sce-change-to-plan/SKILL.md +++ b/.pi/skills/sce-change-to-plan/SKILL.md @@ -11,12 +11,15 @@ description: > Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.pi/skills/sce-commit/SKILL.md b/.pi/skills/sce-commit/SKILL.md index 9c843242..b82bfb53 100644 --- a/.pi/skills/sce-commit/SKILL.md +++ b/.pi/skills/sce-commit/SKILL.md @@ -11,12 +11,15 @@ description: > Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.pi/skills/sce-next-task/SKILL.md b/.pi/skills/sce-next-task/SKILL.md index a07f72d6..e42cd1c4 100644 --- a/.pi/skills/sce-next-task/SKILL.md +++ b/.pi/skills/sce-next-task/SKILL.md @@ -11,12 +11,15 @@ description: > Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/.pi/skills/sce-validate/SKILL.md b/.pi/skills/sce-validate/SKILL.md index d711aa42..f8a92579 100644 --- a/.pi/skills/sce-validate/SKILL.md +++ b/.pi/skills/sce-validate/SKILL.md @@ -11,12 +11,15 @@ description: > Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/config/pkl/renderers/workflow-composite.pkl b/config/pkl/renderers/workflow-composite.pkl index 0c162125..a6b99176 100644 --- a/config/pkl/renderers/workflow-composite.pkl +++ b/config/pkl/renderers/workflow-composite.pkl @@ -74,12 +74,15 @@ description: > Own this workflow from input parsing through its terminal user-visible response. Execute the phases below directly and in order. Phase statuses are internal state, not inter-skill handoffs. Do not invoke another SCE skill, sibling package, or -workflow command. +workflow command. Follow the canonical workflow's steps, gates, and stops exactly +as written: never invent, skip, reorder, or merge a step. ## User-visible output Use `references/output.md` for every gate and terminal response. Render no raw internal state. The reference contains only human-visible Markdown layouts. +User-visible output is limited to those layouts: never invent a layout, and never +wrap one in an added preamble, commentary, summary, or extra section. ## Canonical workflow diff --git a/context/architecture.md b/context/architecture.md index 0ecdd12b..e091c516 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -43,7 +43,7 @@ Renderer modules apply target-specific metadata/frontmatter rules while reusing - All three renderers consume the four canonical workflow packages as behavior sources and emit the same four workflow packages: `sce-change-to-plan`, `sce-next-task`, `sce-validate`, and `sce-commit`. `workflow-composite.pkl` embeds the canonical phase behavior, status branches, waits, same-session resume rules, and persisted-document formats into that workflow's `SKILL.md`; phase statuses remain internal rather than crossing sibling skill boundaries. Every package has exactly one additional file, `references/output.md`, which defines all human-visible gates and terminal Markdown for that workflow. Each thin command or prompt invokes exactly one corresponding workflow skill. - Per-target differences are confined to frontmatter and the surrounding non-workflow outputs. The manual OpenCode renderer adds `agent`, `entry-skill`, and a one-entry `skills` list to command frontmatter, adds `compatibility: opencode` to each package entrypoint, and emits two thin routing agents whose `skill:` permission allowlists name only the four workflow slugs. The Claude renderer adds `compatibility: claude` plus `allowed-tools:` and emits no agents; Claude settings and the hook helper remain separate retained outputs. The Pi renderer adds no frontmatter to either prompts or skills. - Pi renderer consumes the same shared workflow composition as OpenCode and Claude. It emits exactly four thin prompts to `config/.pi/prompts/{slug}.md`, each routing to exactly one workflow skill, and four packages under `config/.pi/skills/{slug}/` containing only `SKILL.md` and `references/output.md`. Pi prompts and skills carry no target-specific frontmatter beyond the shared description and argument hint, so Pi passes the empty extra-frontmatter string to the composite renderer. It emits no Pi agent-role prompts. Pi has no settings/plugin manifest; runtime integration remains the project-local extension emitted verbatim from `config/lib/pi-plugin/sce-pi-extension.ts` to `config/.pi/extensions/sce/index.ts` (auto-discovered by Pi, no registration manifest; see `context/sce/pi-extension-runtime.md`). -- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions and output layouts, while each composite looks up its typed identity in `config/pkl/base/workflow-catalog.pkl`. Every workflow supplies a required `StructuredCompositeSource`, so commands, phase documents, persisted-document formats, and output references render in package or composite mode before Markdown assembly. The renderer has no nullable legacy adapter, frontmatter stripping, or prose-wide replacement chain. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and a catalog-derived `allowed-tools` line for commands. +- Workflow composition itself is shared rather than per target. `config/pkl/renderers/workflow-composite.pkl` owns the four composite workflow definitions and output layouts, while each composite looks up its typed identity in `config/pkl/base/workflow-catalog.pkl`. Every workflow supplies a required `StructuredCompositeSource`, so commands, phase documents, persisted-document formats, and output references render in package or composite mode before Markdown assembly. The renderer has no nullable legacy adapter, frontmatter stripping, or prose-wide replacement chain. Its `renderSkill`, `renderCommand`, and `skillDocuments` entrypoints take a newline-terminated `extraFrontmatterLines` string carrying only the frontmatter a target supports; a target that adds none passes the empty string. Claude passes `compatibility: claude` for skills and a catalog-derived `allowed-tools` line for commands. The `renderSkill` preamble also carries the no-improvisation rule that every generated workflow `SKILL.md` states on every target: the executing agent follows the canonical workflow's steps, gates, and stops exactly as written and never invents, skips, reorders, or merges a step, and its user-visible output is limited to the `references/output.md` layouts with no invented layout and no added preamble, commentary, summary, or extra section. The rule is prose instruction only; the generation contract checks assert paths and metadata, not agent behavior. - Shared renderer document types and OpenCode plugin-registration helpers live in `config/pkl/renderers/common.pkl`. - The canonical OpenCode plugin-registration source for generated SCE plugins lives in `config/pkl/base/opencode.pkl`; `config/pkl/renderers/common.pkl` re-exports the shared plugin list and JSON-ready paths for OpenCode renderers, and the current generated registration scope is limited to SCE-managed plugins emitted by this repo (`sce-bash-policy` and `sce-agent-trace`). - Target renderers remain responsible for formatting target-supported metadata. OpenCode metadata owns thin-agent presentation and compatibility while deriving workflow permission lines from catalog role assignments; OpenCode command routing derives the same role and skill identity from the catalog. Claude metadata derives command tools from catalog records. Pi has no metadata module because it adds no target-specific frontmatter. diff --git a/context/glossary.md b/context/glossary.md index bb609e0d..fb09a33d 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -17,6 +17,7 @@ - `canonical phase module`: One of the eight phase definitions in `config/pkl/base/workflow-*.pkl` (`sce-context-load`, `sce-plan-authoring`, `sce-plan-review`, `sce-task-execution`, `sce-task-context-sync`, `sce-validation`, `sce-plan-context-sync`, `sce-atomic-commit`). Each is the single behavioral source for its phase and an authoring input to the composite renderer. Since 2026-07-29 no target generates them as installable skill packages; the names denote canonical source and the internal phases inside a composed `SKILL.md`. - `extra frontmatter lines`: The newline-terminated string a target passes to the workflow composite renderer carrying only the frontmatter its skills or commands support (for example `compatibility: claude`, or an `allowed-tools:` line). It is the sole per-target parameter of composition; a target that adds no frontmatter passes the empty string. - `workflow output reference`: The required `references/output.md` in every workflow skill package. It is the package's only reference file and defines all and only that workflow's human-visible Markdown gates, reports, and terminal layouts; operational instructions and persisted-file formats remain in `SKILL.md`. +- `no-improvisation rule`: The agent-behavior policy stated by the shared `renderSkill` preamble in every generated workflow `SKILL.md`, on every target. Its process half forbids inventing, skipping, reordering, or merging the canonical workflow's steps, gates, and stops; its output half limits user-visible output to the `references/output.md` layouts, forbidding invented layouts and any added preamble, commentary, summary, or extra section around them. It is prose instruction, not a machine-checked contract. See `context/architecture.md`. - `atomic commit bypass mode`: The `/commit` mode selected when the exact first argument token is `oneshot` or `skip` (case-insensitive; the two aliases are behaviorally identical). It skips the staging-confirmation prompt and the context-file guidance gate, requires exactly one commit message covering all staged files with no split proposals, makes plan citations best-effort instead of blocking, and lets the command run exactly one `git commit`. Any other first token selects proposal-only regular mode. See `context/sce/atomic-commit-workflow.md`. - `canonical OpenCode plugin registration source`: Shared Pkl-authored plugin-registration definition in `config/pkl/base/opencode.pkl`, re-exported from `config/pkl/renderers/common.pkl` as the canonical plugin list/path JSON consumed by OpenCode renderers before they emit generated `opencode.json` manifests; the current entries are `sce-bash-policy` and `sce-agent-trace`. - `checkout identity`: Stable UUIDv7 identifier assigned to a cloned repository or linked Git worktree, stored in `/sce/checkout-id` (never committed) and resolved via `git rev-parse --git-dir`. The identity is created or reused by `sce setup` through `AgentTraceDbLifecycle::setup()` and also auto-created by hook runtime when `sce setup` has not been run. Checkout identity is now diagnostic metadata for repository-scoped Agent Trace storage; it does not select the active DB and is not stored on Agent Trace rows. Any pre-migration per-checkout DB files at `/sce/agent-trace-{checkout_id}.db` are never touched by SCE and are no longer inspectable via the CLI (the checkout-scoped DB surface was removed by the `retire-legacy-agent-trace-db` plan). See `context/cli/checkout-identity.md`. diff --git a/context/patterns.md b/context/patterns.md index 2a7397c2..aaf61a32 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -57,6 +57,7 @@ - Keep OpenCode agents as thin routing surfaces when canonical workflow commands and skills own the behavior; do not duplicate workflow doctrine in agent bodies. - Implement target-specific formatting in dedicated renderer modules under `config/pkl/renderers/`, but keep workflow composition itself in the shared `workflow-composite.pkl`. Every canonical workflow must choose package-vs-composite wording through typed semantic references before Markdown assembly, not by stripping frontmatter or post-processing prose. Require a structured composite source for each workflow and do not reintroduce a legacy rewrite path. A target parameterizes composition only through the frontmatter lines it supports, never by forking the composition logic. - Compose each canonical workflow into one workflow-level skill package for every generated target; keep phase status handling internal to `SKILL.md`, emit no phase-skill package, and emit exactly one `references/output.md` containing that workflow's human-visible Markdown layouts. The canonical phase packages under `config/pkl/base/` remain authoring inputs to that composition, not a generated output surface for any target. +- Keep cross-workflow agent-behavior policy such as the no-improvisation rule in the shared `renderSkill` preamble of `workflow-composite.pkl`, which every workflow and target already composes through. Do not copy the same prose into the four canonical `workflow-*.pkl` modules or into per-workflow `references/output.md` bodies, and do not add a strictness knob or per-workflow override for it. - Keep shared renderer document and plugin-registration contracts in `config/pkl/renderers/common.pkl`; workflow identity metadata belongs in the typed workflow catalog rather than renderer-local description or routing maps. - Keep only actively consumed target metadata in dedicated modules (`opencode-metadata.pkl` and `claude-metadata.pkl`); Pi needs no metadata module because it adds no target-specific frontmatter. - Add OpenCode machine-readable orchestration metadata in `config/pkl/renderers/opencode-content.pkl`: catalog-derived `agent`, `entry-skill`, and a `skills` chain naming that command's single workflow skill. Derive agent permission allowlists from the same catalog role assignments. diff --git a/context/plans/workflow-no-improvisation-rule.md b/context/plans/workflow-no-improvisation-rule.md new file mode 100644 index 00000000..e9aec6c4 --- /dev/null +++ b/context/plans/workflow-no-improvisation-rule.md @@ -0,0 +1,133 @@ +# Plan: workflow-no-improvisation-rule + +## Change summary + +Every generated SCE workflow skill (`sce-change-to-plan`, `sce-next-task`, +`sce-validate`, `sce-commit`) must state explicitly that the executing agent may +not improvise: it follows the canonical workflow's steps, gates, and stops as +written, and it emits only the user-visible responses defined in +`references/output.md`. Today the shared composite skill preamble says to use +`references/output.md` "for every gate and terminal response" and to render no +raw internal state, but it never forbids inventing, skipping, reordering, or +merging process steps, and it never forbids adding commentary, preambles, +summaries, or extra sections around the canonical layouts. + +The rule is added once, in the shared `renderSkill` preamble of +`config/pkl/renderers/workflow-composite.pkl`, which all four workflows and all +three targets (OpenCode, Claude, Pi) already compose through. This preserves the +existing single-owner rendering model rather than repeating the same prose in +four canonical workflow modules. The change is prose-only inside generated +`SKILL.md` documents; no artifact paths, counts, frontmatter, or contracts move. + +## Acceptance criteria + +- [ ] AC1: Every generated workflow `SKILL.md` for every target states that the + canonical workflow's steps and stops must be followed as written and that + no step may be invented, skipped, reordered, or merged. + - Validate: generate into a temp root with + `nix run .#pkl-generate -- "$(mktemp -d -t sce-gen-XXXX)"`, then confirm all + 12 workflow `SKILL.md` files under `.opencode/`, `.claude/`, and `.pi/` + contain the new no-improvisation process sentence. +- [ ] AC2: Every generated workflow `SKILL.md` for every target states that + user-visible output is limited to the layouts in `references/output.md`, + with no invented layouts, added preambles, commentary, or extra sections. + - Validate: same generated payload; confirm all 12 workflow `SKILL.md` files + contain the new no-improvisation output sentence. +- [ ] AC3: The generation contract is unchanged — the same artifact paths, + counts, metadata, and forbidden-path assertions still hold. + - Validate: `nix run .#pkl-check-generated` + +### Full validation + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- `context/sce/shared-context-plan-workflow.md` +- `context/sce/shared-context-code-workflow.md` +- `context/sce/atomic-commit-workflow.md` +- `context/overview.md` (composite renderer preamble description) + +## Constraints and non-goals + +- **In scope:** the `renderSkill` preamble in + `config/pkl/renderers/workflow-composite.pkl`. +- **Out of scope:** the four canonical workflow modules in + `config/pkl/base/workflow-*.pkl`, the per-workflow `references/output.md` + bodies, `renderCommand`, target metadata renderers, OpenCode routing agents, + and any Rust CLI surface. +- **Constraints:** generated targets are ephemeral; edit canonical Pkl only and + verify through ephemeral generation. The composite renderer stays + target-neutral — the rule must apply identically to OpenCode, Claude, and Pi. + Existing preamble sentences and section headings must not be rewritten beyond + what the new rule requires. +- **Non-goal:** introducing a new configurable "strictness" knob, a per-workflow + override, or a machine-checkable lint for improvised output. + +## Assumptions + +- "Every workflow" is satisfied by editing the one shared composite preamble + rather than by adding four copies of the same prose, per the single-owner + rendering model recorded in + `context/decisions/2026-07-29-cross-target-workflow-skill-packages.md`. +- The rule belongs in `SKILL.md` (which the agent reads as instruction) rather + than in `references/output.md` (which each workflow already scopes with "Use + only the applicable layout"). + +## Task stack + +- [x] T01: `Forbid workflow and output improvisation in the composite skill preamble` (status:done) + - Task ID: T01 + - Goal: Add an explicit no-improvisation rule to the shared `renderSkill` + preamble so all four workflow `SKILL.md` documents, on all three targets, + instruct the agent to execute the canonical process exactly as written and + to emit only `references/output.md` layouts as user-visible output. + - Boundaries (in/out of scope): In — the `Purpose` and `User-visible output` + preamble text inside `renderSkill` in + `config/pkl/renderers/workflow-composite.pkl`. Out — canonical + `config/pkl/base/workflow-*.pkl` modules, the four `*_OUTPUT` layout + constants, `renderCommand`, and every target metadata renderer. + - Dependencies: none + - Done when: the preamble forbids inventing, skipping, reordering, or merging + workflow steps and stops, and forbids user-visible output beyond the + `references/output.md` layouts (no added preambles, commentary, summaries, + or extra sections); ephemeral generation shows the new text in all 12 + workflow `SKILL.md` files; `nix run .#pkl-check-generated` and + `nix flake check` pass. + - Verification notes (commands or checks): + `nix run .#pkl-generate -- "$(mktemp -d -t sce-gen-XXXX)"` then grep the + generated `sce-{change-to-plan,next-task,validate,commit}/SKILL.md` under + `.opencode/skills`, `.claude/skills`, and `.pi/skills` for the new + sentences; `nix run .#pkl-check-generated`; `nix flake check`. + - Evidence: `config/pkl/renderers/workflow-composite.pkl` — the `renderSkill` + preamble now ends `Purpose` with "Follow the canonical workflow's steps, + gates, and stops exactly as written: never invent, skip, reorder, or merge a + step." and ends `User-visible output` with "User-visible output is limited to + those layouts: never invent a layout, and never wrap one in an added + preamble, commentary, summary, or extra section." No other file changed; + existing preamble sentences and headings were left intact. + - Verification: `nix run .#pkl-generate -- "$(mktemp -d -t sce-gen-XXXX)"` -> + passed; both sentences present in all 12 generated workflow `SKILL.md` files + under `.claude/skills`, `.opencode/skills`, and `.pi/skills` (matched with + newline-insensitive grep, since the rendered prose wraps across lines). + `nix run .#pkl-check-generated` -> passed (46 files, inventory sha256 + 314a5846c990ac8068b74afd569b62e653119a6f33c8b33516ecef5dd6008b9f). + `nix flake check` -> all checks passed. + - Assumptions: both halves of the rule were implemented, per the plan's open + question offering to drop the output sentence only on request. + +## Open questions + +- The output half of this rule is already partially covered: the preamble says + to use `references/output.md` for every gate and terminal response and to + render no raw internal state, and each `references/output.md` says "Use only + the applicable layout." The genuinely new coverage is the process half (no + invented, skipped, reordered, or merged steps) plus the explicit ban on + wrapping the canonical layouts in extra prose. If you only wanted the process + half, say so and the output sentence will be dropped rather than restated. +- Prose instructions of this kind are unenforceable by generation checks — the + contract checks assert paths and metadata, not agent behavior. This change + raises the odds an agent complies; it cannot guarantee it. If you want a + guarantee, that is a different plan (structured output validation), and I do + not think it is worth building yet.