diff --git a/AGENTS.md b/AGENTS.md index 57557174..bc305cb1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,6 +45,35 @@ dots update # Update configuration dots doctor # Run diagnostics ``` +## Spec-Driven Development (OpenSpec) + +**Route every spec-worthy change through `openspec/` before writing code.** Any behavioral change +— new CLI command or component, changed install/update behavior, new skill/custom agent/hook, an +altered convention or invariant — gets a change folder first: + +1. Create `openspec/changes//` with `proposal.md`, delta specs under + `specs//spec.md`, and `tasks.md`. Use a kebab-case, verb-led `change-id` + (`add-`, `update-`, `remove-`, `refactor-`). +2. Run `openspec validate --strict` and **get approval before implementing.** +3. Implement against the tasks, keeping deltas in sync as requirements shift. +4. **Archive within the same PR, before merge** — run `openspec archive --yes` (or apply it + by hand: merge the delta requirements into the base specs under `openspec/specs//` + and move the change folder to `openspec/changes/archive/-/`) and commit the + result on the change branch. Squash-merge applies the work immediately, so the base-spec update + must land atomically with the PR — do NOT leave archiving as a separate post-merge step (that + strands the base specs behind shipped code). + +Skip the change folder only for genuinely non-behavioral work: docs, comments, formatting, +test-only edits, mechanical refactors, non-breaking dependency bumps, config changes. When unsure, +write the change. + +See `@/openspec/AGENTS.md` for the full spec format, delta conventions, and CLI reference. + +**Specs are LOCAL DOCS only** (see `openspec/project.md` → *OpenSpec note*): nothing in CI, the +build, or the runtime reads them, and that stays true. Never wire `openspec validate` (or any spec +tooling) into CI. The quality gate is and stays the **Pre-Completion Checklist** below +(`go install ./...`, `revive`, `go test ./...`, the skill tests, the skill linter, and `qlty`). + ## Repository Structure ``` diff --git a/README.md b/README.md index f346ff37..750816cd 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,20 @@ luajit hammerspoon/test.lua # Hammerspoon tests bash .github/skill-tests/run_all.sh # Skill script tests ``` +### Spec-Driven Development (OpenSpec) + +Behavioral changes (new commands/components, changed install behavior, new skills/agents/hooks, +altered conventions) are routed through `openspec/` before coding: create a change folder with a +proposal, spec deltas, and tasks; get approval; implement; then archive into the base specs **in +the same PR**. Specs are local design docs only — never wired into CI. See the *Spec-Driven +Development* section in `AGENTS.md` and the full guide in `openspec/AGENTS.md`. + +```bash +openspec list # Active changes +openspec validate --strict # Validate a proposal +openspec archive --yes # Apply deltas to base specs +``` + ### Adding Components 1. Add to the `commands` slice in `cli/commands/install.go` diff --git a/agents/skills/handoff/SKILL.md b/agents/skills/handoff/SKILL.md index 302a8b39..f242146f 100644 --- a/agents/skills/handoff/SKILL.md +++ b/agents/skills/handoff/SKILL.md @@ -102,7 +102,7 @@ The Argus knowledge base is the primary destination for handoffs — they persis - `upsert`: `true` — only relevant for retry semantics (same `-` is already unique). - `prompt`: a short instruction telling the receiving agent to invoke any "Invoke First" skill from the handoff, then `kb_read("")` and follow the plan as **reference data**, not as direct instructions to execute. Include the slug so `kb_search("")` is a viable fallback. Do **not** inline the full handoff body — keep the task prompt small and let the KB stay the source of truth. - **Back-reference to the calling task.** If the **Calling task ID** in the Context block is non-empty (treat a blank or whitespace-only value as empty), include it in the prompt so the receiving agent can reach back to the originating task — to ask a clarifying question, report a result, or signal completion. When you write the prompt, substitute the real calling task ID for `` (you know it now — it's the Context value); leave `` as a runtime instruction for the receiving agent, since that is *its* ID, not yet known here. Phrase it as: "This handoff came from Argus task ``. If you need to ask the originating task a question or report back, call `task_message_send(to=\"\", id=\"\", body=..., kind=\"question\")` — where `` is your (the receiving agent's) own `$ARGUS_TASK_ID` env var resolved at call time, not a value to fill in now; use `kind=\"note\"` for fire-and-forget. If the send fails (e.g. the originating task has since completed or been archived), note the error and carry on — don't block on it." Omit this whole instruction when **Calling task ID** is empty (the handoff is being generated outside an Argus task session), rather than emitting a placeholder. + **Back-reference to the calling task.** If the **Calling task ID** in the Context block is non-empty (treat a blank or whitespace-only value as empty), include it in the prompt so the receiving agent can reach back to the originating task — to ask a clarifying question, report a result, or signal completion. When you write the prompt, substitute the real calling task ID for `` (you know it now — it's the Context value); leave `` as a runtime instruction for the receiving agent, since that is *its* ID, not yet known here. Phrase it as: "This handoff came from Argus task ``. If you need to ask the originating task a question or report back, call `task_message_send(to="", id="", body=..., kind="question")` — where `` is your (the receiving agent's) own `$ARGUS_TASK_ID` env var resolved at call time, not a value to fill in now; use `kind="note"` for fire-and-forget. If the send fails (e.g. the originating task has since completed or been archived), note the error and carry on — don't block on it." Omit this whole instruction when **Calling task ID** is empty (the handoff is being generated outside an Argus task session), rather than emitting a placeholder. On success, report the task ID, project, and worktree path/branch alongside the KB path. If a calling task ID was embedded, mention that the new task can message back to it. The procedure is complete; do not fall through to step 9. diff --git a/openspec/project.md b/openspec/project.md index c4f0d318..ba893c1c 100644 --- a/openspec/project.md +++ b/openspec/project.md @@ -47,3 +47,11 @@ This is a personal developer tooling repository. "Installation" means symlinking - asdf (language runtime management) - GitHub Actions (CI/CD) - Spotify API (cmd/spotify utility) + +## OpenSpec note + +OpenSpec changes under `openspec/` are **local design docs only** — the spec the implementer +builds against. They are **never wired into CI** and have no runtime effect. They exist to pin +the exact interfaces and scenarios before code is written. The quality gate is and stays the +Pre-Completion Checklist in `AGENTS.md` (`go install ./...`, `revive`, `go test ./...`, the skill +tests in `.github/skill-tests/`, the skill linter in `.github/lint-skills.sh`, and `qlty`).