diff --git a/AGENTS.md b/AGENTS.md index 4ba5261..ff8c4ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,9 +7,12 @@ GitHub Issues + local sprint execution files for Claude Code / Codex. ``` skills/ spec-charter/ - SKILL.md ← CHARTER.md create/amend + reassess contract + SKILL.md ← spec/charter.md create/amend + reassess contract references/ ← Detailed specs (on-demand) scripts/ ← Deterministic helpers (node) + spec-system-map/ + SKILL.md ← spec/system-map.md high-level system map contract + templates/ ← Runtime system-map template spec-grill/ SKILL.md ← spec/capabilities.md grill contract references/ ← Detailed specs (on-demand) @@ -36,6 +39,10 @@ GitHub (what) ↔ gh CLI ↔ backlog/sprints/ (how + context) backlog/tasks/ (thin mirror) ``` +## Project Spec Home + +Durable project specs live under `spec/`: `charter.md`, `system-map.md`, and `capabilities.md`. Root `CHARTER.md` is legacy fallback only. + ## Working on This Project - All content in English (Korean in trigger keywords only) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2561f32..4c92634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ Each entry links the GitHub issue (the canonical spec) and the merge PR (the shi ### Changed -- Split the old `backlog-charter` surface into the spec-series skills `spec-charter` and `spec-grill`. `spec-charter` owns `CHARTER.md` create/amend/reassess; `spec-grill` owns `spec/capabilities.md` capability-contract authoring. Closes [#157](https://github.com/sungjunlee/dev-backlog/issues/157), [#158](https://github.com/sungjunlee/dev-backlog/issues/158), and [#159](https://github.com/sungjunlee/dev-backlog/issues/159). +- Consolidated active spec-series artifacts under `spec/`: `spec/charter.md`, `spec/system-map.md`, and `spec/capabilities.md`, with root `CHARTER.md` retained only as a legacy fallback. Added `spec-system-map`, `spec/README.md`, dogfood `spec/system-map.md`, and script/docs compatibility updates. Closes [#161](https://github.com/sungjunlee/dev-backlog/issues/161), [#162](https://github.com/sungjunlee/dev-backlog/issues/162), [#163](https://github.com/sungjunlee/dev-backlog/issues/163), [#164](https://github.com/sungjunlee/dev-backlog/issues/164), and [#165](https://github.com/sungjunlee/dev-backlog/issues/165). +- Split the old `backlog-charter` surface into the spec-series skills `spec-charter` and `spec-grill`. `spec-charter` owns charter create/amend/reassess; `spec-grill` owns `spec/capabilities.md` capability-contract authoring. Closes [#157](https://github.com/sungjunlee/dev-backlog/issues/157), [#158](https://github.com/sungjunlee/dev-backlog/issues/158), and [#159](https://github.com/sungjunlee/dev-backlog/issues/159). ## [0.5.0] — 2026-05-22 diff --git a/CLAUDE.md b/CLAUDE.md index 1843743..bc4d126 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,9 +9,12 @@ GitHub Issues + local sprint execution files for Claude Code / Codex. ```text skills/ spec-charter/ - SKILL.md ← CHARTER.md create/amend + reassess contract + SKILL.md ← spec/charter.md create/amend + reassess contract references/ ← Amendment, alignment, objective, reassess specs - templates/ ← Runtime CHARTER.md template + templates/ ← Runtime charter template + spec-system-map/ + SKILL.md ← spec/system-map.md high-level system map contract + templates/ ← Runtime system-map template spec-grill/ SKILL.md ← spec/capabilities.md grill contract references/ ← Capability heuristics + spec-system research @@ -43,6 +46,10 @@ GitHub (what) ↔ gh CLI ↔ backlog/sprints/ (how + context) backlog/tasks/ (thin mirror) ``` +## Project Spec Home + +Durable project specs live under `spec/`: `charter.md`, `system-map.md`, and `capabilities.md`. Root `CHARTER.md` is legacy fallback only. + ## Working on This Project - All content in English (Korean in trigger keywords only) diff --git a/README.md b/README.md index a01b0cf..b184067 100644 --- a/README.md +++ b/README.md @@ -98,10 +98,11 @@ Optional spec-series setup: ```text /spec-charter create +/spec-system-map /spec-grill ``` -`spec-charter` creates the project-wide `CHARTER.md` axis. On existing repos, follow it with `spec-grill` to author `spec/capabilities.md`, the middle layer of capability contracts and Hard Constraints. +`spec-charter` creates the project-wide `spec/charter.md` axis. On existing repos, follow it with `spec-system-map` for `spec/system-map.md` and `spec-grill` for `spec/capabilities.md`. The spec index lives at [spec/README.md](spec/README.md). For the detailed sprint contract, section semantics, and full script inventory, see [skills/dev-backlog/SKILL.md](skills/dev-backlog/SKILL.md). diff --git a/docs/spec-system-design.md b/docs/spec-system-design.md index af31572..52a7fc1 100644 --- a/docs/spec-system-design.md +++ b/docs/spec-system-design.md @@ -1,7 +1,7 @@ # Spec System Design (v0.1) **Status:** Approved (M tier) · **Date:** 2026-05-23 · **Author:** session capture -**Supersedes:** — · **Related:** [`CHARTER.md`](../CHARTER.md), [`skills/spec-charter/`](../skills/spec-charter/), [`skills/spec-grill/`](../skills/spec-grill/) +**Supersedes:** - · **Related:** [`spec/charter.md`](../spec/charter.md), [`spec/system-map.md`](../spec/system-map.md), [`skills/spec-charter/`](../skills/spec-charter/), [`skills/spec-system-map/`](../skills/spec-system-map/), [`skills/spec-grill/`](../skills/spec-grill/) A layered, brownfield-friendly project spec system that survives multi-day autonomous agent execution without rubber-stamping itself into uselessness. This doc captures the current architecture, durable policy, research grounding, and historical implementation evidence. @@ -9,16 +9,17 @@ A layered, brownfield-friendly project spec system that survives multi-day auton ## Problem -`CHARTER.md` works as a 5-min reference axis (north star + verifiable predicates + immutable decisions). But on real projects two gaps appear: +`spec/charter.md` works as a 5-min reference axis (north star + verifiable predicates + immutable decisions). But on real projects three gaps appear: 1. **No middle layer.** Between "the whole project's north star" and "this sprint's task list" there is no place to write *"this capability does X for the user, within these boundaries, and never violates Y."* Mid-day autonomous agents either over-interpret the charter or fly blind on per-capability specifics. 2. **No live-feedback path.** Learnings from completed work (a working pattern, a measured number, a discovered constraint) accrue in PR descriptions and disappear from the agent's reachable context within a sprint or two. +3. **No stable system-shape map.** Generic `ARCHITECTURE.md` files often mix whole-system maps, module notes, ADRs, and runbooks. `spec/system-map.md` is the narrower high-level map. For autonomous runs that span days, this means: setpoint exists, sensor doesn't, controller drifts. Research-grounded framing in [Research](#research-grounding) below. ## Goals -- Layered: north star (CHARTER) → capability specs (new) → live learnings (new) +- Layered: north star (`spec/charter.md`) -> system map (`spec/system-map.md`) -> capability specs (`spec/capabilities.md`) -> live learnings - Works greenfield and brownfield (signal extraction from existing repos) - Detail level calibrated to *help* AI agents, not constrain them into Goodhart's law - Lower layers can update live without human edit, via structurally bounded channels @@ -28,7 +29,7 @@ For autonomous runs that span days, this means: setpoint exists, sensor doesn't, ## Non-Goals -- Replace `CHARTER.md` (this extends it) +- Replace `spec/charter.md` (this extends it) - Per-capability file proliferation on day 1 (strangler-fig path preserved, not paved) - ADR ceremony before decision volume justifies it - Autonomous spec self-editing by working agents (adversarial-Goodhart risk, see Research) @@ -40,9 +41,11 @@ For autonomous runs that span days, this means: setpoint exists, sensor doesn't, ``` repo/ -├─ CHARTER.md ← Tier 1 (frozen-ish, 5-min read, north star) ├─ spec/ -│ └─ capabilities.md ← NEW: layered capability spec, single file +│ ├─ README.md ← project spec index +│ ├─ charter.md ← Tier 1 (frozen-ish, 5-min read, north star) +│ ├─ system-map.md ← high-level system shape, boundaries, flows, invariants +│ └─ capabilities.md ← layered capability spec, single file │ # │ # ## Capability: │ # Goal (frozen — amend-gated) @@ -65,7 +68,8 @@ Agents need room to reason in prose. They also need stable coordinates when anot ``` Free-form reasoning - CHARTER prose + charter prose + system-map prose capability Goal / Scope / Behaviors sprint Plan / Running Context @@ -83,31 +87,33 @@ The rule: constrain the address, not the thought. `component:` is a routing hand | Layer | Who writes | When | Gate | |---|---|---|---| -| `CHARTER.md` Problem/Approach/Non-Goals | human via `spec-charter amend` | rarely | Tier 1 gate (existing) | -| `CHARTER.md` Objectives | human via amend; status advance proof-gated | when an objective is added/removed/proven | Tier 2 gate (existing) | -| `CHARTER.md` Decisions | append-only | when a non-trivial cross-cutting decision is made | Tier 3 (existing) | +| `spec/charter.md` Problem/Approach/Non-Goals | human via `spec-charter amend` | rarely | Tier 1 gate | +| `spec/charter.md` Objectives | human via amend; status advance proof-gated | when an objective is added/removed/proven | Tier 2 gate | +| `spec/charter.md` Decisions | append-only | when a non-trivial cross-cutting decision is made | Tier 3 | +| `spec/system-map.md` system shape/boundaries/flows/invariants/pointers | human via `spec-system-map` | when project-wide structure changes | high-level-only gate; demote subsystem details | | `spec/capabilities.md` Goal/Scope/Behaviors/HardConstraints per capability | human via `spec-grill` | when a capability's contract changes | challenge + confirm + apply | | `spec/capabilities.md` `## Learnings` blocks | **`dev-relay/scripts/append-learnings.js`** | end of every successful relay run with a primary `component:` tag | structurally bounded append between magic markers; rejects anything else | -| `spec/capabilities.md` `## Decisions` blocks | human | when a capability-level decision is made | append-only by convention; promote to CHARTER Tier 3 if cross-cutting | +| `spec/capabilities.md` `## Decisions` blocks | human | when a capability-level decision is made | append-only by convention; promote to charter Tier 3 if cross-cutting | ### Reassess source-of-truth map | Artifact | Owns | Does not own | |---|---|---| -| `skills/spec-charter/SKILL.md` | CHARTER create/amend and report-only reassess dispatch contract | capability authoring details | +| `skills/spec-charter/SKILL.md` | `spec/charter.md` create/amend and report-only reassess dispatch contract | capability authoring details | | `skills/spec-charter/references/reassess.md` | operational reassess procedure: evidence order, report shape, recommendation rules, Learning Actions, stale-spec failure modes | durable naming policy or historical build notes | -| `skills/spec-grill/SKILL.md` | `spec/capabilities.md` authoring, brownfield signal admission, and 3-axis predicate test | CHARTER mutation rules | +| `skills/spec-system-map/SKILL.md` | `spec/system-map.md` create/amend flow and high-level-only boundary | charter mutation rules or capability contracts | +| `skills/spec-grill/SKILL.md` | `spec/capabilities.md` authoring, brownfield signal admission, and 3-axis predicate test | charter mutation rules | | `docs/spec-system-design.md` | durable design policy: lifecycle, naming policy, mutation discipline, split/defer triggers, historical rationale | step-by-step skill execution details | ### Stale-spec lifecycle Accepted specs are useful only while they still match product reality. The system therefore needs a small reassessment loop, but not autonomous self-editing: -1. **Setpoint:** `CHARTER.md` and `spec/capabilities.md` describe the accepted project/capability contracts. +1. **Setpoint:** `spec/charter.md`, `spec/system-map.md`, and `spec/capabilities.md` describe the accepted project/system/capability contracts. 2. **Sensor:** relay and sprint execution append bounded observations as `## Learnings` or sprint context. 3. **Diagnosis:** deterministic scripts report structural signals first (`capabilities-doctor.js`, `component-lint.js`); `spec-charter reassess` turns those signals into a report. 4. **Human gate:** accepted changes route through `spec-charter amend`, `spec-grill `, or a separate user-approved Learning Action. -5. **No silent controller:** reassess may recommend edits, promotion, or archival, but it must not edit CHARTER direction, capability Goal/Scope/Behaviors/Hard Constraints, Decisions, or Learnings while diagnosing. +5. **No silent controller:** reassess may recommend edits, promotion, or archival, but it must not edit charter direction, system-map structure, capability Goal/Scope/Behaviors/Hard Constraints, Decisions, or Learnings while diagnosing. This keeps freedom where agents need it (reasoning over evidence) and control where the spec could otherwise rationalize itself into noise. @@ -125,7 +131,7 @@ Learning Action is the canonical umbrella term for accepted cleanup after reasse - **Keep inline** when a recent Learning is still useful startup context. - **Promote to capability Decisions** when it describes a durable capability-level rule. -- **Promote to CHARTER Decisions** when it changes the project-wide axis. +- **Promote to charter Decisions** when it changes the project-wide axis. - **Archive outside the hot `spec/capabilities.md` path** when it is useful history but no longer startup context. Reassess may recommend a Learning Action, but diagnosis itself does not rewrite Learnings. The edit is a separate user-approved manual change. @@ -134,10 +140,11 @@ Reassess may recommend a Learning Action, but diagnosis itself does not rewrite The current callable spec-series surface is: -- `spec-charter` — create/amend `CHARTER.md` and run report-only reassess. +- `spec-charter` — create/amend `spec/charter.md` and run report-only reassess. +- `spec-system-map` — create/amend `spec/system-map.md` as the high-level project map. - `spec-grill` — create/refine `spec/capabilities.md` from repo signals. -This split exists because existing-repo onboarding naturally needs `CHARTER.md` first and capability contracts next; hiding the second step behind a charter-named `grill` mode made the intended path hard to discover. +This split exists because existing-repo onboarding naturally needs charter first, then a high-level system map, then capability contracts; hiding later steps behind a charter-named mode made the intended path hard to discover. The names `spec-reassess` and `spec-learn` are reserved/non-callable future split candidates. They should appear only in naming-policy discussion until a split is justified by concrete signal: @@ -169,11 +176,11 @@ From Langosco et al. 2022 (goal misgeneralization) + Manheim & Garrabrant 2018 ( ### 2. Control-theory framing -A multi-day autonomous run with no in-loop ground-truth check is **open-loop control** and will drift. The CHARTER alone is a setpoint without a sensor. `## Learnings` is the minimum-viable sensor: each run feeds back a one-line ground-truth observation that the next run can read. +A multi-day autonomous run with no in-loop ground-truth check is **open-loop control** and will drift. The charter alone is a setpoint without a sensor. `## Learnings` is the minimum-viable sensor: each run feeds back a one-line ground-truth observation that the next run can read. ### 3. Spec-language stability discipline -Across OKRs, ADRs, Constitutional AI, and TLA+: the design choice most copied is **immutability after acceptance** (Nygard). `CHARTER.md` Tier 3 already enforces this; `spec/capabilities.md` extends it via append-only `## Learnings` and `## Decisions` sections. +Across OKRs, ADRs, Constitutional AI, and TLA+: the design choice most copied is **immutability after acceptance** (Nygard). `spec/charter.md` Tier 3 already enforces this; `spec/capabilities.md` extends it via append-only `## Learnings` and `## Decisions` sections. ### The 3-axis predicate test (for grill mode) @@ -188,12 +195,12 @@ Before any capability Behavior or Hard Constraint is committed: | Deferred | Rationale | Promotion trigger | |---|---|---| | Per-capability files (`spec/components/*.md`) | YAGNI; a compact single file is easier to read and route through while under budget | `spec/capabilities.md` > 500 lines, >15 capabilities, or ownership demands | -| ADR directory (`spec/decisions/*.md`) | CHARTER Decisions + per-capability `## Decisions` suffice | Cross-cutting decision volume > 10 in a quarter | +| ADR directory (`spec/decisions/*.md`) | Charter Decisions + per-capability `## Decisions` suffice | Cross-cutting decision volume > 10 in a quarter | | Adversarial grill subagent (separate context) | Single-context grill is testable now; subagent dispatch is an innovation token | Observed self-rationalization in working agent | | Cross-capability dependency graph | Over-engineering; readable from prose | Multiple capability authors complain about silent coupling | | Per-capability `revision:` / `last_amended:` | `git blame` is the source of truth | Auditing demand from outside the team | | Automated reassess hooks in sprint-close / relay-merge | Manual report-only reassess must prove useful before hooks add noise to execution paths | Repeated manual reassess reports produce the same actionable recommendation | -| Auto-promotion of Learnings into Decisions or CHARTER | Promotion changes accepted authority and must stay human-gated | Explicit user asks for a promotion pass and reviews the proposed diff | +| Auto-promotion of Learnings into Decisions or charter | Promotion changes accepted authority and must stay human-gated | Explicit user asks for a promotion pass and reviews the proposed diff | --- @@ -205,7 +212,7 @@ These are current policy anchors carried forward from implementation. They are n - **D3** `spec/capabilities.md` size warning threshold — resolved: warn above 12 capabilities or 400 lines; recommend split above 500 lines, 15 capabilities, or ownership-boundary pressure. - **D4** Multi-component sprint task: resolved to one primary capability slug. Secondary touches are prose, not routing metadata. - **D5** `component:` tag freeform string vs declared-only enum? Resolved to declared capability slug, with `component-lint.js` catching typos before they reach Learnings. -- **D6** Spec-series command surface — resolved: `spec-charter` owns `CHARTER.md`; `spec-grill` owns `spec/capabilities.md`; `spec-reassess` remains reserved until report-only usage justifies a split. +- **D6** Spec-series command surface — resolved: `spec-charter` owns `spec/charter.md`; `spec-system-map` owns `spec/system-map.md`; `spec-grill` owns `spec/capabilities.md`; `spec-reassess` remains reserved until report-only usage justifies a split. --- @@ -237,7 +244,7 @@ PR-1: template + SKILL.md extension (no executable code) ├─ docs/spec-system-design.md (this file) ├─ skills/spec-grill/templates/capabilities.md (NEW) ├─ skills/spec-grill/SKILL.md (capability grill contract) - └─ CHARTER.md (no change; just verify alignment) + └─ spec/charter.md (no change; just verify alignment) ↓ (dogfood: write spec/capabilities.md for dev-backlog itself) ↓ @@ -288,15 +295,15 @@ This section records calibration evidence. It should inform future changes, but The most authentic test of this spec system is applying it to projects we already understand: -1. **dev-backlog itself** (greenfield-ish — `CHARTER.md` exists, no capabilities file yet). Authors: us. Validates greenfield grill + the layered shape on a project we know cold. -2. **dev-relay** (brownfield — established code, no CHARTER yet). Validates the full brownfield path: `extract-signals.js` → grill → `spec/capabilities.md` written end-to-end. Also exercises live-update since dev-relay *is* the relay-merge surface. +1. **dev-backlog itself** (greenfield-ish — `spec/charter.md` exists, no capabilities file yet). Authors: us. Validates greenfield grill + the layered shape on a project we know cold. +2. **dev-relay** (brownfield — established code, no charter yet). Validates the full brownfield path: `extract-signals.js` -> grill -> `spec/capabilities.md` written end-to-end. Also exercises live-update since dev-relay *is* the relay-merge surface. 3. **Large-repo fixture** — a deterministic tamgu_note-shaped fixture with many feature folders and workflow commit scopes. Protects against treating feature count as capability count without depending on a private checkout. 4. **(optional, after both)** A real product repo from outside this workspace. Highest signal but lowest control. Worth doing once internal dogfood looks healthy. 5. **Manual reassess pass** — run `spec-charter reassess` on dev-backlog and one larger repo shape before adding sprint-close or relay-merge hooks. The test is whether the report produces a useful next action without creating churn. Each dogfood produces: - A `spec/capabilities.md` in the target repo -- Reusable signal feedback for spec-system v0.2 (more findings, like the CHARTER dogfood pattern that produced #93–#98) +- Reusable signal feedback for spec-system v0.2 (more findings, like the charter dogfood pattern that produced #93-#98) ### Reassess MVP dogfood note (2026-05-24) @@ -313,13 +320,13 @@ Decision: existing doctor/lint JSON is enough for the MVP reassess mode to produ --- -## CHARTER alignment (self-check) +## Charter alignment (self-check) -This design advances dev-backlog's own CHARTER Objectives: +This design advances dev-backlog's own charter Objectives: -- **O3 (active):** `<5-min reference axis usable` — capability specs *extend* the 5-min property below CHARTER. Not advance to validated on this; one more independent project required. +- **O3 (active):** `<5-min reference axis usable` — capability specs *extend* the 5-min property below the charter. Not advance to validated on this; one more independent project required. - **O4 (active):** `drift detectable without manual triage` — `## Learnings` + `component-lint.js` are direct drift-detection surfaces. Same proof-gate. - **O5 (deferred):** `auto-reassess wired into relay-merge / sprint completion` — report-only `spec-charter reassess` is the manual precursor. Do not wire hooks until manual reassess repeatedly produces useful, low-noise recommendations. -- **O6 (deferred):** `/goal completion-condition auto-emission from CHARTER + active sprint` — unchanged. +- **O6 (deferred):** `/goal completion-condition auto-emission from charter + active sprint` — unchanged. -Status advance for any of these is gated on independent-project proof, per CHARTER Tier 2 discipline. +Status advance for any of these is gated on independent-project proof, per charter Tier 2 discipline. diff --git a/skills/backlog-triage/SKILL.md b/skills/backlog-triage/SKILL.md index 7292d19..29d95e2 100644 --- a/skills/backlog-triage/SKILL.md +++ b/skills/backlog-triage/SKILL.md @@ -27,12 +27,12 @@ Sibling skill to dev-backlog, not a replacement. dev-backlog is the execution hu ### Phase 1 — Report (default, no mutations) 1. **Collect** open issues → snapshot JSON (one `gh` fetch per run) -2. **Analyze** — classification, relationships, stale/obsolete signals, and Alignment Check when repo-root `CHARTER.md` exists +2. **Analyze** — classification, relationships, stale/obsolete signals, and Alignment Check when `spec/charter.md` or legacy root `CHARTER.md` exists 3. **Render** — one markdown report with anchored proposals Every script in this phase is read-only. Running any number of times is safe. The snapshot is the canonical artifact; all downstream analysis consumes it via `--snapshot PATH` (no re-fetch). -Alignment Check is prompt-driven, not a `triage-*.js` script: when `CHARTER.md` exists, map open issues to Objectives using `../spec-charter/references/alignment.md` and emit an `## Alignment` report section. When `CHARTER.md` is absent, skip this step entirely and keep the existing report shape. +Alignment Check is prompt-driven, not a `triage-*.js` script: read `spec/charter.md` first, fall back to legacy root `CHARTER.md`, then map open issues to Objectives using `../spec-charter/references/alignment.md` and emit an `## Alignment` report section. When both files are absent, skip this step entirely and keep the existing report shape. ### Phase 2 — Apply (opt-in, explicit) @@ -128,8 +128,8 @@ Active Objectives with no open issue advancing them (medium severity). ### Contradictions Issues that violate a Non-Goal (high severity). -### Proposed CHARTER changes -Seed proposals for `spec-charter` amend; triage does not mutate `CHARTER.md`. +### Proposed Charter Changes +Seed proposals for `spec-charter` amend; triage does not mutate the charter. ## Apply Checklist Consolidated list of every anchored action for scan-and-check review. The apply step parses @@ -147,7 +147,7 @@ source sections above both count as acceptance surfaces (see `references/apply.m | Milestone lifecycle, monthly progress issue | dev-backlog | | AC checkboxes inside issue bodies (`AC:BEGIN`/`END`) | dev-backlog | | Open-issue classification, relationships, stale flags | backlog-triage | -| CHARTER alignment of open issues | backlog-triage (report; `CHARTER.md` mutations stay with `spec-charter`) | +| Charter alignment of open issues | backlog-triage (report; charter mutations stay with `spec-charter`) | | Priority / milestone **proposals** | backlog-triage (report) | | Priority / milestone **mutations** | backlog-triage (`--apply`) | | Post-triage sprint planning | dev-backlog (reads report, edits sprint file) | @@ -158,7 +158,7 @@ Recommended cadence: run backlog-triage weekly or bi-weekly. Feed the report's M ## Process -**Collect → Analyze → Report.** One `gh` fetch, one snapshot, downstream scripts consume it via `--snapshot`. Re-fetching in each script is a bug — it creates drift across signals. During Analyze, run the prompt-driven Alignment Check when `CHARTER.md` is present; its Proposed CHARTER changes feed `spec-charter` amend and are not applied by `triage-apply.js`, which only mutates GitHub issues. +**Collect -> Analyze -> Report.** One `gh` fetch, one snapshot, downstream scripts consume it via `--snapshot`. Re-fetching in each script is a bug; it creates drift across signals. During Analyze, run the prompt-driven Alignment Check when `spec/charter.md` or legacy root `CHARTER.md` is present; its Proposed Charter Changes feed `spec-charter` amend and are not applied by `triage-apply.js`, which only mutates GitHub issues. **Review the report.** Read each proposal. Check the ones you accept (flip `[ ]` → `[x]`). Leave rejected ones unchecked. Do not delete anchor comments; unchecked anchors are ignored by apply. @@ -193,7 +193,7 @@ Flags on individual scripts override config. - `references/relationships.md` — mention / blocks / depends-on / duplicate heuristics, evidence format - `references/stale.md` — obsolescence signals, thresholds, suggested-action grammar - `references/apply.md` — anchor grammar, parse rules, idempotency contract, apply-log schema -- `../spec-charter/references/alignment.md` — prompt-driven CHARTER work↔objective mapping and drift severity rules +- `../spec-charter/references/alignment.md` — prompt-driven charter work↔objective mapping and drift severity rules --- diff --git a/skills/dev-backlog/SKILL.md b/skills/dev-backlog/SKILL.md index 599e035..f2b4e33 100644 --- a/skills/dev-backlog/SKILL.md +++ b/skills/dev-backlog/SKILL.md @@ -11,7 +11,7 @@ metadata: README covers install and human quick start. This skill file is the execution contract for agents: file roles, sprint structure, process, and script behavior. -Related skills: [`spec-charter`](../spec-charter/SKILL.md) for the optional `CHARTER.md` reference axis, [`spec-grill`](../spec-grill/SKILL.md) for `spec/capabilities.md`, and [`backlog-triage`](../backlog-triage/SKILL.md) for weekly backlog grooming before you plan the next sprint. +Related skills: [`spec-charter`](../spec-charter/SKILL.md) for the optional `spec/charter.md` reference axis, [`spec-system-map`](../spec-system-map/SKILL.md) for `spec/system-map.md`, [`spec-grill`](../spec-grill/SKILL.md) for `spec/capabilities.md`, and [`backlog-triage`](../backlog-triage/SKILL.md) for weekly backlog grooming before you plan the next sprint. Two layers, each with a clear job: @@ -61,7 +61,7 @@ backlog/ ## Sprint File Format The sprint file in `backlog/sprints/` is the execution hub. One file per sprint. -The `objectives` frontmatter field lists the `CHARTER.md` Objective IDs this sprint advances; it is `[]` when the project has no `CHARTER.md`. +The `objectives` frontmatter field lists the charter Objective IDs this sprint advances; it is `[]` when the project has no `spec/charter.md` or legacy root `CHARTER.md`. The `component` field is one primary routing handle from `spec/capabilities.md`. It names the single capability whose `## Learnings` block receives an entry when a relay run merges. Empty string means no live-update target. If a sprint touches secondary areas, mention them in the sprint body or Running Context instead of adding more frontmatter values. ```markdown @@ -206,7 +206,7 @@ Task files get AC checkboxes updated during work. Everything else (notes, decisi **Orient** → Read `_context.md` + active sprint file. No sprint? → Plan. All done? → Complete. -**Plan** → If repo-root `CHARTER.md` exists, read its `active` Objectives first, project them onto not-yet-done work, and record advanced IDs in `objectives:`. If absent, plan as before and leave `objectives: []`. +**Plan** -> If `spec/charter.md` exists, read its `active` Objectives first; otherwise fall back to legacy root `CHARTER.md`. Project Objectives onto not-yet-done work and record advanced IDs in `objectives:`. If both are absent, plan as before and leave `objectives: []`. **Work** → Option A (do it yourself): read batch → implement → verify AC → commit `Fixes #N`. Option B (delegate): follow the relay skill's dispatch process. @@ -238,6 +238,6 @@ All scripts live in `${CLAUDE_SKILL_DIR}/scripts/` (the skill's own directory, n - `scripts/progress-sync.js [--month YYYY-MM] [--dry-run] [--json] [--relay-manifest PATH] [--finalize]` — Sync the monthly GitHub Progress issue. `--finalize` adds the month-end block and closes the target month's issue idempotently. - `scripts/sprint-close.sh [backlog-dir] [--dry-run] [--close-milestone]` — Close active sprint: set completed, move tasks, remind about context promotion - `scripts/context-hook.sh [backlog-dir]` — One-line sprint summary for Claude Code PreToolUse hook (always exits 0) -- `scripts/objectives-check.js [--sprints-dir PATH] [--charter PATH] [--json]` — Verify every `objectives:` ID in sprint files still exists in `CHARTER.md` with an actionable (non-deferred) status. Graceful no-op when `CHARTER.md` is absent. +- `scripts/objectives-check.js [--sprints-dir PATH] [--charter PATH] [--json]` — Verify every `objectives:` ID in sprint files still exists in `spec/charter.md` (or legacy root `CHARTER.md`) with an actionable (non-deferred) status. Graceful no-op when both are absent. - `scripts/component-lint.js [--sprints-dir PATH] [--capabilities PATH] [--json]` — Verify every `component:` value in sprint files resolves to one declared capability in `spec/capabilities.md`. Comma-separated multi-component values fail because `component:` is the primary routing handle; put secondary touches in sprint prose. Graceful no-op when `spec/capabilities.md` is absent. - `scripts/capabilities-doctor.js [--capabilities PATH] [--json] [--strict]` — Check `spec/capabilities.md` compactness: capability count, line count, per-capability size, Learnings marker health, and inline Learnings budget. Default mode warns; `--strict` exits non-zero on hard split triggers or malformed Learnings markers. diff --git a/skills/dev-backlog/references/process.md b/skills/dev-backlog/references/process.md index 14738e6..330f3b1 100644 --- a/skills/dev-backlog/references/process.md +++ b/skills/dev-backlog/references/process.md @@ -25,7 +25,7 @@ Two files at most (`_context.md` + active sprint), full picture. When starting a new sprint: 0. If an active sprint exists, set its `status: completed` and write a final Progress entry first. -1. If repo-root `CHARTER.md` exists, read its `active` Objectives first. Derive the sprint as the projection of those objectives onto not-yet-done work, and record the advanced Objective IDs in sprint frontmatter `objectives: [O1, O3]`. If absent, plan exactly as before and leave `objectives: []`. +1. If `spec/charter.md` exists, read its `active` Objectives first. If it is absent, fall back to legacy root `CHARTER.md`. Derive the sprint as the projection of those objectives onto not-yet-done work, and record the advanced Objective IDs in sprint frontmatter `objectives: [O1, O3]`. If both are absent, plan exactly as before and leave `objectives: []`. 2. Create GitHub milestone: `gh api repos/{owner}/{repo}/milestones -f title="Sprint W13" -f due_on="2026-03-28"` 3. Assign issues: `gh issue edit --milestone "Sprint W13"` 4. Pull issues to `backlog/tasks/` diff --git a/skills/dev-backlog/scripts/objectives-check.js b/skills/dev-backlog/scripts/objectives-check.js index a360804..176f2db 100644 --- a/skills/dev-backlog/scripts/objectives-check.js +++ b/skills/dev-backlog/scripts/objectives-check.js @@ -1,27 +1,30 @@ #!/usr/bin/env node /** * Verify that every `objectives:` ID referenced by a sprint file still - * exists in CHARTER.md with an actionable status. + * exists in spec/charter.md with an actionable status. * * Usage: ./scripts/objectives-check.js [--sprints-dir PATH] [--charter PATH] [--json] * * Reports two drift classes per sprint: - * - missing : the ID is not in CHARTER.md at all (removed; IDs are never reused) + * - missing : the ID is not in the charter at all (removed; IDs are never reused) * - deferred : the ID exists but is marked [deferred]; sprints should not target * deferred objectives * - * Graceful no-op when CHARTER.md is absent (most projects opt out of CHARTER). + * Graceful no-op when spec/charter.md and legacy CHARTER.md are absent. * * Exit codes: - * 0 no drift found, or CHARTER.md absent + * 0 no drift found, or charter absent * 1 drift found (missing or deferred IDs referenced) */ const fs = require("fs"); const path = require("path"); +const { + CANONICAL_CHARTER_PATH, + resolveCharterPath, +} = require("./spec-paths.js"); const DEFAULT_SPRINTS_DIR = path.join("backlog", "sprints"); -const DEFAULT_CHARTER_PATH = "CHARTER.md"; function usage() { return "Usage: objectives-check.js [--sprints-dir PATH] [--charter PATH] [--json]"; @@ -30,7 +33,7 @@ function usage() { function parseArgs(args) { const options = { sprintsDir: DEFAULT_SPRINTS_DIR, - charterPath: DEFAULT_CHARTER_PATH, + charterPath: null, json: false, }; @@ -120,15 +123,24 @@ function findDrift(sprintFiles, charterObjectives, { readFile = fs.readFileSync function checkObjectives({ sprintsDir = DEFAULT_SPRINTS_DIR, - charterPath = DEFAULT_CHARTER_PATH, + charterPath = null, + repoRoot = process.cwd(), readFile = fs.readFileSync, fileExists = fs.existsSync, readdir = fs.readdirSync, } = {}) { - if (!fileExists(charterPath)) { - return { charterFound: false, charterPath, drift: [], sprintCount: 0 }; + const resolved = resolveCharterPath({ repoRoot, charterPath, fileExists }); + if (!resolved.found) { + return { + charterFound: false, + charterPath: resolved.charterPath, + charterSource: resolved.source, + checkedPaths: resolved.checkedPaths, + drift: [], + sprintCount: 0, + }; } - const charterContent = readFile(charterPath, "utf-8"); + const charterContent = readFile(resolved.charterPath, "utf-8"); const charterObjectives = parseCharterObjectives(charterContent); const sprintFiles = listSprintFiles(sprintsDir, { readdir, fileExists }); @@ -136,7 +148,9 @@ function checkObjectives({ return { charterFound: true, - charterPath, + charterPath: resolved.charterPath, + charterSource: resolved.source, + checkedPaths: resolved.checkedPaths, charterObjectiveIds: [...charterObjectives.keys()].sort(), sprintCount: sprintFiles.length, drift, @@ -145,10 +159,10 @@ function checkObjectives({ function formatReport(result) { if (!result.charterFound) { - return `No CHARTER.md at ${result.charterPath} — nothing to check.`; + return `No ${CANONICAL_CHARTER_PATH} or legacy CHARTER.md found — nothing to check.`; } const lines = [ - `Checked ${result.sprintCount} sprint file(s) against ${result.charterObjectiveIds.length} CHARTER objective(s).`, + `Checked ${result.sprintCount} sprint file(s) against ${result.charterObjectiveIds.length} charter objective(s) from ${result.charterPath}.`, ]; if (result.drift.length === 0) { lines.push("No drift detected ✓"); @@ -187,6 +201,7 @@ module.exports = { extractObjectivesField, parseSprintObjectives, parseCharterObjectives, + resolveCharterPath, listSprintFiles, findDrift, checkObjectives, diff --git a/skills/dev-backlog/scripts/objectives-check.test.js b/skills/dev-backlog/scripts/objectives-check.test.js index b93feaa..4318f65 100644 --- a/skills/dev-backlog/scripts/objectives-check.test.js +++ b/skills/dev-backlog/scripts/objectives-check.test.js @@ -35,7 +35,7 @@ describe("parseArgs", () => { it("uses defaults when nothing passed", () => { const parsed = parseArgs([]); assert.equal(parsed.sprintsDir, path.join("backlog", "sprints")); - assert.equal(parsed.charterPath, "CHARTER.md"); + assert.equal(parsed.charterPath, null); assert.equal(parsed.json, false); }); @@ -171,30 +171,36 @@ describe("findDrift", () => { }); describe("checkObjectives", () => { - it("returns charterFound:false when CHARTER.md is absent", () => { + it("returns charterFound:false when no canonical or legacy charter exists", () => { const result = checkObjectives({ - charterPath: "/no/such/CHARTER.md", - fileExists: (p) => p !== "/no/such/CHARTER.md", + repoRoot: "/no/such", + fileExists: () => false, }); assert.equal(result.charterFound, false); + assert.equal(result.charterSource, "absent"); + assert.ok(result.checkedPaths.some((p) => p.endsWith(path.join("spec", "charter.md")))); + assert.ok(result.checkedPaths.some((p) => p.endsWith("CHARTER.md"))); assert.equal(result.drift.length, 0); }); - it("reports drift over real fixtures", () => { + it("uses spec/charter.md by default", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "obj-check-full-")); try { const sprintsDir = path.join(dir, "backlog", "sprints"); fs.mkdirSync(sprintsDir, { recursive: true }); - fs.writeFileSync(path.join(dir, "CHARTER.md"), SAMPLE_CHARTER); + fs.mkdirSync(path.join(dir, "spec"), { recursive: true }); + fs.writeFileSync(path.join(dir, "spec", "charter.md"), SAMPLE_CHARTER); fs.writeFileSync( path.join(sprintsDir, "2026-05-x.md"), "---\nmilestone: x\nobjectives: [O3, O99]\n---\n", ); const result = checkObjectives({ sprintsDir, - charterPath: path.join(dir, "CHARTER.md"), + repoRoot: dir, }); assert.equal(result.charterFound, true); + assert.equal(result.charterSource, "canonical"); + assert.equal(result.charterPath, path.join(dir, "spec", "charter.md")); assert.equal(result.sprintCount, 1); assert.equal(result.drift.length, 1); assert.deepEqual(result.drift[0].missing, ["O99"]); @@ -202,12 +208,39 @@ describe("checkObjectives", () => { fs.rmSync(dir, { recursive: true, force: true }); } }); + + it("falls back to legacy root CHARTER.md", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "obj-check-legacy-")); + try { + const sprintsDir = path.join(dir, "backlog", "sprints"); + fs.mkdirSync(sprintsDir, { recursive: true }); + fs.writeFileSync(path.join(dir, "CHARTER.md"), SAMPLE_CHARTER); + const result = checkObjectives({ sprintsDir, repoRoot: dir }); + assert.equal(result.charterFound, true); + assert.equal(result.charterSource, "legacy"); + assert.equal(result.charterPath, path.join(dir, "CHARTER.md")); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + }); + + it("honors explicit --charter without fallback", () => { + const result = checkObjectives({ + repoRoot: "/repo", + charterPath: "custom.md", + fileExists: (p) => p.endsWith(path.join("spec", "charter.md")), + }); + assert.equal(result.charterFound, false); + assert.equal(result.charterSource, "explicit"); + assert.equal(result.checkedPaths.length, 1); + assert.equal(result.checkedPaths[0], path.join("/repo", "custom.md")); + }); }); describe("formatReport", () => { it("renders absent-charter message", () => { - const result = { charterFound: false, charterPath: "CHARTER.md", drift: [], sprintCount: 0 }; - assert.match(formatReport(result), /No CHARTER\.md/); + const result = { charterFound: false, charterPath: "spec/charter.md", drift: [], sprintCount: 0 }; + assert.match(formatReport(result), /No spec\/charter\.md or legacy CHARTER\.md/); }); it("renders no-drift summary", () => { diff --git a/skills/dev-backlog/scripts/spec-paths.js b/skills/dev-backlog/scripts/spec-paths.js new file mode 100644 index 0000000..969ea62 --- /dev/null +++ b/skills/dev-backlog/scripts/spec-paths.js @@ -0,0 +1,47 @@ +const fs = require("fs"); +const path = require("path"); + +const CANONICAL_CHARTER_PATH = path.join("spec", "charter.md"); +const LEGACY_CHARTER_PATH = "CHARTER.md"; + +function resolveRepoPath(repoRoot, candidate) { + return path.isAbsolute(candidate) ? candidate : path.join(repoRoot, candidate); +} + +function resolveCharterPath({ + repoRoot = process.cwd(), + charterPath = null, + fileExists = fs.existsSync, +} = {}) { + const candidates = charterPath + ? [{ path: charterPath, source: "explicit" }] + : [ + { path: CANONICAL_CHARTER_PATH, source: "canonical" }, + { path: LEGACY_CHARTER_PATH, source: "legacy" }, + ]; + + const checkedPaths = candidates.map((candidate) => resolveRepoPath(repoRoot, candidate.path)); + const found = candidates.find((candidate) => fileExists(resolveRepoPath(repoRoot, candidate.path))); + + if (!found) { + return { + found: false, + charterPath: checkedPaths[0], + source: charterPath ? "explicit" : "absent", + checkedPaths, + }; + } + + return { + found: true, + charterPath: resolveRepoPath(repoRoot, found.path), + source: found.source, + checkedPaths, + }; +} + +module.exports = { + CANONICAL_CHARTER_PATH, + LEGACY_CHARTER_PATH, + resolveCharterPath, +}; diff --git a/skills/spec-charter/SKILL.md b/skills/spec-charter/SKILL.md index 6251ad2..1f60472 100644 --- a/skills/spec-charter/SKILL.md +++ b/skills/spec-charter/SKILL.md @@ -1,17 +1,17 @@ --- name: spec-charter argument-hint: "[create|amend|reassess]" -description: "Create, amend, and reassess CHARTER.md as the project-wide spec axis. Use to establish or evolve project direction, Objectives, Non-Goals, Decisions, stale spec findings, project charter, 기준, 헌장, 방향성, spec axis." +description: "Create, amend, and reassess spec/charter.md as the project-wide spec axis. Use to establish or evolve project direction, Objectives, Non-Goals, Decisions, stale spec findings, project charter, 기준, 헌장, 방향성, spec axis." compatibility: Requires git. Works on Claude Code and Codex. metadata: - related-skills: "spec-grill, dev-backlog, backlog-triage" + related-skills: "spec-system-map, spec-grill, dev-backlog, backlog-triage" --- # Spec Charter -Create and amend `CHARTER.md`, the opt-in project reference axis used to measure backlog work, sprint plans, and drift. This skill is rerunnable. +Create and amend `spec/charter.md`, the opt-in project reference axis used to measure backlog work, sprint plans, and drift. This skill is rerunnable. -`CHARTER.md` is the first layer, not the whole large-repo spec. On existing/brownfield repos, finish create mode by recommending `spec-grill` so the user can author `spec/capabilities.md` from real repo signals. +`spec/charter.md` is the first layer, not the whole large-repo spec. On existing/brownfield repos, finish create mode by recommending `spec-system-map` for `spec/system-map.md` and `spec-grill` for `spec/capabilities.md` from real repo signals. ## Execution Contract @@ -21,33 +21,34 @@ Explicit modes win first: | User intent | Mode | Boundary | |-------------|------|----------| -| Create the project axis, baseline, charter, or first spec layer | `create` | Only when repo-root `CHARTER.md` is absent, unless the user explicitly asks to replace it. | -| Update direction, objectives, decisions, or accepted charter wording | `amend` | Applies tier gates and may edit `CHARTER.md` after confirmation. | +| Create the project axis, baseline, charter, or first spec layer | `create` | Only when neither `spec/charter.md` nor legacy root `CHARTER.md` exists, unless the user explicitly asks to replace it. | +| Update direction, objectives, decisions, or accepted charter wording | `amend` | Applies tier gates and may edit the resolved charter after confirmation. | | Check whether charter/capabilities/Learnings are stale or should change | `reassess` | Report-only; routes accepted fixes to `spec-charter amend`, `spec-grill`, or a Learning Action. | -When no mode is specified, route by intent first, then use file state only for generic charter requests: no repo-root `CHARTER.md` means create mode, and an existing repo-root `CHARTER.md` means amend mode. If the user asks for capability contracts, component boundaries, or `spec/capabilities.md`, route to `spec-grill`. +When no mode is specified, route by intent first, then use file state only for generic charter requests: prefer `spec/charter.md`; fall back to legacy root `CHARTER.md`; if neither exists, use create mode. If the user asks for capability contracts, component boundaries, or `spec/capabilities.md`, route to `spec-grill`. ### Helper Scripts -Resolve helper scripts from the installed `spec-charter` skill directory, not from the target repo. In a source checkout, that means the local `scripts/` directory beside this `SKILL.md`; in an installed skill, first locate the skill directory and run the same script from there. Always pass the target repo explicitly (`--path /CHARTER.md`) so helpers do not inspect the skill directory by accident. If a helper is unavailable, report **Missing Evidence** and continue with bounded file reads. +Resolve helper scripts from the installed `spec-charter` skill directory, not from the target repo. In a source checkout, that means the local `scripts/` directory beside this `SKILL.md`; in an installed skill, first locate the skill directory and run the same script from there. Always pass the target repo explicitly (`--path /spec/charter.md`) so helpers do not inspect the skill directory by accident. If a helper is unavailable, report **Missing Evidence** and continue with bounded file reads. ### Completion Contract End every mode with a short summary: -- `create`: created files, unresolved assumptions, and whether `spec-grill` is the recommended next step. +- `create`: created files, unresolved assumptions, and whether `spec-system-map` and `spec-grill` are recommended next steps. - `amend`: accepted changes, refused/parked changes, proof cited for status advances, and size-check result. - `reassess`: required report sections from the Reassess Mode dispatch contract, with one recommended next step. -## What CHARTER.md Is +## What spec/charter.md Is -`CHARTER.md` lives at the target repo root as a peer of `README.md`. It records what good looks like: the problem, approach, explicit non-goals, verifiable objectives, and immutable decision history the backlog is measured against. +`spec/charter.md` lives in the target repo's project spec directory. It records what good looks like: the problem, approach, explicit non-goals, verifiable objectives, and immutable decision history the backlog is measured against. -Absence is supported. Projects opt in by creating the file; other skills degrade gracefully when it is missing. Keep the charter under a ~5-minute read. Operational know-how does not belong here; put rediscovery-prone HOW-knowledge in `_context.md`. +Absence is supported. Projects opt in by creating the file; other skills degrade gracefully when it is missing. Legacy root `CHARTER.md` is read as a fallback and should be migrated deliberately. Keep the charter under a ~5-minute read. Operational know-how does not belong here; put rediscovery-prone HOW-knowledge in `_context.md`. | File | Question it answers | |------|---------------------| -| `CHARTER.md` | What good looks like / why (the yardstick) | +| `spec/charter.md` | What good looks like / why (the yardstick) | +| `spec/system-map.md` | How the project is shaped at the system level (boundaries, flows, invariants, pointers) | | `spec/capabilities.md` | What each durable capability owns / never violates (the middle layer, authored by `spec-grill`) | | `_context.md` | Operational facts you would otherwise rediscover (HOW-knowledge) | | `CLAUDE.md` / `AGENTS.md` | How agents work in this repo (development harness; not product authority by default) | @@ -65,12 +66,12 @@ This tiering prevents the axis from self-evolving into a rubber-stamp: direction ## Create Mode -Use create mode when `CHARTER.md` is absent at the repo root, or when invoked as `spec-charter create` and no charter exists. +Use create mode when neither `spec/charter.md` nor legacy root `CHARTER.md` exists, or when invoked as `spec-charter create` and no charter exists. -1. Draft from repo signals: product/user-facing signals (`README.md`, open epics/issues, `CHANGELOG.md`) before development-harness signals (`CLAUDE.md`, `AGENTS.md`). Harness files may inform workflow conventions, local commands, and repo-specific guardrails, but they do not override README, CHARTER, issues, code structure, or user interview answers for product/capability authority unless they explicitly describe product boundaries. When signals conflict, surface the conflict in the interview rather than picking silently. +1. Draft from repo signals: product/user-facing signals (`README.md`, open epics/issues, `CHANGELOG.md`) before development-harness signals (`CLAUDE.md`, `AGENTS.md`). Harness files may inform workflow conventions, local commands, and repo-specific guardrails, but they do not override README, charter, issues, code structure, or user interview answers for product/capability authority unless they explicitly describe product boundaries. When signals conflict, surface the conflict in the interview rather than picking silently. 2. Interview the user to fill and sharpen Problem, Approach, Non-Goals, and initial Objectives. Follow the checklist in `references/create.md`: Problem framing options, the wedge test for Approach, Non-Goals elicitation, and Objective framing that cites `references/objectives.md`. -3. Write repo-root `CHARTER.md` from `templates/charter.md` with `revision: 1` and today's `last_amended`. The Decisions table may be left empty. Seed 3-5 rows only when prior design docs, ADRs, or notable merged PRs already record direction; whatever lands becomes immutable from revision 2. -4. If the target repo is brownfield, recommend `spec-grill` as the next step. Brownfield signals include existing source roots (`src/`, `app/`, `lib/`, `packages/`, `skills/`), commit history, tests/scripts/config, open issues, or multiple top-level feature/workflow surfaces. +3. Create `spec/` if needed, then write `spec/charter.md` from `templates/charter.md` with `revision: 1` and today's `last_amended`. The Decisions table may be left empty. Seed 3-5 rows only when prior design docs, ADRs, or notable merged PRs already record direction; whatever lands becomes immutable from revision 2. +4. If the target repo is brownfield, recommend `spec-system-map` and `spec-grill` as the next steps. Brownfield signals include existing source roots (`src/`, `app/`, `lib/`, `packages/`, `skills/`), commit history, tests/scripts/config, open issues, or multiple top-level feature/workflow surfaces. Objective conventions: @@ -84,9 +85,9 @@ See `references/objectives.md` for worked examples, rewrite patterns, and a 30-s ## Amend Mode -Use amend mode when `CHARTER.md` exists at the repo root, or when invoked as `spec-charter amend`. +Use amend mode when `spec/charter.md` exists, legacy root `CHARTER.md` exists, or when invoked as `spec-charter amend`. -First re-read the current `CHARTER.md`. Direct hand-edits are allowed because it is the user's file; this skill is the disciplined path for applying the tier gates. +First re-read `spec/charter.md`. If it is absent but root `CHARTER.md` exists, read that legacy file, state that the canonical path is now `spec/charter.md`, and recommend migrating before or during the accepted amendment. Direct hand-edits are allowed because it is the user's file; this skill is the disciplined path for applying the tier gates. Apply the 3-tier discipline: @@ -94,7 +95,7 @@ Apply the 3-tier discipline: - Tier 2 status advance: require proof for `active` -> `validated` or `deferred`; cite a merged PR, passing check, or relay run whose Done Criteria match the predicate. Without proof, refuse the advance and flag it. - Tier 3 Decisions: append only. Never edit or delete an existing row; a reversal is a new row with `supersedes`. -After applying an accepted amendment, bump `last_amended` to today and increment `revision`. Then run `check-size.js --path /CHARTER.md` from the installed skill's `scripts/` directory to confirm the 5-minute-read property still holds; collapse long `deferred` lists or oversized Decisions rationale if the script warns. +After applying an accepted amendment, bump `last_amended` to today and increment `revision`. Then run `check-size.js --path /spec/charter.md` from the installed skill's `scripts/` directory to confirm the 5-minute-read property still holds; collapse long `deferred` lists or oversized Decisions rationale if the script warns. Amend mode can take a `backlog-triage` Alignment Check report as a seed of proposed changes. The report proposes; this skill applies through the gates. @@ -102,15 +103,15 @@ See `references/amendment.md` for deep challenge and proof-gate heuristics. ## Reassess Mode -Use reassess mode when the user asks whether `CHARTER.md` or `spec/capabilities.md` is stale, asks to review Learnings, wants a periodic spec health check, or when major model/tool/harness changes could alter how agents interpret repo context. +Use reassess mode when the user asks whether `spec/charter.md`, `spec/system-map.md`, or `spec/capabilities.md` is stale, asks to review Learnings, wants a periodic spec health check, or when major model/tool/harness changes could alter how agents interpret repo context. -Reassess never edits files. It diagnoses drift and recommends next actions; accepted fixes must run through `spec-charter amend`, `spec-grill `, or a separate user-approved Learning Action. +Reassess never edits files. It diagnoses drift and recommends next actions; accepted fixes must run through `spec-charter amend`, `spec-system-map amend`, `spec-grill `, or a separate user-approved Learning Action. Dispatch contract: 1. Resolve helper scripts from the installed dev-backlog skill directory; if unavailable, report **Missing Evidence**. -2. Start with bounded evidence: `capabilities-doctor.js --json`, `component-lint.js --json`, named CHARTER/capability sections, the active sprint, and at most the latest five completed sprint files. -3. Emit these report sections: **Evidence**, **No Change**, **Grill Candidates**, **Amend Candidates**, **Learning Actions**, **Missing Evidence**, **Recommended Next Step**. +2. Start with bounded evidence: `capabilities-doctor.js --json`, `component-lint.js --json`, named charter, system-map, or capability sections, the active sprint, and at most the latest five completed sprint files. +3. Emit these report sections: **Evidence**, **No Change**, **System Map Candidates**, **Grill Candidates**, **Amend Candidates**, **Learning Actions**, **Missing Evidence**, **Recommended Next Step**. 4. Use `references/reassess.md` as the source of truth for evidence order, report shape, recommendation rules, Learning Actions, and stale-spec failure modes. ## References @@ -120,4 +121,5 @@ Dispatch contract: - `references/alignment.md` — shared work-to-objective mapping logic consumed by `backlog-triage` and `dev-backlog`. - `references/objectives.md` — verifiable-predicate examples, common rewrite patterns, 30-second test. - `references/reassess.md` — report-only stale-spec reassessment: evidence sources, output shape, Learning Actions, and failure modes. +- [`../spec-system-map/SKILL.md`](../spec-system-map/SKILL.md) — companion skill for authoring `spec/system-map.md`. - [`../spec-grill/SKILL.md`](../spec-grill/SKILL.md) — companion skill for authoring `spec/capabilities.md`. diff --git a/skills/spec-charter/references/alignment.md b/skills/spec-charter/references/alignment.md index 85fe5d2..8c05cf4 100644 --- a/skills/spec-charter/references/alignment.md +++ b/skills/spec-charter/references/alignment.md @@ -1,6 +1,6 @@ # Charter Alignment Mapping -Use this reference when mapping backlog work to `CHARTER.md` Objectives. The mapping is semantic, prompt-driven analysis: compare issue or epic title/body against objective predicates and Non-Goals. +Use this reference when mapping backlog work to charter Objectives. Read `spec/charter.md` first; if absent, fall back to legacy root `CHARTER.md`; if both are absent, skip Alignment. The mapping is semantic, prompt-driven analysis: compare issue or epic title/body against objective predicates and Non-Goals. ## Issue To Objective Mapping @@ -35,6 +35,6 @@ Start the Alignment report with a compact coverage line: Use the first count for open issues that map to at least one objective. Mention neglected objectives or contradictions after the separator. -## Proposed CHARTER Changes +## Proposed Charter Changes -When findings suggest the charter may need to evolve, format proposals as a seed for `spec-charter` amend. The triage or planning report proposes only; `spec-charter` owns gated mutation of `CHARTER.md`. +When findings suggest the charter may need to evolve, format proposals as a seed for `spec-charter` amend. The triage or planning report proposes only; `spec-charter` owns gated mutation of `spec/charter.md`. diff --git a/skills/spec-charter/references/amendment.md b/skills/spec-charter/references/amendment.md index 1d9e96d..dd80821 100644 --- a/skills/spec-charter/references/amendment.md +++ b/skills/spec-charter/references/amendment.md @@ -1,6 +1,6 @@ # Charter Amendment Guidance -Use this reference in `spec-charter` amend mode after re-reading the current repo-root `CHARTER.md`. The default bias is stability: no change unless concrete evidence shows the charter is stale, weak, or newly validated. +Use this reference in `spec-charter` amend mode after re-reading `spec/charter.md`, or legacy root `CHARTER.md` only as a fallback. The default bias is stability: no change unless concrete evidence shows the charter is stale, weak, or newly validated. ## Tier 1 Challenge Checklist diff --git a/skills/spec-charter/references/create.md b/skills/spec-charter/references/create.md index c1c355e..83bcc88 100644 --- a/skills/spec-charter/references/create.md +++ b/skills/spec-charter/references/create.md @@ -1,6 +1,6 @@ # Charter Create Mode: Signals, Interview, Seed Decisions -Use this reference in `spec-charter` create mode after confirming no repo-root `CHARTER.md` exists. The goal is a defensible first revision that survives its own proof gate — not a perfect axis on day one. Stability comes from amend mode; create mode just has to set a credible starting point. +Use this reference in `spec-charter` create mode after confirming neither `spec/charter.md` nor legacy root `CHARTER.md` exists. The goal is a defensible first revision that survives its own proof gate — not a perfect axis on day one. Stability comes from amend mode; create mode just has to set a credible starting point. ## 1. Signal Collection (Priority + Conflict) diff --git a/skills/spec-charter/references/objectives.md b/skills/spec-charter/references/objectives.md index 705cf78..a7026a1 100644 --- a/skills/spec-charter/references/objectives.md +++ b/skills/spec-charter/references/objectives.md @@ -6,7 +6,7 @@ The shape: > `O [status] · src: ` -The predicate should map to a verification path you could write down today: a command to run, a scenario to walk through, a count to take. If you cannot name the verification, the predicate is not yet verifiable — sharpen it before committing it to CHARTER. +The predicate should map to a verification path you could write down today: a command to run, a scenario to walk through, a count to take. If you cannot name the verification, the predicate is not yet verifiable — sharpen it before committing it to the charter. ## ✅ Good Predicates @@ -18,14 +18,14 @@ Each example pairs a predicate with the concrete check that would advance its st 2. **"An agent resuming a sprint mid-session sees in-flight `[~]` items it did not author and can act on them without re-asking the user"** *Verification:* open the active sprint file in a fresh session; confirm `[~]` markers + PR refs are readable. A continuity predicate verified by a single observation. -3. **"A user can answer 'is this project still on track?' in under 5 minutes against `CHARTER.md`"** - *Verification:* timed read + answer against the live CHARTER. Mixed-rigor: not a script, but a timed scenario with a binary outcome. (This is dev-backlog's own O3.) +3. **"A user can answer 'is this project still on track?' in under 5 minutes against `spec/charter.md`"** + *Verification:* timed read + answer against the live charter. Mixed-rigor: not a script, but a timed scenario with a binary outcome. (This is dev-backlog's own O3.) 4. **"Every open Issue maps to an active or deferred Objective without manual triage"** *Verification:* `backlog-triage` Alignment Check report shows 0 orphans on the current backlog. A drift predicate with an existing tool as the check. -5. **"A new contributor reads `CHARTER.md` in under 5 minutes and can name one explicitly rejected scope"** - *Verification:* word count + Non-Goals section non-empty + onboarding scenario. Cheap to observe; sharper than "CHARTER is short." +5. **"A new contributor reads `spec/charter.md` in under 5 minutes and can name one explicitly rejected scope"** + *Verification:* word count + Non-Goals section non-empty + onboarding scenario. Cheap to observe; sharper than "charter is short." Notice the shape: each one names **who** does **what** with a **measurable outcome**. None of them say "improve" or "implement." @@ -45,9 +45,9 @@ Each failure mode appears regularly. The rewrite shows the move that fixes it. *Failure:* unfalsifiable opinion. Whose DX, doing what, judged how? *Rewrite:* "An agent dispatches a relay run with one command and no manual edits to manifest files." Name the actor, the action, the observable. -4. **"Adopt CHARTER everywhere"** +4. **"Adopt charter everywhere"** *Failure:* process declaration, not a user-facing outcome. Confuses the project's internal habit with what the project produces. - *Rewrite:* "Every active project in this workspace has a committed `CHARTER.md` at repo root." Make it a count, not a vibe. + *Rewrite:* "Every active project in this workspace has a committed `spec/charter.md`." Make it a count, not a vibe. 5. **"Reduce context loss across sessions"** *Failure:* direction without verification — true when? observed by whom? diff --git a/skills/spec-charter/references/reassess.md b/skills/spec-charter/references/reassess.md index 713c67e..682c579 100644 --- a/skills/spec-charter/references/reassess.md +++ b/skills/spec-charter/references/reassess.md @@ -1,6 +1,6 @@ # Reassess-Mode Heuristics -Use this reference in `spec-charter reassess` after reading the Reassess Mode section in `SKILL.md`. The mode is a report-only stale-spec review. It helps the user decide whether to run `spec-charter amend`, `spec-grill `, or a separate user-approved Learning Action. +Use this reference in `spec-charter reassess` after reading the Reassess Mode section in `SKILL.md`. The mode is a report-only stale-spec review. It helps the user decide whether to run `spec-charter amend`, `spec-system-map amend`, `spec-grill `, or a separate user-approved Learning Action. ## Policy Ownership @@ -14,12 +14,12 @@ Reassess is the controller review, not the writer. - Sensors: `## Learnings`, sprint `component:` handles, doctor/lint output, recent sprint context. - Diagnosis: the reassess report. -- Controller action: user-approved `amend`, `grill`, or Learning Action. -- Forbidden shortcut: silently editing accepted CHARTER direction or capability contracts during reassess. +- Controller action: user-approved `amend`, `system-map`, `grill`, or Learning Action. +- Forbidden shortcut: silently editing accepted charter direction or capability contracts during reassess. The default answer can be "no change." Do not manufacture churn just because the user asked for a reassessment. -Learning Actions are the user-gated family for keeping recent Learnings inline, promoting durable facts to Decisions, promoting cross-cutting facts to CHARTER Decisions, or archiving old history outside the hot startup path. If the user accepts one, end reassess and perform a separate user-approved manual edit. Do not treat that edit as part of reassess diagnosis. +Learning Actions are the user-gated family for keeping recent Learnings inline, promoting durable facts to Decisions, promoting cross-cutting facts to charter Decisions, or archiving old history outside the hot startup path. If the user accepts one, end reassess and perform a separate user-approved manual edit. Do not treat that edit as part of reassess diagnosis. ## Cadence Triggers @@ -28,7 +28,7 @@ Run a lightweight reassess pass when either condition applies: - A major model, coding-agent tool, or repo harness change affects how agents read instructions, call tools, or preserve context. - An active project has used the spec-system for 3-6 months without a spec health review. -Keep this low-noise: the review can still conclude "no change," and it does not create an automatic edit path. Treat `CLAUDE.md` / `AGENTS.md` as development-harness context during this pass. They can explain local commands, agent workflow, and guardrails, but they do not override README, CHARTER, issues, code structure, or accepted capability contracts as product authority. +Keep this low-noise: the review can still conclude "no change," and it does not create an automatic edit path. Treat `CLAUDE.md` / `AGENTS.md` as development-harness context during this pass. They can explain local commands, agent workflow, and guardrails, but they do not override README, charter, issues, code structure, or accepted capability contracts as product authority. ## Evidence Order @@ -36,12 +36,13 @@ Prefer bounded evidence before broad reading: 1. `capabilities-doctor.js --json` for compactness, marker health, and inline Learnings count. 2. `component-lint.js --json` for sprint `component:` routing drift. -3. `CHARTER.md` Objectives and Decisions when a recommendation could affect project-wide direction. -4. `spec/capabilities.md` capability blocks named by the evidence. -5. `CLAUDE.md` / `AGENTS.md` only when the reassess question involves harness behavior, local commands, or agent context loading. -6. Latest five completed sprint files, plus the active sprint when it exists. +3. `spec/charter.md` Objectives and Decisions when a recommendation could affect project-wide direction. +4. `spec/system-map.md` when evidence points to stale project-wide structure, boundaries, flows, or invariants. +5. `spec/capabilities.md` capability blocks named by the evidence. +6. `CLAUDE.md` / `AGENTS.md` only when the reassess question involves harness behavior, local commands, or agent context loading. +7. Latest five completed sprint files, plus the active sprint when it exists. -If a script is missing, say it was skipped and continue with file reads. Missing `CHARTER.md` or `spec/capabilities.md` is not an error; it is an opt-in state with a next-step recommendation. +If a script is missing, say it was skipped and continue with file reads. Missing `spec/charter.md`, `spec/system-map.md`, or `spec/capabilities.md` is not an error; it is an opt-in state with a next-step recommendation. ## Report Shape @@ -56,11 +57,14 @@ Use this structure unless the user asks for a shorter answer: ### No Change - +### System Map Candidates +- — evidence: ; suspected change: ; next: `spec-system-map amend` + ### Grill Candidates - — evidence: ; suspected change: ; next: `spec-grill ` ### Amend Candidates -- — evidence: ; suspected change: ; next: `spec-charter amend` +- — evidence: ; suspected change: ; next: `spec-charter amend` ### Learning Actions - Keep inline: @@ -94,6 +98,17 @@ Recommend `spec-grill ` when any of these are true: Do not rewrite the capability during reassess. Name the block and the suspected edit. +### System Map Candidate + +Recommend `spec-system-map amend` when evidence affects project-wide structure without changing why/good-state: + +- runtime boundaries changed across capabilities +- a core flow has a new step, owner, or external system +- a project-wide invariant is missing, stale, or contradicted +- the map copied module details that should be demoted to linked docs + +Do not rewrite the map during reassess. Name the suspected section and the evidence. + ### Amend Candidate Recommend `spec-charter amend` when evidence affects project-wide direction: @@ -101,7 +116,7 @@ Recommend `spec-charter amend` when evidence affects project-wide direction: - a repeated Learning changes multiple capabilities - an Objective appears validated or deferred but lacks proof - a Non-Goal is repeatedly violated by accepted work -- a capability-level Decision is cross-cutting enough to belong in CHARTER +- a capability-level Decision is cross-cutting enough to belong in `spec/charter.md` Do not weaken an Objective so the available proof appears sufficient. @@ -111,7 +126,7 @@ Learning Action is the canonical umbrella for accepted Learnings cleanup after r Keep recent Learnings inline when they are still useful startup context. -Promote a Learning to `## Decisions` when it has become a durable capability rule. Promote to CHARTER Decisions only when it affects more than one capability or changes the project-wide axis. +Promote a Learning to `## Decisions` when it has become a durable capability rule. Promote to charter Decisions only when it affects more than one capability or changes the project-wide axis. Archive older Learnings when they are useful history but no longer startup context. Reassess may recommend a Learning Action, but the actual edit is human-gated. diff --git a/skills/spec-charter/scripts/check-size.js b/skills/spec-charter/scripts/check-size.js index b5749f1..5fd157e 100644 --- a/skills/spec-charter/scripts/check-size.js +++ b/skills/spec-charter/scripts/check-size.js @@ -1,10 +1,10 @@ #!/usr/bin/env node /** - * Lint CHARTER.md size against the ~5-minute-read property. + * Lint spec/charter.md size against the ~5-minute-read property. * * Usage: ./scripts/check-size.js [--path PATH] [--strict] [--json] * - * Reads CHARTER.md (default ./CHARTER.md), counts words + lines, and + * Reads spec/charter.md by default, counts words + lines, and * prints a summary. Warns above 1000 words (~5 min at 200 wpm) or * 80 lines and suggests candidates to collapse (long deferred lists, * oversized Decisions rationale). @@ -12,7 +12,7 @@ * Exit codes: * 0 ok or warnings (advisory) * 1 --strict and the file exceeds either threshold - * 2 CHARTER.md not found + * 2 charter not found */ const fs = require("fs"); @@ -22,13 +22,14 @@ const WORD_LIMIT = 1000; const LINE_LIMIT = 80; const WORDS_PER_MINUTE = 200; const LONG_RATIONALE_CHARS = 140; +const DEFAULT_CHARTER_PATH = path.join("spec", "charter.md"); function usage() { return "Usage: check-size.js [--path PATH] [--strict] [--json]"; } function parseArgs(args) { - const options = { charterPath: "CHARTER.md", strict: false, json: false }; + const options = { charterPath: DEFAULT_CHARTER_PATH, strict: false, json: false }; for (let i = 0; i < args.length; i += 1) { const arg = args[i]; @@ -182,7 +183,7 @@ function formatWarnings(result) { } function checkSize({ - charterPath, + charterPath = DEFAULT_CHARTER_PATH, readFile = fs.readFileSync, fileExists = fs.existsSync, } = {}) { @@ -212,7 +213,7 @@ function main() { if (parsed.json) { console.log(JSON.stringify({ found: false, charterPath: result.charterPath }, null, 2)); } else { - console.error(`CHARTER.md not found at ${result.charterPath}`); + console.error(`charter not found at ${result.charterPath}`); } process.exit(2); } diff --git a/skills/spec-charter/scripts/check-size.test.js b/skills/spec-charter/scripts/check-size.test.js index 23d6909..3fe01b1 100644 --- a/skills/spec-charter/scripts/check-size.test.js +++ b/skills/spec-charter/scripts/check-size.test.js @@ -17,8 +17,8 @@ const { } = require("./check-size.js"); describe("parseArgs", () => { - it("defaults to CHARTER.md, not strict, not json", () => { - assert.deepEqual(parseArgs([]), { charterPath: "CHARTER.md", strict: false, json: false }); + it("defaults to spec/charter.md, not strict, not json", () => { + assert.deepEqual(parseArgs([]), { charterPath: path.join("spec", "charter.md"), strict: false, json: false }); }); it("accepts --strict and --json", () => { @@ -203,7 +203,8 @@ describe("checkSize", () => { it("reads and analyzes a real on-disk file", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "check-size-")); try { - const file = path.join(dir, "CHARTER.md"); + const file = path.join(dir, "spec", "charter.md"); + fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, "---\nrevision: 1\n---\n\nHello world\n"); const result = checkSize({ charterPath: file }); assert.equal(result.found, true); diff --git a/skills/spec-grill/SKILL.md b/skills/spec-grill/SKILL.md index 17bdc37..943c0f4 100644 --- a/skills/spec-grill/SKILL.md +++ b/skills/spec-grill/SKILL.md @@ -9,7 +9,7 @@ metadata: # Spec Grill -Author `spec/capabilities.md`, the middle layer between `CHARTER.md` and the active sprint. `spec-grill` is not a file generator; it pressure-tests existing repo signals into durable capability contracts. +Author `spec/capabilities.md`, the middle layer between `spec/charter.md` and the active sprint. `spec-grill` is not a file generator; it pressure-tests existing repo signals into durable capability contracts. Use this after `spec-charter create` on existing/brownfield repos, or whenever the user asks to define capability boundaries, component contracts, Behaviors, or Hard Constraints. @@ -40,11 +40,11 @@ End every run with a short summary: ## Brownfield Signal Rules -`extract-signals.js` draws from README, `CHARTER.md`, `CLAUDE.md`/`AGENTS.md`, top-level source dirs, and recent commit messages. +`extract-signals.js` draws from README, `spec/charter.md` with legacy root `CHARTER.md` fallback, `CLAUDE.md`/`AGENTS.md`, top-level source dirs, and recent commit messages. Use the draft as interview seed only. The script labels signal authority: -- README/CHARTER/issues are product authority. +- README/charter/issues are product authority. - source directories are repo-structure evidence. - commit scopes are history. - `CLAUDE.md`/`AGENTS.md` are development-harness context. @@ -60,7 +60,7 @@ The file's mutation discipline: - Goal / In-scope / Out-of-scope: human-gated through this skill. - Expected Behaviors / Hard Constraints: human-gated and must pass the 3-axis predicate test. - `## Learnings`: not an interview target; appended only by the bounded Learnings writer between magic markers. -- `## Decisions`: append-only by convention; promote cross-cutting decisions to `CHARTER.md` through `spec-charter amend`. +- `## Decisions`: append-only by convention; promote cross-cutting decisions to `spec/charter.md` through `spec-charter amend`. ## Capability Admission Test @@ -81,7 +81,7 @@ Use this as a bloat check before the per-capability flow. A large feature-first For each capability, walk the user through this order; do not skip ahead: -1. **Goal** — one sentence: what the user can observe when this works. Diagnosis-side framing belongs in CHARTER; capability Goal is the observable outcome. +1. **Goal** — one sentence: what the user can observe when this works. Diagnosis-side framing belongs in the charter; capability Goal is the observable outcome. 2. **In-scope / Out-of-scope** — what this capability owns, and the boundary it deliberately respects. Out-of-scope prevents creep. 3. **Expected Behaviors** — three verifiable predicates. Each one must pass the 3-axis test below. Reject and rewrite until it does. 4. **Hard Constraints** — two bright-lines this capability never crosses, even if asked. Adversarial-Goodhart defenses live here. @@ -104,4 +104,4 @@ On first run, copy `templates/capabilities.md` to `spec/capabilities.md` at the After applying an accepted change, do not bump a revision number on `spec/capabilities.md`; `git blame` is the source of truth. Note in the conversation which capability was edited. -See `references/capabilities.md` for additional grill heuristics and [`../spec-charter/SKILL.md`](../spec-charter/SKILL.md) for the project-wide CHARTER layer. +See `references/capabilities.md` for additional grill heuristics and [`../spec-charter/SKILL.md`](../spec-charter/SKILL.md) for the project-wide charter layer. diff --git a/skills/spec-grill/references/capabilities.md b/skills/spec-grill/references/capabilities.md index 6ce8247..b9fa1fa 100644 --- a/skills/spec-grill/references/capabilities.md +++ b/skills/spec-grill/references/capabilities.md @@ -37,10 +37,10 @@ Bad Goal lines usually describe diagnosis, implementation, or an internal tool. |---|---| | "Reduce context loss across sprints." | "An agent resuming work mid-session reads the active sprint file and acts on in-flight items without re-asking what is going on." | | "`sync-pull.js` mirrors GitHub." | "Open GitHub Issues are mirrored into `backlog/tasks/*.md` without diverging on local AC checkbox state." | -| "Backlog triage with CHARTER awareness." | "Open Issues are classified, related, flagged stale, and aligned to CHARTER Objectives without humans maintaining a parallel triage spreadsheet." | -| "Keep CHARTER short." | "A user creates or amends `CHARTER.md` through tier-gated discipline and the file stays a 5-minute read." | +| "Backlog triage with charter awareness." | "Open Issues are classified, related, flagged stale, and aligned to charter Objectives without humans maintaining a parallel triage spreadsheet." | +| "Keep charter short." | "A user creates or amends `spec/charter.md` through tier-gated discipline and the file stays a 5-minute read." | -Move diagnosis-side framing to CHARTER Problem. Move scripts and file names to In-scope unless the script is the user-visible surface. +Move diagnosis-side framing to the charter Problem. Move scripts and file names to In-scope unless the script is the user-visible surface. ## Behavior vs. Hard Constraint @@ -108,9 +108,9 @@ It must not touch: - `### Learnings` - `### Decisions` - other capability blocks -- `CHARTER.md`, unless the user separately invokes amend mode +- `spec/charter.md`, unless the user separately invokes amend mode -If a rerun discovers a cross-cutting decision, append it to the relevant Decisions table or promote it to CHARTER via amend mode. Do not rewrite old Decisions rows. +If a rerun discovers a cross-cutting decision, append it to the relevant Decisions table or promote it to `spec/charter.md` via amend mode. Do not rewrite old Decisions rows. ## Capability Count Guidance @@ -142,7 +142,7 @@ dev-backlog has four skill directories, but six capabilities: - `sprint-execution` owns the active sprint as the execution hub. - `backlog-sync` owns the GitHub Issues to task-file mirror. -- `spec-charter` owns CHARTER lifecycle and report-only reassess. +- `spec-charter` owns charter lifecycle and report-only reassess. - `spec-grill` owns `spec/capabilities.md` authoring and capability-contract pressure tests. - `triage-grooming` owns backlog classification and relationship reports. - `task-progress-reporting` owns monthly progress issue synchronization. @@ -180,7 +180,7 @@ Use the canonical policy in `docs/spec-system-design.md` and the operational rep - keep recent Learnings inline when they still help startup context - promote durable capability facts to `## Decisions` -- promote cross-cutting facts to CHARTER Decisions +- promote cross-cutting facts to charter Decisions - archive older history outside the hot `spec/capabilities.md` path Do not let relay delete or rewrite Learnings. A Learning Action is human-gated or doctor-suggested, not an automatic side effect of a merge. diff --git a/skills/spec-grill/scripts/extract-signals.js b/skills/spec-grill/scripts/extract-signals.js index 0f9ea8d..b14ba42 100644 --- a/skills/spec-grill/scripts/extract-signals.js +++ b/skills/spec-grill/scripts/extract-signals.js @@ -9,7 +9,7 @@ * grill mode owns admission, merging, splitting, and naming. * * Signal authority: - * - README.md / CHARTER.md — product authority + * - README.md / spec/charter.md — product authority * - Top-level source dirs — repo-structure evidence * - CLAUDE.md / AGENTS.md — development-harness conventions * - Last N commit messages — history @@ -26,12 +26,17 @@ const fs = require("fs"); const path = require("path"); const { execFileSync } = require("child_process"); +const { + CANONICAL_CHARTER_PATH, + LEGACY_CHARTER_PATH, + resolveCharterPath, +} = require("../../dev-backlog/scripts/spec-paths.js"); const SOURCE_ROOT_CANDIDATES = ["src", "lib", "app", "packages", "skills"]; const SUMMARY_DIR_LIMIT = 5; const DEFAULT_COMMIT_LIMIT = 100; -function buildSignalAuthority({ readmeFound, charterFound, harnessFiles, sourceRoot, commitsScanned }) { +function buildSignalAuthority({ readmeFound, charterFound, charterSource, harnessFiles, sourceRoot, commitsScanned }) { return [ { signal: "README.md", @@ -40,10 +45,12 @@ function buildSignalAuthority({ readmeFound, charterFound, harnessFiles, sourceR note: "User-facing product framing; can seed Problem, Approach, and capability goals.", }, { - signal: "CHARTER.md", + signal: "spec/charter.md", authority: "product", found: charterFound, - note: "Accepted project axis; Objectives can constrain capability candidates.", + note: charterSource === "legacy" + ? "Accepted project axis found through legacy root CHARTER.md fallback; migrate to spec/charter.md." + : "Accepted project axis; Objectives can constrain capability candidates.", }, { signal: "CLAUDE.md/AGENTS.md", @@ -172,12 +179,24 @@ function readOptionalFile(filePath, { readFile = fs.readFileSync, fileExists = f } } +function resolveCharterFile(repoRoot, deps = {}) { + const resolved = resolveCharterPath({ repoRoot, fileExists: deps.fileExists }); + if (!resolved.found) { + return { found: false, path: resolved.charterPath, source: resolved.source, content: null }; + } + return { + found: true, + path: resolved.charterPath, + source: resolved.source, + content: readOptionalFile(resolved.charterPath, deps), + }; +} + function readCharterObjectives(repoRoot, deps = {}) { - const charterPath = path.join(repoRoot, "CHARTER.md"); - const content = readOptionalFile(charterPath, deps); - if (!content) return []; + const charter = resolveCharterFile(repoRoot, deps); + if (!charter.content) return []; const objectives = []; - for (const line of content.split("\n")) { + for (const line of charter.content.split("\n")) { const match = line.match(/^- (O\d+) \[(validated|active|deferred)\]\s+(.*?)(?:\s+·\s+src:|\s*$)/); if (match) { objectives.push({ id: match[1], status: match[2], predicate: match[3].trim() }); @@ -218,7 +237,7 @@ function buildCapability({ name, sourceRootName, signals, readmeSummary, charter : `Inferred from commit scope '${name}'. Confirm the owning source surface and out-of-scope boundary in grill.`; const objectiveHint = charterObjectives.length > 0 - ? ` Candidate CHARTER objective served: ${charterObjectives[0].id} (${charterObjectives[0].predicate.slice(0, 80)}${charterObjectives[0].predicate.length > 80 ? "..." : ""}). Confirm in grill.` + ? ` Candidate charter objective served: ${charterObjectives[0].id} (${charterObjectives[0].predicate.slice(0, 80)}${charterObjectives[0].predicate.length > 80 ? "..." : ""}). Confirm in grill.` : ""; return { @@ -265,7 +284,7 @@ function extractSignals({ const deps = { readFile, fileExists, statSync, readdir, exec }; const readme = readOptionalFile(path.join(repoRoot, "README.md"), deps); - const charter = readOptionalFile(path.join(repoRoot, "CHARTER.md"), deps); + const charter = resolveCharterFile(repoRoot, deps); const claudeMd = readOptionalFile(path.join(repoRoot, "CLAUDE.md"), deps); const agentsMd = readOptionalFile(path.join(repoRoot, "AGENTS.md"), deps); const harnessFiles = [ @@ -282,7 +301,9 @@ function extractSignals({ const inventory = { repoRoot: path.resolve(repoRoot), readmeFound: readme !== null, - charterFound: charter !== null, + charterFound: charter.found, + charterPath: charter.found ? charter.path : null, + charterSource: charter.source, claudeMdFound: harnessFiles.length > 0, harnessFiles, sourceRoot: sourceRoot ? sourceRoot.name : null, @@ -293,7 +314,8 @@ function extractSignals({ }; const signalAuthority = buildSignalAuthority({ readmeFound: readme !== null, - charterFound: charter !== null, + charterFound: charter.found, + charterSource: charter.source, harnessFiles, sourceRoot, commitsScanned: commitMessages.length, @@ -320,7 +342,7 @@ function formatHumanReport(result) { lines.push(`Repo: ${inventory.repoRoot}`); lines.push("Signals:"); lines.push(` - README.md: ${inventory.readmeFound ? "found" : "missing"}`); - lines.push(` - CHARTER.md: ${inventory.charterFound ? "found" : "missing"}; objectives: ${inventory.charterObjectiveCount}`); + lines.push(` - spec/charter.md: ${inventory.charterFound ? `found (${inventory.charterSource})` : "missing"}; objectives: ${inventory.charterObjectiveCount}`); lines.push(` - CLAUDE.md/AGENTS.md: ${inventory.claudeMdFound ? `found (${(inventory.harnessFiles || []).join(", ")})` : "missing"}; authority: development-harness`); lines.push(` - source root: ${inventory.sourceRoot ?? "none detected"} (${inventory.sourceDirCount} dir(s))`); lines.push(` - commits scanned: ${inventory.commitsScanned}; scopes seen: ${inventory.commitScopeCount}`); @@ -375,6 +397,9 @@ module.exports = { extractCommitScopes, getRecentCommitMessages, readOptionalFile, + resolveCharterFile, + CANONICAL_CHARTER_PATH, + LEGACY_CHARTER_PATH, readCharterObjectives, summarizeReadme, buildCapability, diff --git a/skills/spec-grill/scripts/extract-signals.test.js b/skills/spec-grill/scripts/extract-signals.test.js index c484272..93e8677 100644 --- a/skills/spec-grill/scripts/extract-signals.test.js +++ b/skills/spec-grill/scripts/extract-signals.test.js @@ -9,6 +9,7 @@ const { listCapabilityCandidates, extractCommitScopes, readOptionalFile, + resolveCharterFile, readCharterObjectives, summarizeReadme, buildSignalAuthority, @@ -153,11 +154,11 @@ describe("readCharterObjectives", () => { beforeEach(() => { repo = makeRepo(); }); afterEach(() => { fs.rmSync(repo, { recursive: true, force: true }); }); - it("returns empty when CHARTER.md is absent", () => { + it("returns empty when spec/charter.md and legacy CHARTER.md are absent", () => { assert.deepEqual(readCharterObjectives(repo), []); }); - it("parses validated/active/deferred objectives", () => { + it("parses validated/active/deferred objectives from spec/charter.md", () => { const charter = `--- revision: 1 --- @@ -169,13 +170,23 @@ revision: 1 - O2 [active] outcome two · src: user - O3 [deferred] outcome three deferred to follow-up `; - write(repo, "CHARTER.md", charter); + write(repo, "spec/charter.md", charter); const objectives = readCharterObjectives(repo); assert.equal(objectives.length, 3); assert.equal(objectives[0].id, "O1"); assert.equal(objectives[0].status, "validated"); assert.match(objectives[0].predicate, /outcome one/); }); + + it("falls back to legacy root CHARTER.md", () => { + write(repo, "CHARTER.md", "- O1 [active] legacy objective · src: user\n"); + const resolved = resolveCharterFile(repo); + assert.equal(resolved.found, true); + assert.equal(resolved.source, "legacy"); + const objectives = readCharterObjectives(repo); + assert.equal(objectives.length, 1); + assert.equal(objectives[0].id, "O1"); + }); }); describe("summarizeReadme", () => { @@ -236,23 +247,24 @@ describe("buildSignalAuthority", () => { assert.match(harness.note, /does not create product capability boundaries/); }); - it("labels an objective-empty CHARTER.md as found product authority", () => { + it("labels an objective-empty spec/charter.md as found product authority", () => { const authority = buildSignalAuthority({ readmeFound: false, charterFound: true, + charterSource: "canonical", harnessFiles: [], sourceRoot: null, commitsScanned: 0, }); - const charter = authority.find((entry) => entry.signal === "CHARTER.md"); + const charter = authority.find((entry) => entry.signal === "spec/charter.md"); assert.equal(charter.authority, "product"); assert.equal(charter.found, true); }); }); describe("buildCapability", () => { - it("includes a CHARTER objective hint when objectives are present", () => { + it("includes a charter objective hint when objectives are present", () => { const cap = buildCapability({ name: "auth", sourceRootName: "src", @@ -335,12 +347,12 @@ describe("extractSignals — integration fixtures", () => { assert.equal(result.capabilities.length, 0); }); - it("brownfield-full: README + CLAUDE.md + src/ + commits + CHARTER", () => { + it("brownfield-full: README + CLAUDE.md + src/ + commits + spec charter", () => { write(repo, "README.md", "# Project\n\nA logging pipeline.\n"); write(repo, "CLAUDE.md", "# Conventions\n\nUse pino.\n"); mkdir(repo, "src/ingest"); mkdir(repo, "src/storage"); - write(repo, "CHARTER.md", `--- + write(repo, "spec/charter.md", `--- revision: 1 --- ## Objectives @@ -362,6 +374,7 @@ revision: 1 assert.equal(result.inventory.readmeFound, true); assert.equal(result.inventory.charterFound, true); + assert.equal(result.inventory.charterSource, "canonical"); assert.equal(result.inventory.claudeMdFound, true); assert.deepEqual(result.inventory.harnessFiles, ["CLAUDE.md"]); assert.equal(result.inventory.sourceRoot, "src"); @@ -385,8 +398,8 @@ revision: 1 assert.equal(harness.found, true); }); - it("reports CHARTER.md as found even when it has no Objectives", () => { - write(repo, "CHARTER.md", "# Charter\n\n## Decisions\n"); + it("reports spec/charter.md as found even when it has no Objectives", () => { + write(repo, "spec/charter.md", "# Charter\n\n## Decisions\n"); const result = extractSignals({ repoRoot: repo, @@ -396,7 +409,7 @@ revision: 1 assert.equal(result.inventory.charterFound, true); assert.equal(result.inventory.charterObjectiveCount, 0); assert.equal( - result.signal_authority.find((entry) => entry.signal === "CHARTER.md").found, + result.signal_authority.find((entry) => entry.signal === "spec/charter.md").found, true, ); }); diff --git a/skills/spec-grill/templates/capabilities.md b/skills/spec-grill/templates/capabilities.md index 1e13d74..dbf35df 100644 --- a/skills/spec-grill/templates/capabilities.md +++ b/skills/spec-grill/templates/capabilities.md @@ -1,6 +1,6 @@ # Capabilities -This file is the middle layer between `CHARTER.md` (north star) and the active sprint (this week's tasks). Each capability describes one subsystem buckets-worth of work with a frozen-ish contract and a structurally-bounded live-feedback channel. +This file is the middle layer between `spec/charter.md` (north star) and the active sprint (this week's tasks). Each capability describes one subsystem buckets-worth of work with a frozen-ish contract and a structurally-bounded live-feedback channel. Use loose prose and strict handles. Goal, scope, behaviors, sprint Plan, and Running Context are where agents can explain nuance. Capability IDs and sprint `component:` values are routing handles: use one lowercase slug such as `sprint-execution`, not a sentence or comma-separated list. @@ -11,7 +11,7 @@ Mutation discipline (matches the design doc): | `Goal`, `In-scope`, `Out-of-scope` | human via `spec-grill` | when the contract changes | challenge + confirm + apply | | `Expected Behaviors`, `Hard Constraints` | human via grill | when a behavior or bright-line changes | grill + 3-axis predicate test | | `## Learnings` (between magic markers) | `append-learnings.js` only | end of every successful relay run tagged with this primary capability slug | structurally bounded append; rejects writes outside markers | -| `## Decisions` | human, append-only | when a capability-level decision is made | append-only by convention; promote to CHARTER if cross-cutting | +| `## Decisions` | human, append-only | when a capability-level decision is made | append-only by convention; promote to `spec/charter.md` if cross-cutting | Compactness budget: diff --git a/skills/spec-system-map/SKILL.md b/skills/spec-system-map/SKILL.md new file mode 100644 index 0000000..070dba4 --- /dev/null +++ b/skills/spec-system-map/SKILL.md @@ -0,0 +1,68 @@ +--- +name: spec-system-map +argument-hint: "[create|amend]" +description: "Create or amend spec/system-map.md as a high-level project system map. Use for architecture scope confusion, system shape, runtime boundaries, core flows, invariants, storage/external systems, or SYSTEM_MAP." +compatibility: Requires git. Works on Claude Code and Codex. +metadata: + related-skills: "spec-charter, spec-grill, dev-backlog" +--- + +# Spec System Map + +Create or amend `spec/system-map.md`, the high-level map of how the project is shaped. This is narrower than a generic `ARCHITECTURE.md`: it names project-wide structure, boundaries, flows, storage/external systems, invariants, and pointers to deeper docs. + +## Boundary + +| File | Role | +|------|------| +| `spec/charter.md` | Why / good state / Objectives / Decisions | +| `spec/system-map.md` | System shape / runtime boundaries / core flows / invariants / pointers | +| `spec/capabilities.md` | Capability-level contracts / Hard Constraints / Learnings | + +Do not turn `system-map.md` into exhaustive module documentation, API reference, runbook, ADR log, or implementation notes. Demote subsystem detail to linked docs; promote only project-wide structure or invariants. + +## Mode Router + +- `create`: use when `spec/system-map.md` is absent or the user asks for a first system map. +- `amend`: use when the file exists and the user asks to update architecture shape, boundaries, flows, invariants, or links. + +When no mode is specified, route by file state. Create `spec/` if needed. + +## Create Mode + +1. Read bounded signals: `spec/charter.md` if present, `README.md`, `AGENTS.md`/`CLAUDE.md`, top-level directories, package/config files, and existing docs that appear architecture-related. +2. Draft from `templates/system-map.md`; keep sections short and link out instead of expanding subsystem detail. +3. Include these sections: System Shape, Runtime Boundaries, Core Flows, Storage And External Systems, Project-Wide Invariants, Where To Go Next. +4. If the repo is brownfield, explicitly mark uncertain boundaries as assumptions rather than inventing detail. +5. Recommend `spec-grill` when the map reveals durable capability boundaries that are not yet in `spec/capabilities.md`. + +## Amend Mode + +1. Re-read `spec/system-map.md` and the concrete change evidence. +2. Update only project-wide shape, boundaries, flows, storage/external systems, invariants, or pointers. +3. Move low-level module details, endpoint lists, deployment commands, and temporary implementation notes out of the map. +4. If a change is really a capability contract, route it to `spec-grill`. If it changes why/good-state, route it to `spec-charter amend`. + +## Quality Checks + +Before finishing, verify: + +- A reader can understand the project shape in under 5 minutes. +- Every section names current project-wide facts, not aspirational design. +- The map links to deeper docs instead of copying them. +- No subsystem gets more detail than the whole-system flow needs. +- No stale module-level TODOs, endpoint inventories, or runbook commands are included. + +## Eval Prompts + +Use these as quick pressure tests when changing the skill or a generated map: + +- "Create a system map for an existing repo with many modules and no architecture docs." Expected: short `spec/system-map.md`, uncertainty labeled, subsystem details linked or deferred. +- "Update this map with a new helper function and endpoint." Expected: refuse or demote as too low-level unless it changes a project-wide flow or invariant. +- "Turn this ARCHITECTURE.md into spec/system-map.md." Expected: preserve high-level boundaries and flows, remove runbook/API/module inventories, add pointers. + +## References + +- `templates/system-map.md` — starting shape for `spec/system-map.md`. +- [`../spec-charter/SKILL.md`](../spec-charter/SKILL.md) — project charter lifecycle. +- [`../spec-grill/SKILL.md`](../spec-grill/SKILL.md) — capability-contract lifecycle. diff --git a/skills/spec-system-map/templates/system-map.md b/skills/spec-system-map/templates/system-map.md new file mode 100644 index 0000000..0b0b31e --- /dev/null +++ b/skills/spec-system-map/templates/system-map.md @@ -0,0 +1,30 @@ +# System Map + +## System Shape + + + +## Runtime Boundaries + +- `` owns . +- `` does not own . + +## Core Flows + +1. **:** ->
-> . +2. **:** ->
-> . + +## Storage And External Systems + +- ``: . + +## Project-Wide Invariants + +- +- + +## Where To Go Next + +- Product direction: [`charter.md`](charter.md) +- Capability contracts: [`capabilities.md`](capabilities.md) +- : []() diff --git a/spec/README.md b/spec/README.md new file mode 100644 index 0000000..507a827 --- /dev/null +++ b/spec/README.md @@ -0,0 +1,11 @@ +# Project Specs + +Durable project-level specs live here. Root docs stay focused on entrypoints and agent instructions. + +| File | Role | +| --- | --- | +| [`charter.md`](charter.md) | Why the project exists, what good looks like, Objectives, and project-wide Decisions. | +| [`system-map.md`](system-map.md) | High-level system shape: boundaries, flows, storage/external systems, invariants, and pointers. | +| [`capabilities.md`](capabilities.md) | Capability contracts: Goal, Scope, Expected Behaviors, Hard Constraints, Learnings, and Decisions. | + +Use `spec-charter` for `charter.md`, `spec-system-map` for `system-map.md`, and `spec-grill` for `capabilities.md`. diff --git a/spec/capabilities.md b/spec/capabilities.md index 3333e9c..3776a15 100644 --- a/spec/capabilities.md +++ b/spec/capabilities.md @@ -1,6 +1,6 @@ # dev-backlog Capabilities -The middle layer between [`CHARTER.md`](../CHARTER.md) and the active sprint. Each block describes one subsystem-worth of work with a frozen-ish contract and a structurally bounded live-feedback channel. +The middle layer between [`charter.md`](charter.md) and the active sprint. Each block describes one subsystem-worth of work with a frozen-ish contract and a structurally bounded live-feedback channel. Mutation discipline matches [`docs/spec-system-design.md`](../docs/spec-system-design.md): Goal/Scope/Behaviors/HardConstraints are human-gated via `spec-grill`; `## Learnings` is appended only by a bounded `append-learnings` writer between magic markers; `## Decisions` is append-only by convention. @@ -77,18 +77,18 @@ Capability headings are strict routing handles. Use one lowercase slug after `## ## Capability: spec-charter -**Goal:** A user creates, amends, or reassesses `CHARTER.md` through tier-gated discipline, and the file stays a 5-minute read. +**Goal:** A user creates, amends, or reassesses `spec/charter.md` through tier-gated discipline, and the file stays a 5-minute read. **In-scope:** - `spec-charter` create + amend + reassess modes - Three-tier discipline (Direction / Predicates / History) and the proof gate for Objective status advances - `check-size.js` budget enforcement after every amend -- Brownfield handoff guidance to `spec-grill` after initial CHARTER creation +- Brownfield handoff guidance to `spec-system-map` and `spec-grill` after initial charter creation **Out-of-scope:** - Authoring per-capability contracts in `spec/capabilities.md` (`spec-grill` capability) - Charter deletion — no supported path -- Reading `CHARTER.md` from sibling skills (each does it directly; this capability does not gate reads) +- Reading `spec/charter.md` from sibling skills (each does it directly; this capability does not gate reads) ### Expected Behaviors - After `amend` lands a real diff, `revision` increments by exactly 1 and `last_amended` advances to that day; a no-op invocation never bumps either field. @@ -106,24 +106,60 @@ Capability headings are strict routing handles. Use one lowercase slug after `## ### Decisions | date | decision | rationale | supersedes | | --- | --- | --- | --- | -| 2026-05-22 | CHARTER is a separate file at repo root, not merged into `_context.md` | Yardstick must stay <5-min; HOW-knowledge would dilute it | — | +| 2026-05-22 | CHARTER is a separate file, not merged into `_context.md` | Yardstick must stay <5-min; HOW-knowledge would dilute it | — | | 2026-05-22 | `backlog-charter` is a third sibling skill, not folded into `dev-backlog` | Different concern (axis lifecycle vs. execution) | — | -| 2026-05-29 | `backlog-charter` is renamed to `spec-charter` for CHARTER lifecycle work | The artifact is a project spec axis, not a backlog-only helper | 2026-05-22 | +| 2026-05-29 | `backlog-charter` is renamed to `spec-charter` for charter lifecycle work | The artifact is a project spec axis, not a backlog-only helper | 2026-05-22 | +| 2026-05-29 | New charter files live at `spec/charter.md`; root `CHARTER.md` is legacy fallback | Multiple project spec artifacts need one durable home under `spec/` | 2026-05-22 | + +--- + +## Capability: spec-system-map + +**Goal:** A user captures project-wide system shape in `spec/system-map.md` without letting it become an exhaustive architecture encyclopedia. + +**In-scope:** +- `spec-system-map` create + amend modes +- `spec/system-map.md` template and dogfood artifact +- Boundaries between charter, system map, and capability contracts +- Demotion of module details, endpoint lists, and runbook commands into linked docs + +**Out-of-scope:** +- Mutating `spec/charter.md` direction or Objectives (`spec-charter` capability) +- Authoring per-capability contracts (`spec-grill` capability) +- Replacing ADRs, runbooks, generated API docs, or implementation notes + +### Expected Behaviors +- Create mode writes `spec/system-map.md` and creates `spec/` when needed. +- The map includes System Shape, Runtime Boundaries, Core Flows, Storage And External Systems, Project-Wide Invariants, and Where To Go Next. +- Brownfield uncertainty is labeled as an assumption instead of filled with invented details. + +### Hard Constraints +- Never include exhaustive module inventories, endpoint lists, deployment commands, or temporary TODOs in `spec/system-map.md`. +- Never promote a subsystem detail unless it changes a project-wide boundary, flow, storage/external system, or invariant. + +### Learnings + + + +### Decisions +| date | decision | rationale | supersedes | +| --- | --- | --- | --- | +| 2026-05-29 | Use `system-map.md`, not `ARCHITECTURE.md`, for the high-level project map | The name narrows scope away from mixed architecture/runbook/module docs | — | --- ## Capability: spec-grill -**Goal:** A user turns existing repo signals into compact `spec/capabilities.md` capability contracts instead of stopping at a project-wide CHARTER. +**Goal:** A user turns existing repo signals into compact `spec/capabilities.md` capability contracts instead of stopping at a project-wide charter. **In-scope:** - `spec-grill` greenfield and brownfield capability authoring -- `extract-signals.js` raw candidate seeding from README, CHARTER, source roots, harness files, and commit scopes +- `extract-signals.js` raw candidate seeding from README, charter, source roots, harness files, and commit scopes - Capability admission, Goal/Scope interview, Expected Behaviors, and Hard Constraints - `templates/capabilities.md` and `references/capabilities.md` **Out-of-scope:** -- Mutating `CHARTER.md` direction or Objectives (`spec-charter` capability) +- Mutating `spec/charter.md` direction or Objectives (`spec-charter` capability) - Appending runtime Learnings after relay runs (bounded writer contract outside grill) - Treating directory names or commit scopes as accepted capabilities without interview admission @@ -149,11 +185,11 @@ Capability headings are strict routing handles. Use one lowercase slug after `## ## Capability: triage-grooming -**Goal:** Open Issues are classified, related, flagged stale, and aligned to CHARTER Objectives without humans maintaining a parallel triage spreadsheet. +**Goal:** Open Issues are classified, related, flagged stale, and aligned to charter Objectives without humans maintaining a parallel triage spreadsheet. **In-scope:** - `backlog-triage` collect / relate / stale / report / apply pipeline -- CHARTER-aware Alignment Check (Issue → active Objective mapping) +- Charter-aware Alignment Check (Issue → active Objective mapping) - Triage snapshots (v2 collector) and the advisory triage report artifact **Out-of-scope:** diff --git a/CHARTER.md b/spec/charter.md similarity index 84% rename from CHARTER.md rename to spec/charter.md index d5bf091..5338ed3 100644 --- a/CHARTER.md +++ b/spec/charter.md @@ -16,7 +16,7 @@ sessions is rebuilt from scratch each time. Keep GitHub Issues as the canonical task spec; add a thin, explicit, markdown-only execution hub (the active sprint file) that humans and agents both read and update. Companion skills (`backlog-triage`, `spec-charter`, -`spec-grill`) groom and orient the same GitHub-anchored state — they never +`spec-system-map`, `spec-grill`) groom and orient the same GitHub-anchored state — they never replace it. No server, no daemon, no hidden state, no silent sync. @@ -25,16 +25,16 @@ No server, no daemon, no hidden state, no silent sync. - A database, server, or background daemon — Markdown + bash + node built-ins only; no mystery state. - A lifecycle-owning workflow engine (Fractal / gsd-2 style) — those conflict with the GitHub-anchored model; their patterns are absorbed, never integrated. - Silent background sync — every pull and push is an explicit user action. -- A knowledge base / wiki replacement — `CHARTER.md` is a yardstick, `_context.md` is rediscovery-prone HOW-knowledge, neither is a long-form doc store. +- A knowledge base / wiki replacement — `spec/charter.md` is a yardstick, `_context.md` is rediscovery-prone HOW-knowledge, neither is a long-form doc store. - Per-vendor connectors (Jira, Linear, Notion) — out of scope, not the wedge. ## Objectives - O1 [validated] Claude Code, Codex, and humans read the same active sprint file as the single execution state · src: user - O2 [validated] GitHub Issues remain the canonical task spec; no parallel issue store exists in dev-backlog · src: user -- O3 [active] A user can answer "is this project still on track?" in under 5 minutes against a stable per-project reference axis (`CHARTER.md`) · src: user +- O3 [active] A user can answer "is this project still on track?" in under 5 minutes against a stable per-project reference axis (`spec/charter.md`) · src: user - O4 [active] Open-issue drift (orphan work, neglected objectives, contradictions) is detectable without manual triage · src: user -- O5 [deferred] Automated `reassess` of `CHARTER.md` wired into `relay-merge` / sprint completion — deferred to a follow-up spec -- O6 [deferred] `/goal` completion-condition auto-emission from `CHARTER.md` + active sprint — deferred to a follow-up spec +- O5 [deferred] Automated `reassess` of `spec/charter.md` wired into `relay-merge` / sprint completion — deferred to a follow-up spec +- O6 [deferred] `/goal` completion-condition auto-emission from `spec/charter.md` + active sprint — deferred to a follow-up spec ## Decisions | date | decision | rationale | supersedes | @@ -45,3 +45,4 @@ No server, no daemon, no hidden state, no silent sync. | 2026-05-22 | The Alignment Check is prompt-driven inside `backlog-triage`, not a new `triage-*.js` | Issue→objective mapping is semantic, unlike the deterministic relate/stale scripts | — | | 2026-05-22 | Patterns from Fractal and gsd-2 are absorbed, not integrated | Both own the whole project lifecycle and conflict with the GitHub-Issues-anchored model | — | | 2026-05-29 | `backlog-charter` splits into `spec-charter` and `spec-grill` | Existing-repo onboarding needs a discoverable second step from project charter to capability contracts | 2026-05-22 | +| 2026-05-29 | New charter files live at `spec/charter.md`; root `CHARTER.md` is legacy fallback | Charter, system map, and capabilities should share one project spec home under `spec/` | 2026-05-22 | diff --git a/spec/system-map.md b/spec/system-map.md new file mode 100644 index 0000000..8891568 --- /dev/null +++ b/spec/system-map.md @@ -0,0 +1,58 @@ +# dev-backlog System Map + +## System Shape + +dev-backlog is a skill suite plus deterministic helper scripts. GitHub Issues remain the canonical task source; local Markdown files provide execution context for humans and coding agents. + +```text +GitHub Issues + -> gh CLI explicit sync + -> backlog/tasks/ thin mirror + -> backlog/sprints/ active execution hub + -> humans / Claude Code / Codex + +spec/ + charter.md project yardstick + system-map.md project structure map + capabilities.md capability contracts +``` + +## Runtime Boundaries + +- `skills/dev-backlog/` owns sprint execution, task mirrors, and progress helper scripts. +- `skills/backlog-triage/` owns advisory issue grooming and charter Alignment reports. +- `skills/spec-charter/` owns `spec/charter.md` lifecycle and charter proof gates. +- `skills/spec-system-map/` owns this high-level system map. +- `skills/spec-grill/` owns `spec/capabilities.md` authoring. +- `spec/` holds durable project specs, not active sprint execution memory. + +## Core Flows + +1. **Sync:** `sync-pull.js` mirrors open GitHub Issues into `backlog/tasks/`. +2. **Plan:** sprint planning reads charter Objectives when present, then writes one active file under `backlog/sprints/`. +3. **Execute:** agents read the active sprint, update Plan state and Progress, and keep task context local. +4. **Groom:** `backlog-triage` produces advisory reports; mutations require explicit user action. +5. **Spec evolve:** `spec-charter`, `spec-system-map`, and `spec-grill` update durable project specs through their own gates. + +## Storage And External Systems + +- GitHub Issues: task source of truth. +- Git: versioned local Markdown artifacts and scripts. +- `gh` CLI: explicit GitHub read/write bridge. +- Node.js scripts: deterministic checks and sync helpers. +- Bash scripts: local workflow wrappers. + +## Project-Wide Invariants + +- No hidden server, database, daemon, or background sync. +- GitHub Issues define task intent; sprint files define execution context. +- `spec/charter.md` is canonical; root `CHARTER.md` is legacy fallback only. +- `spec/capabilities.md` remains compact enough to read at session start. +- Completed sprint files are immutable history. + +## Where To Go Next + +- Product direction: [`charter.md`](charter.md) +- Capability contracts: [`capabilities.md`](capabilities.md) +- Sprint execution contract: [`../skills/dev-backlog/SKILL.md`](../skills/dev-backlog/SKILL.md) +- Spec-system rationale: [`../docs/spec-system-design.md`](../docs/spec-system-design.md)