From f963a807ba0902ccbf4a7797f7457b1d74e0d39d Mon Sep 17 00:00:00 2001 From: Personal Stack Agent Date: Mon, 8 Jun 2026 10:29:52 +0000 Subject: [PATCH] Document the Spec-Driven Development (Spec Kit) integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds docs/agents-spec-driven-development.md covering the end-to-end SDD flow — specify scaffolding under templates/repo/.specify, the /speckit.* commands for both Claude and Codex, the install.sh seed model for --scope user|project, the runner seed-by-default behavior, and the council plan -> specs/NNN -> tasks.json path. Updates the agent-kit and council READMEs to point at it. --- docs/agents-spec-driven-development.md | 88 ++++++++++++++++++++++++++ platform/agents/council/README.md | 25 +++++++- platform/agents/kit/README.md | 37 +++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 docs/agents-spec-driven-development.md diff --git a/docs/agents-spec-driven-development.md b/docs/agents-spec-driven-development.md new file mode 100644 index 00000000..5fd8d89e --- /dev/null +++ b/docs/agents-spec-driven-development.md @@ -0,0 +1,88 @@ +# Agent Spec-Driven Development + +This is the end-to-end path for creating a spec-driven feature with council. + +## Create a feature + +1. Start from the target repository root and make sure `.specify` exists. For + personal-stack it is committed; for other projects, install the kit with: + + ```bash + curl -fsSL -H "Authorization: Bearer ${KB_BEARER_TOKEN}" \ + "${KB_URL}/install.sh" | AGENT_KIT_PROJECT_ROOT="$PWD" \ + bash -s -- --agent all --scope project + ``` + +2. Create or refine the feature spec with the dot-form Spec Kit commands: + `/speckit.specify`, `/speckit.clarify`, `/speckit.plan`, + `/speckit.tasks`, and `/speckit.analyze`. User-scope installs also work; if + `.specify` is absent, `/speckit.specify` scaffolds a minimal project runtime + before creating the first spec. + +3. Run council planning against the spec or a brief: + + ```bash + python3 platform/agents/council/council.py plan \ + --brief specs/001-feature/spec.md \ + --spec-dir specs/001-feature + ``` + + `--brief` may also be `-` for stdin or a free-text string. Without + `--spec-dir`, council allocates the next `specs/NNN-slug` directory and + writes `spec.md`, `plan.md`, and generated `tasks.md` under the run + directory. + +4. Review `consolidated_plan.md`, `tasks.json`, and + `specs/NNN-slug/tasks.md` in the run directory. `tasks.json` is canonical; + `tasks.md` is generated from it and must keep an exact JSON-block bijection. + If a human changes task data in `tasks.md`, reconcile by regenerating with + `council plan --run --brief /brief.md` or by making the matching + `tasks.json` change before fan-out. + +5. Execute the approved DAG: + + ```bash + python3 platform/agents/council/council.py fanout --run .council/runs/ + ``` + + Fan-out commits `specs/NNN-slug` onto the integration branch before workers + are spawned. Workers then run in isolated worktrees and the orchestrator + merges successful task commits onto `council//integration` for review. + +## Gates and scope + +The analyze gate hard-fails before execution when +`.specify/memory/constitution.md` is missing or placeholder-like, when +`tasks.md` is missing beside `tasks.json`, or when `tasks.md` no longer +round-trips to the canonical task JSON. Constitution text is injected into +planner, critic, reviser, and consolidator prompts only; worker and verifier +prompts do not receive it. + +The MCP ConfigMap is explicitly unchanged by SDD. Do not edit +`platform/cluster/flux/apps/agents/mcp/agents-mcp-servers-configmap.yaml` for +Spec Kit command, scaffold, or council task changes. + +The commit-capture and stop-digest hooks are not path-suppressible. The edit +recall hook has an allowlist, but commit capture and stop digest can only be +disabled for a session through the global hook controls such as +`KB_AUTO_MCP_DISABLED=1`. + +## Upstream pin and upgrades + +The vendored scaffold is tracked in +`platform/agents/kit/spec-kit-source.lock`: upstream +`https://github.com/github/spec-kit`, tag `v0.9.5`, with the resolved commit +currently recorded as `UNRESOLVED-DNS-BLOCKED`. The agent-kit owner must replace +that placeholder with the real tag commit before merge. + +Spec Kit self-upgrades are human-only and off-runtime. Do not run them from +installer, runner, hook, or council execution paths. The owner workflow is: + +1. Install or upgrade `specify-cli` pinned to the candidate upstream tag. +2. Run `specify self upgrade --dry-run` outside runtime installs and compare + the scaffold changes. +3. Resolve the candidate tag commit and update `spec-kit-source.lock`. +4. Copy only the approved `.specify` scaffold paths into + `platform/agents/kit/templates/repo/.specify/`. +5. Keep `.specify/memory/constitution.md` as the committed personal-stack file; + do not replace it with the generic upstream template. diff --git a/platform/agents/council/README.md b/platform/agents/council/README.md index b27552ca..4d9feb63 100644 --- a/platform/agents/council/README.md +++ b/platform/agents/council/README.md @@ -37,6 +37,24 @@ python3 platform/agents/council/council.py --self-test `plan` prints the run dir on stdout. Inspect `consolidated_plan.md` and `tasks.json` there. +Spec-driven runs also materialize Spec Kit artifacts in the run directory: +`specs/NNN-slug/spec.md`, `plan.md`, and `tasks.md`. The slug is derived from +the first line of the brief; pass `--slug some-name` to choose the slug while +keeping the next available `NNN` number. `--brief` accepts a file, `-` for +stdin, or free text when the argument is not an existing path. + +`tasks.json` is canonical. `tasks.md` is generated from it and includes one +JSON block per task between council markers so it can round-trip exactly. Human +edits to prose around the generated blocks are fine; changing task data requires +editing the marked JSON blocks and regenerating or re-running `council plan +--run --brief /brief.md` so `tasks.md` and `tasks.json` match. + +The analyze gate is a HARD-FAIL checkpoint before fan-out. It requires a +non-placeholder `.specify/memory/constitution.md`, requires `tasks.md` beside +`tasks.json`, and enforces a bijection between the canonical task JSON and the +marked task blocks in `tasks.md`. `plan`, `fanout`, and `fleet` all run this +gate before execution. + ```bash # stages 5-6: execute the task DAG with cheap workers, verify, reconcile python3 platform/agents/council/council.py fanout --run .council/runs/ @@ -53,7 +71,9 @@ verifier (`claude:sonnet`) checks the diff against the objective. Worker commits are merged onto a `council//integration` branch in dependency order; conflicts are left out and reported. **Nothing is merged into your branch** — `fanout` prints the integration branch name for review. See `report.md` in the -run dir. +run dir. Before worker fan-out starts, the run's `specs/NNN-slug` directory is +committed onto the integration branch so every worker sees the same committed +spec, plan, and task artifacts. ```bash # ad-hoc, engine-agnostic worker pool over any tasks.json (no plan phase) @@ -136,6 +156,9 @@ state.json # resume marker - Sub-invocations run with `KB_AUTO_MCP_DISABLED=1` so council's internal prompts never pollute the knowledge base. - Codex planning/critique uses `model_reasoning_effort=high`, read-only sandbox. +- The project constitution is injected only into reasoning roles: planner, + critic, reviser, and consolidator. Worker and verifier prompts do not receive + the constitution block. - Both `claude` and `codex` CLIs must be installed and authenticated. - We don't bundle a full JSON-Schema validator; `validate_tasks` checks the fields fan-out relies on and runs a topological sort (cycle / unknown-dep diff --git a/platform/agents/kit/README.md b/platform/agents/kit/README.md index e6a9fcd9..ce2d2703 100644 --- a/platform/agents/kit/README.md +++ b/platform/agents/kit/README.md @@ -39,6 +39,43 @@ repo-local `.claude` and `.codex` directories instead of user config homes. See [PORTABILITY.md](PORTABILITY.md) for uninstall, backup/export, restore, and compatibility-matrix details. +## Spec-driven development scaffold + +The kit vendors the GitHub Spec Kit runtime under +`templates/repo/.specify`. The checked-in scaffold includes templates plus the +Bash helper scripts under `.specify/scripts/bash`; those scripts are executable +in the template tree and are installed with mode `0755`. + +`render-agent-kit.py` treats `.specify` as a project seed, not as generated +client state: + +- The personal-stack repo-root `.specify` tree is committed. Its scripts and + templates mirror the vendored scaffold; its memory directory carries the real + project constitution. +- The repo-local `.specify/memory/constitution.md` is committed and hand-edited. + It is the personal-stack constitution. Do not render over it; edit that file + directly when governance changes. +- The generic `.specify/templates/constitution-template.md` remains a scaffold + template for future projects. +- Project-scope installs seed `.specify` under `AGENT_KIT_PROJECT_ROOT` or + `$PWD`. The constitution is written only when absent; the vendored scripts and + templates are refreshed from the installer bundle. +- `.specify` is intentionally not tracked for uninstall. `install.sh + --uninstall` removes agent client files, but never removes a project's Spec + Kit scaffold or specs. +- Runner workspaces are also seeded from the same scaffold. The agent runner + image copies `templates/repo/.specify` to `/opt/agent-kit/sdd`, and the + runner entrypoint seeds workspace repositories from `AGENT_KIT_SDD_SOURCE`. + +Spec Kit commands are dot-form commands: `/speckit.specify`, +`/speckit.clarify`, `/speckit.plan`, `/speckit.tasks`, `/speckit.analyze`, +`/speckit.implement`, `/speckit.checklist`, `/speckit.constitution`, and +`/speckit.taskstoissues`. They ship through `install.sh` for both `--scope user` +and `--scope project`. Claude receives slash-command Markdown under +`commands/speckit.*.md`; Codex receives matching `speckit-*` skills. The +user-scope `/speckit.specify` flow bootstraps a minimal `.specify` tree in the +current project when it is absent and does not overwrite existing Spec Kit files. + Run the read-only doctor when debugging runner memory, MCP, or installer drift: