From b5d8021433817a8278fe0e2ece164cbca9e7ece3 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna Date: Mon, 17 Aug 2026 03:16:38 +0900 Subject: [PATCH 1/9] docs(knowledge): add frontmatter, lifecycle status/authority, and a generated index Roadmap items 4-6, 10: every knowledge doc now carries structured YAML frontmatter (status, authority, systems, owners, authorship) instead of a plain blockquote, so agents can tell what's current vs stale/superseded without reading the whole doc. knowledge/index.md is generated from that frontmatter by scripts/build-knowledge-index.mjs, wired into /write-doc's last step. --- .agents/skills/write-doc/SKILL.md | 11 +- .agents/skills/write-doc/doc-style.md | 29 ++++- .../skills/write-doc/templates/as-built.md | 17 ++- .../skills/write-doc/templates/design-doc.md | 18 ++- .../skills/write-doc/templates/product-doc.md | 17 ++- .agents/skills/write-doc/templates/runbook.md | 17 ++- knowledge/README.md | 83 ++++++++++++- knowledge/architecture/overview.md | 15 +++ knowledge/decisions/0000-template.md | 21 +++- knowledge/index.md | 33 ++++++ scripts/build-knowledge-index.mjs | 109 ++++++++++++++++++ 11 files changed, 356 insertions(+), 14 deletions(-) create mode 100644 knowledge/index.md create mode 100644 scripts/build-knowledge-index.mjs diff --git a/.agents/skills/write-doc/SKILL.md b/.agents/skills/write-doc/SKILL.md index ba70a55..9983c04 100644 --- a/.agents/skills/write-doc/SKILL.md +++ b/.agents/skills/write-doc/SKILL.md @@ -78,7 +78,7 @@ Run independent lookups in parallel. ## Step 4 — Draft 1. Copy the matching template and fill every section; delete the HTML guidance comments; drop genuinely empty optional sections rather than writing "N/A". -2. Apply [doc-style.md](doc-style.md) — no frontmatter, blockquote status line, Mermaid for diagrams, path+symbol citations, honest treatment of known gaps. +2. Apply [doc-style.md](doc-style.md) — YAML frontmatter, Mermaid for diagrams, path+symbol citations, honest treatment of known gaps. 3. For design docs, the **Cross-repo impact**, **Privacy & security**, and **Rollout & sequencing** sections are required for anything touching sensitive data, notifications, or billing/plans. --- @@ -98,10 +98,11 @@ git checkout -b Branch name: `-docs-` when a ticket exists (e.g. `ac-301-docs-invite-links`), otherwise `docs-`. -1. Write the doc file(s) to the target folder from the decision table. -2. Make the index edits in the same change: check off the matching `architecture/overview.md` "To document" item, and add a cross-link from the most closely related existing doc if one exists. -3. Show the user the doc (or a summary + path) for review. -4. Finish by suggesting `/raise-pr` — it detects the changes, commits, pushes, and opens the PR. Do not duplicate its logic here. +1. Write the doc file(s) to the target folder from the decision table, with frontmatter filled in per [doc-style.md](doc-style.md) (`authorship: ai-assisted`, `human_reviewed: false` unless a human is actively co-authoring in this session). +2. Make the index edits in the same change: check off the matching `architecture/overview.md` "To document" item, and add a cross-link (`related:` frontmatter and/or a "Related docs" section) from the most closely related existing doc if one exists. +3. Regenerate the generated index: `node scripts/build-knowledge-index.mjs`. +4. Show the user the doc (or a summary + path) for review. +5. Finish by suggesting `/raise-pr` — it detects the changes, commits, pushes, and opens the PR. Do not duplicate its logic here. --- diff --git a/.agents/skills/write-doc/doc-style.md b/.agents/skills/write-doc/doc-style.md index b50387b..ed05cf9 100644 --- a/.agents/skills/write-doc/doc-style.md +++ b/.agents/skills/write-doc/doc-style.md @@ -4,7 +4,7 @@ Apply this checklist to every doc drafted for the knowledge base. ## Format -- Plain markdown, **no YAML frontmatter** — a single `#` H1 title, then a `>` blockquote status/provenance line right under it (e.g. `> As-built, derived from code — 2026-07-05.`). +- Every doc opens with **YAML frontmatter** (schema below), then a `#` H1 title, then optionally a short `>` blockquote framing line if the frontmatter alone doesn't convey the doc's provenance (e.g. `> Reverse-engineered from code — verify before treating as spec.`). Don't restate `status`/`created` in the blockquote — that's what the frontmatter is for. - Markdown tables for any mapping (repo → role, endpoint → consumer, plan → limits). - **Diagrams are Mermaid fenced blocks** — GitHub renders them natively; never image files: - `sequenceDiagram` for cross-repo/message flows (client → service → storage → push) @@ -12,6 +12,33 @@ Apply this checklist to every doc drafted for the knowledge base. - `erDiagram` for non-trivial data models - Delete the template's HTML guidance comments after filling; drop optional sections that are genuinely empty rather than writing "N/A". +## Frontmatter schema + +Every field is required unless marked optional. See `knowledge/README.md` for the full definitions of status/authority/authorship. + +```yaml +--- +id: # decisions/ use adr-NNNN; others use the filename stem +title: +type: architecture | design | decision | runbook | product | release +status: draft | proposed | accepted | deprecated | superseded | archived +authority: canonical | supporting | generated | historical +systems: [<system-name>, ...] # from AGENTS.md's Systems table; [] if workspace-wide +owners: [<team-or-handle>, ...] +authorship: human | ai-assisted | generated +human_reviewed: true | false +created: YYYY-MM-DD +last_reviewed: YYYY-MM-DD +tags: [<tag>, ...] # optional +related: [<doc-id>, ...] # optional — ids of related docs/ADRs +superseded_by: <doc-id> # optional — only when status: superseded +--- +``` + +- `authorship: ai-assisted` + `human_reviewed: false` is the default for anything `/write-doc` generates that hasn't been read and confirmed by a person yet. Flip `human_reviewed` to `true` only when a human actually reviewed the content (e.g. approved the PR with a substantive review, not just merged it). +- Never mark a doc `authority: canonical` with `human_reviewed: false` — canonical status is a claim a human is willing to stand behind. +- Keep `last_reviewed` current when you materially edit a doc; leave `created` untouched. + ## Citing code - Cite as repo-relative path + symbol: `acme-api/services/invite.service.ts` `createInvite`. **No line numbers** — they rot. diff --git a/.agents/skills/write-doc/templates/as-built.md b/.agents/skills/write-doc/templates/as-built.md index a4fd161..6ba36a4 100644 --- a/.agents/skills/write-doc/templates/as-built.md +++ b/.agents/skills/write-doc/templates/as-built.md @@ -1,6 +1,21 @@ +--- +id: <feature-slug> +title: <Feature / topic name> +type: architecture +status: accepted +authority: supporting +systems: [<system-name>, ...] +owners: [] +authorship: ai-assisted +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +--- + # <Feature / topic name> -> As-built documentation, derived from code — <YYYY-MM-DD>. Items marked `TODO(verify: ...)` are unconfirmed. +> As-built documentation, derived from code. Items marked `TODO(verify: ...)` are unconfirmed. ## Overview diff --git a/.agents/skills/write-doc/templates/design-doc.md b/.agents/skills/write-doc/templates/design-doc.md index 8f51326..7c3bac8 100644 --- a/.agents/skills/write-doc/templates/design-doc.md +++ b/.agents/skills/write-doc/templates/design-doc.md @@ -1,6 +1,22 @@ +--- +id: <feature-slug> +title: <Feature title> +type: design +status: draft +authority: supporting +systems: [<system-name>, ...] +owners: [] +authorship: ai-assisted +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +related: [] +--- + # <Feature title> -> Status: Draft — <YYYY-MM-DD>. Ticket: <TICKET-ID or "none">. +> Ticket: <TICKET-ID or "none">. ## Summary diff --git a/.agents/skills/write-doc/templates/product-doc.md b/.agents/skills/write-doc/templates/product-doc.md index 8d81ce3..e83ad53 100644 --- a/.agents/skills/write-doc/templates/product-doc.md +++ b/.agents/skills/write-doc/templates/product-doc.md @@ -1,6 +1,19 @@ -# <Topic> +--- +id: <topic-slug> +title: <Topic> +type: product +status: accepted +authority: supporting +systems: [<system-name>, ...] +owners: [] +authorship: ai-assisted +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +--- -> Product doc — <YYYY-MM-DD>. +# <Topic> ## What it is diff --git a/.agents/skills/write-doc/templates/runbook.md b/.agents/skills/write-doc/templates/runbook.md index 73cd2b5..38c516f 100644 --- a/.agents/skills/write-doc/templates/runbook.md +++ b/.agents/skills/write-doc/templates/runbook.md @@ -1,6 +1,21 @@ +--- +id: <task-slug> +title: "Runbook: <task name>" +type: runbook +status: accepted +authority: supporting +systems: [<system-name>, ...] +owners: [] +authorship: ai-assisted +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +--- + # Runbook: <task name> -> Last verified: <YYYY-MM-DD> by <who>. +> Last verified by <who> — see `last_reviewed` above. ## When to use this diff --git a/knowledge/README.md b/knowledge/README.md index b311955..9bd816a 100644 --- a/knowledge/README.md +++ b/knowledge/README.md @@ -7,8 +7,9 @@ of the workspace). ## Structure -| Folder | Contents | +| Folder / file | Contents | |---|---| +| `index.md` | Generated entry point — start here instead of searching blindly. See [Index](#index). | | `architecture/` | System-level architecture: how the repos fit together, data flow, infra | | `design/` | Feature design documents (one file per feature/epic) | | `decisions/` | Architecture Decision Records (ADRs) — see the template | @@ -16,6 +17,22 @@ of the workspace). | `product/` | Product context: personas, feature specs, terminology, UX audits | | `releases/` | Release notes and store submission notes | +## Index + +`index.md` groups every doc by type and status (Architecture, Active Designs, +Accepted Decisions, Operational Runbooks, Product Knowledge, Recently +Reviewed, Deprecated/Superseded/Archived), generated from frontmatter. It's +**generated, not hand-edited** — run this after adding, removing, or changing +the status of any doc: + +```bash +node scripts/build-knowledge-index.mjs +``` + +`/write-doc` runs this automatically as its last step. Agents doing broad +"what do we know about X" retrieval should check `index.md` before searching, +per the retrieval policy in `AGENTS.md`. + ## Conventions - New design docs and ADRs land **here**, as markdown, via PR on a task @@ -26,6 +43,70 @@ of the workspace). it over writing docs by hand. - Legacy documents in external systems (Google Docs, Notion, ...): link them from the relevant markdown file rather than re-transcribing. +- Every doc carries YAML frontmatter — see [Frontmatter](#frontmatter) below. + `/write-doc`'s templates already include it; fill in every field. + +## Frontmatter + +Every file in `knowledge/` (except this README, `index.md`, and the ADR +template itself) opens with frontmatter agents can parse without reading the +whole doc: + +```yaml +--- +id: <kebab-slug> # decisions/ use adr-NNNN; others use the filename stem +title: <Title> +type: architecture | design | decision | runbook | product | release +status: draft | proposed | accepted | deprecated | superseded | archived +authority: canonical | supporting | generated | historical +systems: [<system-name>, ...] # names from AGENTS.md's Systems table; [] if workspace-wide +owners: [<team-or-handle>, ...] +authorship: human | ai-assisted | generated +human_reviewed: true | false +created: YYYY-MM-DD +last_reviewed: YYYY-MM-DD +tags: [<tag>, ...] # optional +related: [<doc-id>, ...] # optional +superseded_by: <doc-id> # optional — only when status: superseded +--- +``` + +### Status — is it current? + +| Status | Meaning | +|---|---| +| `draft` | Being written; not yet ready for review | +| `proposed` | Ready for review; not yet decided/adopted | +| `accepted` | Current and in effect | +| `deprecated` | Still true today, but on its way out — don't build on it | +| `superseded` | Replaced by another doc — see `superseded_by` | +| `archived` | Kept for history only; not applicable to current work | + +Agents: prefer `accepted` docs over anything else. Never treat `deprecated`, +`superseded`, or `archived` docs as current guidance — read them for +historical context only, and say so if you cite one. + +### Authority — how much to trust it + +| Authority | Meaning | +|---|---| +| `canonical` | The source of truth for its topic. Requires `human_reviewed: true`. | +| `supporting` | Useful and believed accurate, but not the final word. | +| `generated` | Machine-derived (e.g. an as-built doc from code reading); treat as a lead to verify, not a citation. | +| `historical` | Was true once; kept for context, not for current decisions. | + +Preference order when sources conflict: `canonical` > `supporting` > +`generated` > `historical`. An agent that finds a `generated` doc contradicting +a `canonical` one should trust the `canonical` one and flag the discrepancy +rather than silently picking either. + +### Authorship + +`authorship: ai-assisted` + `human_reviewed: false` is the default for +anything an agent writes. Flip `human_reviewed: true` only when a person +actually read and confirmed the content — approving a PR without comment +doesn't count. A doc can never be `authority: canonical` while +`human_reviewed: false`. ## When this outgrows the meta repo diff --git a/knowledge/architecture/overview.md b/knowledge/architecture/overview.md index 33d68f4..0c4864c 100644 --- a/knowledge/architecture/overview.md +++ b/knowledge/architecture/overview.md @@ -1,3 +1,18 @@ +--- +id: overview +title: System Overview +type: architecture +status: draft +authority: supporting +systems: [] +owners: [] +authorship: human +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +--- + # System Overview > Starter doc — fill in as the system takes shape. Items below marked unchecked are documentation gaps. diff --git a/knowledge/decisions/0000-template.md b/knowledge/decisions/0000-template.md index 2063fc5..d5d9113 100644 --- a/knowledge/decisions/0000-template.md +++ b/knowledge/decisions/0000-template.md @@ -1,7 +1,24 @@ +--- +id: adr-0000 +title: Title +type: decision +status: proposed +authority: canonical +systems: [<system-name>, ...] +owners: [] +authorship: human +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +related: [] +superseded_by: null +--- + # ADR-0000: Title -- **Status**: Proposed | Accepted | Superseded by ADR-XXXX -- **Date**: YYYY-MM-DD +> Status and date live in the frontmatter above — keep them in sync. + - **Deciders**: who was involved ## Context diff --git a/knowledge/index.md b/knowledge/index.md new file mode 100644 index 0000000..4967d29 --- /dev/null +++ b/knowledge/index.md @@ -0,0 +1,33 @@ +# Knowledge Index + +<!-- Generated by scripts/build-knowledge-index.mjs — do not edit by hand. + Regenerate after adding/editing docs. --> + +## Architecture + +- [System Overview](architecture/overview.md) — draft + +## Active Designs + +_None yet._ + +## Accepted Decisions + +_None yet._ + +## Operational Runbooks + +_None yet._ + +## Product Knowledge + +_None yet._ + +## Recently Reviewed + +- [System Overview](architecture/overview.md) — draft + +## Deprecated / Superseded / Archived + +_None yet._ + diff --git a/scripts/build-knowledge-index.mjs b/scripts/build-knowledge-index.mjs new file mode 100644 index 0000000..2c91662 --- /dev/null +++ b/scripts/build-knowledge-index.mjs @@ -0,0 +1,109 @@ +#!/usr/bin/env node +// Regenerates knowledge/index.md from the frontmatter of every doc in +// knowledge/. Run after adding/editing docs: `node scripts/build-knowledge-index.mjs` +// Requires Node 18+. No dependencies — parses only the flat scalar/list +// frontmatter shape used by the write-doc templates (see +// .agents/skills/write-doc/doc-style.md), not general YAML. + +import { readdirSync, statSync, readFileSync, writeFileSync } from "node:fs"; +import { join, relative, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const KNOWLEDGE_DIR = join(ROOT, "knowledge"); + +const SKIP_FILES = new Set(["README.md", "index.md", "0000-template.md"]); + +function walk(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + const st = statSync(full); + if (st.isDirectory()) { + out.push(...walk(full)); + } else if (entry.endsWith(".md") && !SKIP_FILES.has(entry)) { + out.push(full); + } + } + return out; +} + +// Parses `key: value`, `key: [a, b, c]`, and quoted scalars. Good enough for +// the flat frontmatter schema in knowledge/README.md — not a general parser. +function parseFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return null; + const fm = {}; + for (const line of match[1].split("\n")) { + const kv = line.match(/^([A-Za-z_]+):\s*(.*)$/); + if (!kv) continue; + const [, key, rawValue] = kv; + let value = rawValue.trim(); + if (value.startsWith("[") && value.endsWith("]")) { + value = value + .slice(1, -1) + .split(",") + .map((s) => s.trim().replace(/^["']|["']$/g, "")) + .filter(Boolean); + } else { + value = value.replace(/^["']|["']$/g, ""); + if (value === "true") value = true; + else if (value === "false") value = false; + else if (value === "null" || value === "") value = null; + } + fm[key] = value; + } + return fm; +} + +const files = walk(KNOWLEDGE_DIR); +const docs = []; +for (const file of files) { + const content = readFileSync(file, "utf8"); + const fm = parseFrontmatter(content); + const relPath = relative(ROOT, file); + if (!fm) { + docs.push({ path: relPath, missingFrontmatter: true }); + continue; + } + docs.push({ path: relPath, ...fm }); +} + +function section(title, items, render) { + if (items.length === 0) return `## ${title}\n\n_None yet._\n`; + return `## ${title}\n\n${items.map(render).join("\n")}\n`; +} + +const link = (d) => `- [${d.title || d.path}](${relative(KNOWLEDGE_DIR, join(ROOT, d.path))}) — ${d.status || "unknown status"}`; + +const withFm = docs.filter((d) => !d.missingFrontmatter); +const missing = docs.filter((d) => d.missingFrontmatter); + +const architecture = withFm.filter((d) => d.type === "architecture" && !["deprecated", "superseded", "archived"].includes(d.status)); +const designs = withFm.filter((d) => d.type === "design" && ["draft", "proposed"].includes(d.status)); +const decisions = withFm.filter((d) => d.type === "decision" && d.status === "accepted"); +const runbooks = withFm.filter((d) => d.type === "runbook" && !["deprecated", "superseded", "archived"].includes(d.status)); +const product = withFm.filter((d) => d.type === "product" && !["deprecated", "superseded", "archived"].includes(d.status)); +const deprecated = withFm.filter((d) => ["deprecated", "superseded", "archived"].includes(d.status)); + +const recent = [...withFm] + .filter((d) => d.last_reviewed || d.created) + .sort((a, b) => (b.last_reviewed || b.created || "").localeCompare(a.last_reviewed || a.created || "")) + .slice(0, 10); + +const out = `# Knowledge Index + +<!-- Generated by scripts/build-knowledge-index.mjs — do not edit by hand. + Regenerate after adding/editing docs. --> + +${section("Architecture", architecture, link)} +${section("Active Designs", designs, link)} +${section("Accepted Decisions", decisions, link)} +${section("Operational Runbooks", runbooks, link)} +${section("Product Knowledge", product, link)} +${section("Recently Reviewed", recent, link)} +${section("Deprecated / Superseded / Archived", deprecated, link)} +${missing.length > 0 ? `## Missing frontmatter\n\nThese docs have no frontmatter and are excluded from the sections above — add it (see \`knowledge/README.md\`):\n\n${missing.map((d) => `- ${d.path}`).join("\n")}\n` : ""}`; + +writeFileSync(join(KNOWLEDGE_DIR, "index.md"), out); +console.log(`Wrote knowledge/index.md (${docs.length} docs, ${missing.length} missing frontmatter)`); From eea2428bc8b0bf7423c84d8f253aa90cb34be537 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 03:18:30 +0900 Subject: [PATCH 2/9] docs(agents): define AGENTS.md as the AI control plane, add POLICY.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roadmap items 1-3, 7, 21: AGENTS.md now has a Commands table, Definition of Done pointer, and a concrete Semble retrieval policy (search before recursively reading, cite sources, prefer canonical docs). POLICY.md is new — Definition of Done, ADR triggers, verification-evidence and confidence reporting formats. Machine-enforceable policy (.ai/policies.yaml, risk-levels.yaml) is deferred to Phase 2, flagged as such. --- AGENTS.md | 65 +++++++++++++++++++++++++++++--- POLICY.md | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 13 +++++-- 3 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 POLICY.md diff --git a/AGENTS.md b/AGENTS.md index 196cccd..c8f131e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,12 +8,19 @@ Project values (name, org, repo list, ticket prefix, default branch) live in ## Systems <!-- TODO: fill in — one row per repo in your devrig.toml repos list. - Delete the example rows below once you've added your own. --> + Delete the example rows below once you've added your own. "Depends on" + lists other systems this one calls or shares data with — an agent + changing a system should check what depends on it before assuming a + change is isolated. --> -| Repo | What it is | Stack | -|---|---|---| -| _`example-api/`_ | _Backend API_ | _e.g. NestJS, PostgreSQL_ | -| _`example-web/`_ | _Web frontend_ | _e.g. Next.js, Tailwind_ | +| System | Repo | Purpose | Stack | Depends on | +|---|---|---|---|---| +| _api_ | _`example-api/`_ | _Backend API_ | _e.g. NestJS, PostgreSQL_ | — | +| _web_ | _`example-web/`_ | _Web frontend_ | _e.g. Next.js, Tailwind_ | _api_ | + +An agent should never have to guess which repo owns something, what stack it +uses, what it depends on, how to test it, or what "done" means for it — that's +what this file, the per-repo `AGENTS.md`, and [`POLICY.md`](POLICY.md) are for. Each system repo should carry its own `AGENTS.md` with stack/structure/gotcha details — read the relevant one(s) before working in that repo. A repo's @@ -27,11 +34,49 @@ All repos use the default branch named in `devrig.toml` (`DEFAULT_BRANCH`). Task branches follow `<ticket-id>-<type>-<short-title>`, all lowercase kebab-case (e.g. `ac-123-feature-user-invites`). +## Commands + +<!-- TODO: fill in per system — install, dev, test, lint, typecheck, build. + Agents should never have to guess these. Keep in sync with each repo's + own AGENTS.md, which is the source of truth for repo-specific detail. --> + +| System | Install | Test | Lint | Typecheck | Build | +|---|---|---|---|---|---| +| _api_ | | | | | | +| _web_ | | | | | | + ## Testing <!-- TODO: document how changes are validated per repo — test suites, commands, what runs in CI vs. locally. --> +## Definition of Done + +See [`POLICY.md`](POLICY.md#definition-of-done) — every task follows it, and +`/verify-change` checks it before a PR is raised. + +## Retrieval policy + +Before changing code or answering an architectural question: + +1. Read this file (workspace `AGENTS.md`). +2. Read the target repo's own `AGENTS.md`. +3. Identify which systems are affected (the table above). +4. Check [`knowledge/index.md`](knowledge/index.md) for relevant docs by type/status. +5. Search Semble (`mcp__semble__search`) for the task's terminology, in the + affected repos and with `--content docs` against `knowledge/`. +6. Search `knowledge/decisions/` for accepted ADRs touching the affected systems. +7. Search `knowledge/design/` for active (`draft`/`proposed`) design docs on the same topic. +8. Inspect only the source files retrieval actually surfaced as relevant — + don't recursively read a whole repo unless retrieval failed to find + anything and you have to fall back to browsing. +9. When answering or handing off a plan, cite the sources used (doc paths, + `repo/path:symbol`) — see `POLICY.md`'s audit section. + +Prefer `authority: canonical` docs over `supporting`, `generated`, or +`historical` ones when they conflict (see `knowledge/README.md`). Never treat +a `deprecated`, `superseded`, or `archived` doc as current guidance. + ## Knowledge graph (graphify) Enabled by the `graphify` toggle in `devrig.toml`. There is no single @@ -59,6 +104,16 @@ Rules: - The full skill lives in `.agents/skills/graphify/SKILL.md` (installed by `setup.sh` from the graphify CLI, so it's gitignored, not committed). +## Risk & agent permissions + +<!-- TODO (Phase 2): backfill with .ai/policies.yaml and .ai/risk-levels.yaml + once those exist. Until then, treat anything touching auth, billing, + schemas, or production infra as high-risk by default and confirm with + the user before proceeding, per POLICY.md. --> + +See [`POLICY.md`](POLICY.md) for what requires human approval and what's +forbidden outright. When in doubt about risk, ask rather than assume. + ## Knowledge base Design docs, architecture notes, ADRs, and runbooks live in [`knowledge/`](knowledge/) diff --git a/POLICY.md b/POLICY.md new file mode 100644 index 0000000..cab6118 --- /dev/null +++ b/POLICY.md @@ -0,0 +1,108 @@ +# Workspace Policy + +Human-readable policy for agents and contributors working in this workspace. +This file states the rules; nothing here is automatically enforced yet +(that's tracked separately — see the note at the bottom). + +## Definition of Done + +A task is complete only when: + +1. Relevant tests pass (see each system's row in `AGENTS.md`'s Commands table). +2. Lint passes. +3. Type checking passes, where the stack has it. +4. Build succeeds, where applicable. +5. Documentation impact has been evaluated — updated in `knowledge/` if the + change affects architecture, design, product behavior, or operations; or + explicitly noted as not needed. +6. ADR requirement has been evaluated — see below. +7. Verification evidence has been recorded (see `/verify-change`), not just + asserted. +8. A PR has been opened for every affected repo (`/raise-pr`). + +Agents should never report a task as "done" without this evidence attached — +see [Verification evidence](#verification-evidence). + +## Verification evidence + +Report verification as evidence, not assertion: + +```markdown +## Verification + +Unit tests: PASS — `npm test` +Lint: PASS — `npm run lint` +Typecheck: PASS — `npm run typecheck` +Build: PASS — `npm run build` +Documentation: Updated `knowledge/design/<doc>.md` +ADR: Not required — implementation-only change +``` + +If a check doesn't apply to the repo (no lint config, no build step), say so +explicitly rather than omitting the line silently. + +## ADR requirement + +An ADR (`knowledge/decisions/`) is required when a change: + +- Introduces or changes architecture spanning multiple systems +- Changes a database schema +- Changes authentication or authorization behavior +- Changes a public API contract or inter-service communication +- Touches major infrastructure or a framework choice +- Introduces or replaces a critical external service/dependency + +A PR for such a change must say either: + +``` +ADR: knowledge/decisions/NNNN-<slug>.md +``` + +or + +``` +ADR not required: <one-line reason> +``` + +## Confidence and uncertainty reporting + +When handing off work or answering a non-trivial question, state: + +```markdown +## Confidence + +High | Medium | Low + +## Assumptions + +- <anything taken as given without direct verification> + +## Unverified + +- <anything not directly checked, e.g. a production config> + +## Human attention required + +- <anything that changes user-facing behavior in a risky way> +``` + +## Sources and citations + +Answers to architectural or "where is X" questions should end with: + +``` +Sources: + +knowledge/decisions/000N-<slug>.md +knowledge/design/<slug>.md +<repo>/<path>:<symbol> +``` + +This gives traceability and lets a human spot-check without re-deriving the answer. + +--- + +*Phase 2 will add machine-enforceable policy: `.ai/policies.yaml` (forbidden +actions, approval-required actions, protected paths), `.ai/risk-levels.yaml`, +and CLI/CI enforcement on top of this document. Until then, this file is the +only enforcement — agents and reviewers are expected to actually follow it.* diff --git a/README.md b/README.md index 96d185e..09fd833 100644 --- a/README.md +++ b/README.md @@ -163,8 +163,11 @@ the knowledge only you have — the generated README's **"Customize this workspace"** section carries this same checklist into your workspace: - [ ] `AGENTS.md` — fill the **Systems** table (one row per repo: what it is, - stack) and the **Testing** section. This is the source of truth every - skill reads. Keep the generated README's "What's inside" table in sync. + stack, what it depends on), the **Commands** table, and the **Testing** + section. This is the source of truth every skill reads. Keep the + generated README's "What's inside" table in sync. +- [ ] `POLICY.md` — adjust the Definition of Done and ADR triggers to match + your team's actual bar (e.g. add a security-review requirement). - [ ] `.agents/skills/code-review/references/` and `.agents/skills/write-doc/references/` — one reference file per repo (copy `_example-repo.md`). The skills work without them but get much @@ -186,14 +189,16 @@ directly and re-run `./setup.sh`. |---|---| | `devrig.toml` | Your project config — the one file every tool reads | | `setup.sh` | Idempotent bootstrap/update script | -| `AGENTS.md` | Agent-agnostic source of truth (systems, branch rules, conventions) | +| `AGENTS.md` | Agent-agnostic source of truth (systems, commands, branch rules, retrieval policy) | +| `POLICY.md` | Definition of Done, ADR requirement, verification/confidence reporting | | `CLAUDE.md` | Claude Code specifics; imports `AGENTS.md` | | `.agents/skills/` | Canonical workflow skills (agent-agnostic) | | `.claude/` | Claude Code settings, agents, skill symlinks | | `.opencode/` | opencode agents and plugin config | | `.mcp.json` / `opencode.json` | MCP servers (issue tracker, semble) | | `git-hooks/` | Shared hooks for every repo (`core.hooksPath`): protected-branch pre-commit / pre-push, plus the graphify graph rebuilds | -| `knowledge/` | Markdown knowledge base (architecture, decisions, design, runbooks, product, releases) | +| `knowledge/` | Markdown knowledge base (architecture, decisions, design, runbooks, product, releases) — see `knowledge/index.md` | +| `scripts/` | Workspace maintenance scripts (e.g. `build-knowledge-index.mjs`) | | `<repo>/` (untracked) | Your project repos, cloned by `setup.sh` | ## Adding a skill From 71811a74f38d9599cd678a473e051970e582e3f7 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 03:20:53 +0900 Subject: [PATCH 3/9] feat(skills): add /plan-task and /verify-change, upgrade /start-task Roadmap items 8-10: separates the workflow into start-task (context gathering) -> plan-task (written plan, human gate) -> implement -> verify-change (evidence per POLICY.md) -> raise-pr, instead of going straight from ticket to code edits. /raise-pr now points at /verify-change's evidence before opening a PR. --- .agents/skills/plan-task/SKILL.md | 95 ++++++++++++++++++++++++ .agents/skills/raise-pr/SKILL.md | 4 ++ .agents/skills/start-task/SKILL.md | 49 ++++++++++++- .agents/skills/verify-change/SKILL.md | 100 ++++++++++++++++++++++++++ .claude/skills/plan-task | 1 + .claude/skills/verify-change | 1 + CLAUDE.md | 7 +- README.md | 2 +- 8 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 .agents/skills/plan-task/SKILL.md create mode 100644 .agents/skills/verify-change/SKILL.md create mode 120000 .claude/skills/plan-task create mode 120000 .claude/skills/verify-change diff --git a/.agents/skills/plan-task/SKILL.md b/.agents/skills/plan-task/SKILL.md new file mode 100644 index 0000000..b859cef --- /dev/null +++ b/.agents/skills/plan-task/SKILL.md @@ -0,0 +1,95 @@ +--- +name: plan-task +description: Turn gathered task context into a written plan before touching code — goal, affected systems, relevant knowledge/ADRs, files likely to change, proposed changes, risks, test strategy, and documentation impact. Use for anything non-trivial (multi-repo, schema/auth/billing changes, unclear scope) after /start-task, or whenever the user asks to "plan this task" / "write a plan before implementing". Skip for small, well-scoped changes. +--- + +# Plan a Task + +> Project values (ticket prefix, default branch, repo list) come from +> `devrig.toml` and `AGENTS.md` at the workspace root — read them; never assume. + +Produces a written plan an agent (or a human) implements against, instead of +rediscovering context mid-implementation. Complements Claude Code's native +plan mode — where available, presenting this plan through that flow (so the +user gets the same approve/edit gate) is preferred over dumping it as chat +text; on agent tools without a native plan mode, print it directly. + +## Usage + +`/plan-task` — uses context already gathered by `/start-task` in this session. +`/plan-task <TICKET-ID or description>` — gathers context first if `/start-task` wasn't run. + +## Step 1 — Ensure context exists + +If `/start-task`'s "Context gathered" block is already in this session, use it. +Otherwise run its Step 4 (Gather context) now — don't plan on a guess. + +## Step 2 — Read what retrieval found + +Per the retrieval policy in `AGENTS.md`: read the related ADRs and design +docs found, not just their titles. Read enough of each likely-affected file +to know its current shape — don't propose changes to code you haven't looked at. + +If retrieval found nothing relevant for a non-trivial task, say so explicitly +in the plan rather than proceeding on assumptions. + +## Step 3 — Draft the plan + +```markdown +## Goal + +<1-2 sentences: what this task achieves and why, from the ticket/request.> + +## Systems affected + +<rows from AGENTS.md's Systems table, plus anything depending on them.> + +## Relevant knowledge + +<knowledge/ docs read, with a one-line takeaway each — "none found" if genuinely none.> + +## Relevant ADRs + +<knowledge/decisions/ docs that constrain this work — "none found" if genuinely none.> + +## Files likely affected + +<repo/path — what changes there, one line each. Group by repo.> + +## Proposed changes + +<the approach, as concrete steps. Call out any alternative considered and why +it lost, if there was a real fork in the road.> + +## Risks + +<what could go wrong — breaking changes, cross-repo coordination, migration +order, rollback difficulty. "None identified" only if you actually checked +POLICY.md's risk triggers and none apply.> + +## Test strategy + +<which suites run (per AGENTS.md's Commands table), and any new test coverage +this task should add.> + +## Documentation impact + +<which knowledge/ docs need creating/updating, and whether this crosses +POLICY.md's ADR-required list. "None" only if genuinely nothing changes.> +``` + +Every claim in the plan should trace back to something actually read this +session — retrieval hits, `AGENTS.md`, or the ticket. Mark anything unverified +as `TODO(verify: ...)` rather than asserting it. + +## Step 4 — Get the plan approved + +Present the plan and wait for the user to approve, edit, or redirect before +implementing. Treat this as a real gate, not a formality — a plan the user +hasn't seen is not an approved plan. + +## Step 5 — Hand off + +Once approved, implement against the plan directly, or note that +`/verify-change` should run once implementation is done. Don't re-run context +gathering mid-implementation unless the plan turns out to be wrong. diff --git a/.agents/skills/raise-pr/SKILL.md b/.agents/skills/raise-pr/SKILL.md index 5e93501..5c1f729 100644 --- a/.agents/skills/raise-pr/SKILL.md +++ b/.agents/skills/raise-pr/SKILL.md @@ -19,6 +19,10 @@ description: Raise pull requests for the current task — detects which workspac Detects which workspace repos have changes for the current task, creates the task branch where needed, commits and pushes, then creates a PR on GitHub for every affected repo. +If `/verify-change` hasn't run yet this session, run it first — per +`POLICY.md`'s Definition of Done, a PR shouldn't go up with unverified or +failing checks. Include its evidence block in the PR description (Step 8). + --- ## Step 1 — Recall the ticket context diff --git a/.agents/skills/start-task/SKILL.md b/.agents/skills/start-task/SKILL.md index 1be684c..f5062e1 100644 --- a/.agents/skills/start-task/SKILL.md +++ b/.agents/skills/start-task/SKILL.md @@ -1,6 +1,6 @@ --- name: start-task -description: Start work on a Linear issue — verifies the issue exists, assigns it to you, moves it to In Progress, determines the task type, and syncs the default branch. +description: Start work on a Linear issue — verifies the issue exists, assigns it to you, moves it to In Progress, determines the task type, syncs the default branch, and gathers context (affected systems, related ADRs/designs, likely files, risks, test plan) before any code changes. --- # Start a Linear Issue @@ -109,3 +109,50 @@ git fetch origin <BASE> && git checkout -b <BASE> origin/<BASE> If that also fails, report the error and stop — do NOT fall back to `main` or any other branch. Confirm `<BASE>` is up to date. + +### 4. Gather context + +Before any code changes, collect enough context that `/plan-task` (or direct +implementation, for small tasks) doesn't start from zero. Run these in +parallel where possible — this follows the retrieval policy in `AGENTS.md`: + +1. **Systems** — from the issue title/description and labels, identify which + rows of `AGENTS.md`'s Systems table are affected, plus anything those + systems depend on. +2. **Repositories** — the repos backing the affected systems. +3. **Related ADRs** — search `knowledge/decisions/` (or check + `knowledge/index.md`'s Accepted Decisions section) for anything touching + the affected systems. +4. **Relevant designs** — search `knowledge/design/` and `mcp__semble__search + --content docs` for the issue's terminology. +5. **Related code** — `mcp__semble__search` in each affected repo for the + issue's terminology; note likely files, don't open every hit. +6. **Dependencies** — anything outside this task's control the work relies on + (a third-party API, another team's in-flight change, a migration). +7. **Risks** — flag if the issue touches auth, billing, schemas, or + production infra (see `POLICY.md`'s ADR requirement — these usually need one). +8. **Tests** — which test suite(s) (per `AGENTS.md`'s Commands table) cover + the affected systems. + +Do not recursively read whole repos — if search surfaces nothing, say so +rather than falling back to browsing everything. + +Report: + +```markdown +## Context gathered + +Ticket: <ID> — <title> +Systems: <affected systems> +Repositories: <repos> +Related ADRs: <paths, or "none found"> +Relevant designs: <paths, or "none found"> +Likely files: <repo/path, ...> +Dependencies: <external factors, or "none identified"> +Risks: <flags, or "none identified"> +Test plan: <suite(s) to run> +``` + +Suggest `/plan-task` next for anything non-trivial (multi-repo, schema/auth +changes, or unclear scope); small, well-scoped tasks can go straight to +implementation. diff --git a/.agents/skills/verify-change/SKILL.md b/.agents/skills/verify-change/SKILL.md new file mode 100644 index 0000000..cee2927 --- /dev/null +++ b/.agents/skills/verify-change/SKILL.md @@ -0,0 +1,100 @@ +--- +name: verify-change +description: Run the applicable tests, lint, typecheck, build, and security checks for the current change and report evidence in POLICY.md's format, instead of asserting a task is done. Use before /raise-pr, whenever the user asks to "verify this" / "run the checks" / "is this done", or as the last step of implementing a task. +--- + +# Verify a Change + +> Project values (ticket prefix, default branch, repo list) come from +> `devrig.toml` and `AGENTS.md` at the workspace root — read them; never assume. + +Closes the loop between "I made the change" and "it's actually done" per +`POLICY.md`'s Definition of Done. Never report a task complete without +running this. + +## Usage + +`/verify-change` — verifies every affected repo (same detection as `/raise-pr`). +`/verify-change <repo>` — verifies just one repo. + +## Step 1 — Detect affected repos + +Same detection as `/raise-pr`'s Step 2: a repo is affected if it has +uncommitted changes, is on a task branch, or has local commits ahead of +`origin/<BASE>`. Run the rest of this skill per affected repo. + +## Step 2 — Run the applicable checks + +For each affected repo, look up its commands in `AGENTS.md`'s Commands table +(or its own `AGENTS.md` if more specific). Run whichever of these the repo +actually has — do not invent a command it doesn't define, and do not skip one +it does define: + +```bash +<install> # only if dependencies changed +<test> +<lint> +<typecheck> +<build> +``` + +Run them in the order that fails fastest and cheapest first (typically lint → +typecheck → test → build), and stop reporting further steps as PASS once one +fails — a failed lint doesn't mean tests were also checked. + +If a repo has no test suite / no lint config / no typecheck / no build step, +say so explicitly — it's not a failure, but it must be stated, not omitted. + +## Step 3 — Security and sensitive-change checks + +Applicable when the diff touches auth, secrets/config, webhooks, or a new +external-facing endpoint (see `POLICY.md`'s ADR triggers and the code-review +skill's mandatory checks): + +- Scan the diff for hardcoded secrets/keys/tokens: `git diff --stat` + + targeted `grep` for common patterns, or defer to the repo's existing + secret-scanning if configured. +- Confirm any new webhook/callback endpoint verifies a signature server-side. +- Confirm any new/changed auth check verifies (not just decodes) tokens and + checks ownership/membership, not just "is logged in". + +If none of these apply to the diff, state "Security checks: not applicable to +this diff" rather than omitting the section. + +## Step 4 — Documentation and ADR evaluation + +Cross-check against `POLICY.md`: + +- Does this change match any of the ADR-required triggers? If yes, confirm an + ADR exists (`knowledge/decisions/`) or flag that one is missing — don't let + verification pass silently on a missing required ADR. +- Does `knowledge/` need updating for this change (design doc, runbook, + architecture doc)? If a doc was updated, confirm + `node scripts/build-knowledge-index.mjs` was run afterward. + +## Step 5 — Report evidence + +Use `POLICY.md`'s exact format, one block per affected repo: + +```markdown +## Verification — <repo> + +Unit tests: PASS — `<command>` +Lint: PASS — `<command>` +Typecheck: PASS — `<command>` +Build: PASS — `<command>` +Security checks: <PASS / not applicable> — <detail> +Documentation: <Updated <path> / Not required — reason> +ADR: <knowledge/decisions/NNNN-<slug>.md / Not required — reason> +``` + +Any line that isn't PASS must show the actual failure output (or a short +excerpt of it), not just "FAIL" — the next step is fixing it, not re-asserting +success. + +## Step 6 — Stop on failure + +If anything fails, fix it and re-run this skill from Step 2 for that repo — +do not proceed to `/raise-pr` with a failing check. If a failure is +pre-existing and unrelated to this change, say so explicitly and confirm with +the user before proceeding past it. diff --git a/.claude/skills/plan-task b/.claude/skills/plan-task new file mode 120000 index 0000000..f602fe9 --- /dev/null +++ b/.claude/skills/plan-task @@ -0,0 +1 @@ +../../.agents/skills/plan-task \ No newline at end of file diff --git a/.claude/skills/verify-change b/.claude/skills/verify-change new file mode 120000 index 0000000..b826312 --- /dev/null +++ b/.claude/skills/verify-change @@ -0,0 +1 @@ +../../.agents/skills/verify-change \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 7314246..859724f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,12 @@ This workspace also configures Claude-Code-only tooling not covered by `AGENTS.m `AGENTS.md`): use these for the corresponding workflows instead of reinventing them ad hoc. - `/start-task <TICKET-ID>` — fetch the ticket, assign it, move it to - In Progress, sync the default branch + In Progress, sync the default branch, and gather context (systems, ADRs, + designs, likely files, risks, test plan) + - `/plan-task` — turn gathered context into a written plan (goal, systems, + files, proposed changes, risks, test strategy) before implementing + - `/verify-change` — run tests/lint/typecheck/build/security checks and + report evidence per `POLICY.md`, before `/raise-pr` - `/raise-pr` — branch, commit, push, and open PRs for every affected repo - `/code-review` — review a PR, branch, or local diff (full or light mode) - `/write-doc` — write design docs, as-builts, ADRs, and runbooks into the diff --git a/README.md b/README.md index 09fd833..7e88669 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ stay untracked. Everything is configured from a single **`devrig.toml`** file. | | What you get | |---|---| -| 🧠 | **AI workflow skills** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (agent-agnostic in `.agents/skills/`, symlinked for Claude Code, opencode configured too) | +| 🧠 | **AI workflow skills** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (agent-agnostic in `.agents/skills/`, symlinked for Claude Code, opencode configured too) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — semantic code search agents use via MCP instead of grep-and-read | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — a knowledge graph per repo that agents query instead of grepping, kept fresh by git hooks | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — token-optimizing command proxy for Claude Code | From 121bf0373e4c44a0e53be87d152a6d409d62f270 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 03:30:53 +0900 Subject: [PATCH 4/9] feat(policy): machine-readable config, CI enforcement, evidence-based PRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roadmap Phase 2 (items 1-10): - .ai/{systems,commands,ownership,policies,risk-levels}.yaml mirror AGENTS.md/POLICY.md for tools/CI to parse reliably, validated against .ai/schemas/*.schema.json (scripts/validate-ai-config.mjs, no external deps — scripts/lib/yaml-lite.mjs + json-schema-lite.mjs). - scripts/validate-knowledge.mjs checks frontmatter completeness/enum validity, canonical-requires-human_reviewed, ADR id/filename consistency, broken internal links, and generated-index freshness. - scripts/check-adr-requirement.mjs fails a PR that touches a protected path (.ai/policies.yaml) without an ADR in the same diff. - .github/workflows/validate.yml and knowledge-check.yml wire both into CI. - POLICY.md fleshed out: policy areas, forbidden/approval-required actions, protected paths, risk levels, data handling, agent roles, and an enforcement-status table that's honest about what's still human-only. - /raise-pr's PR template now includes Systems affected, Testing (with /verify-change evidence), Risks, Documentation, ADR, and Rollback sections. - /plan-task's output now includes a Confidence/Assumptions/Unverified/ Human-attention-required block. --- .agents/skills/plan-task/SKILL.md | 18 ++++ .agents/skills/raise-pr/SKILL.md | 42 ++++++-- .ai/commands.yaml | 21 ++++ .ai/ownership.yaml | 10 ++ .ai/policies.yaml | 64 ++++++++++++ .ai/risk-levels.yaml | 27 +++++ .ai/schemas/commands.schema.json | 25 +++++ .ai/schemas/policies.schema.json | 29 ++++++ .ai/schemas/risk-levels.schema.json | 24 +++++ .ai/schemas/systems.schema.json | 26 +++++ .ai/systems.yaml | 22 ++++ .github/workflows/knowledge-check.yml | 29 ++++++ .github/workflows/validate.yml | 19 ++++ POLICY.md | 134 +++++++++++++++++++++++-- README.md | 9 +- scripts/check-adr-requirement.mjs | 73 ++++++++++++++ scripts/lib/json-schema-lite.mjs | 69 +++++++++++++ scripts/lib/yaml-lite.mjs | 111 +++++++++++++++++++++ scripts/validate-ai-config.mjs | 65 ++++++++++++ scripts/validate-knowledge.mjs | 138 ++++++++++++++++++++++++++ 20 files changed, 939 insertions(+), 16 deletions(-) create mode 100644 .ai/commands.yaml create mode 100644 .ai/ownership.yaml create mode 100644 .ai/policies.yaml create mode 100644 .ai/risk-levels.yaml create mode 100644 .ai/schemas/commands.schema.json create mode 100644 .ai/schemas/policies.schema.json create mode 100644 .ai/schemas/risk-levels.schema.json create mode 100644 .ai/schemas/systems.schema.json create mode 100644 .ai/systems.yaml create mode 100644 .github/workflows/knowledge-check.yml create mode 100644 .github/workflows/validate.yml create mode 100644 scripts/check-adr-requirement.mjs create mode 100644 scripts/lib/json-schema-lite.mjs create mode 100644 scripts/lib/yaml-lite.mjs create mode 100644 scripts/validate-ai-config.mjs create mode 100644 scripts/validate-knowledge.mjs diff --git a/.agents/skills/plan-task/SKILL.md b/.agents/skills/plan-task/SKILL.md index b859cef..57405eb 100644 --- a/.agents/skills/plan-task/SKILL.md +++ b/.agents/skills/plan-task/SKILL.md @@ -76,6 +76,24 @@ this task should add.> <which knowledge/ docs need creating/updating, and whether this crosses POLICY.md's ADR-required list. "None" only if genuinely nothing changes.> + +## Confidence + +<High | Medium | Low — per POLICY.md's confidence/uncertainty reporting.> + +## Assumptions + +<anything taken as given without direct verification.> + +## Unverified + +<anything not directly checked — e.g. a config only readable in production.> + +## Human attention required + +<anything risky enough (per POLICY.md's risk levels) that a human should +look closely before/while it's implemented — "none" only if the risk level +is genuinely Low.> ``` Every claim in the plan should trace back to something actually read this diff --git a/.agents/skills/raise-pr/SKILL.md b/.agents/skills/raise-pr/SKILL.md index 5c1f729..2ff47e7 100644 --- a/.agents/skills/raise-pr/SKILL.md +++ b/.agents/skills/raise-pr/SKILL.md @@ -191,10 +191,12 @@ Examples: ### Description -Write a description aimed at an engineer reviewer. Structure it as follows: +Write a description aimed at an engineer reviewer, evidence-based per +`POLICY.md`'s Definition of Done — not just an assertion that it works. +Structure it as follows: ``` -## What +## What & why [1–3 sentence summary of what this PR does and why. Include the motivation or ticket context if inferable from commits.] @@ -202,19 +204,41 @@ Write a description aimed at an engineer reviewer. Structure it as follows: [Bullet list of the key implementation decisions — what was changed, added, or removed and the reasoning. Be specific: name files, functions, or APIs touched where helpful.] -## How to test +## Systems affected -[Step-by-step instructions a reviewer can follow to verify the changes work. Include: -- Setup steps if any (migrations, env vars, seed data) -- The specific flows to exercise (happy path and at least one edge case) -- What the expected outcome looks like] +[Rows from AGENTS.md's Systems table that this PR touches, plus anything depending on them. One repo, one line if this is single-repo.] + +## Testing + +[Step-by-step instructions a reviewer can follow to verify the changes work — setup steps, the flows to exercise (happy path + at least one edge case), expected outcome. Then the /verify-change evidence block if it was run this session:] + +Unit tests: PASS — `<command>` +Lint: PASS — `<command>` +Typecheck: PASS — `<command>` +Build: PASS — `<command>` + +## Risks + +[Breaking changes, cross-repo coordination, migration/deploy ordering, rollback difficulty — per POLICY.md's risk levels. "None identified" only if you actually checked and none apply.] + +## Documentation + +[knowledge/ docs added or updated, with paths — or "Not required: <reason>".] + +## ADR + +[knowledge/decisions/NNNN-<slug>.md if POLICY.md's ADR requirement applies — or "Not required: <reason>".] + +## Rollback + +[How to revert if this ships a problem — usually "revert this PR", but call out anything that makes rollback harder (irreversible migration, a mobile client that can't be force-upgraded).] ## Concerns / notes -[Any risks, trade-offs, known limitations, or things the reviewer should pay special attention to. If there are none, omit this section entirely.] +[Any trade-offs, known limitations, or things the reviewer should pay special attention to that don't fit above. If there are none, omit this section entirely.] ``` -Populate each section from the commit messages, diff, and any context available. Do not leave placeholder text — if a section has nothing meaningful to say, omit it rather than filling it with filler. +Populate each section from the commit messages, diff, `/verify-change`'s evidence (if run this session), and any context available. Do not leave placeholder text — if a section has nothing meaningful to say, write the explicit "Not required"/"None identified" form shown above rather than omitting it silently (the reviewer should see that it was considered, not guess). `Concerns / notes` is the one section that's fine to omit entirely when empty. --- diff --git a/.ai/commands.yaml b/.ai/commands.yaml new file mode 100644 index 0000000..06c5194 --- /dev/null +++ b/.ai/commands.yaml @@ -0,0 +1,21 @@ +# Structured mirror of AGENTS.md's Commands table. Agents should read this +# (or the table) instead of guessing a system's test/lint/build commands. +# Validate against .ai/schemas/commands.schema.json. +# +# TODO: fill in real commands per system; leave a key empty (or omit it) if +# that system genuinely has no such step (e.g. no typecheck on a plain JS repo). + +systems: + api: + install: npm ci + test: npm test + lint: npm run lint + typecheck: npm run typecheck + build: npm run build + + web: + install: npm ci + test: npm test + lint: npm run lint + typecheck: npm run typecheck + build: npm run build diff --git a/.ai/ownership.yaml b/.ai/ownership.yaml new file mode 100644 index 0000000..80c93c9 --- /dev/null +++ b/.ai/ownership.yaml @@ -0,0 +1,10 @@ +# Who owns what, by area rather than by repo (one area can span systems). +# Complements .ai/systems.yaml (system -> repo) and can later be reconciled +# against GitHub CODEOWNERS per repo. +# +# TODO: fill in your own areas/owners; delete the example below. + +areas: + authentication: + systems: [api, web] + owners: [backend-team] diff --git a/.ai/policies.yaml b/.ai/policies.yaml new file mode 100644 index 0000000..06f4197 --- /dev/null +++ b/.ai/policies.yaml @@ -0,0 +1,64 @@ +# Machine-readable policy. POLICY.md is the human-readable explanation of +# these same rules — keep both in sync. Validate against +# .ai/schemas/policies.schema.json. +# +# This file describes intent; nothing in this repo currently enforces it +# automatically beyond .github/workflows/knowledge-check.yml's protected-path +# ADR check. CLI/CI enforcement of forbidden_actions/approval_required is a +# gap — see the note in POLICY.md. + +forbidden_actions: + - commit_secrets + - force_push_default_branch + - disable_security_checks + - bypass_required_tests + - delete_audit_logs + - modify_production_data_directly + +approval_required: + - production_deployment + - authentication_change + - billing_change + - database_migration + - secret_rotation + - destructive_data_change + +# Reading is always permitted; modifying anything under these paths requires +# human approval regardless of an agent's assigned role. Glob syntax. +protected_paths: + - "infrastructure/production/**" + - "migrations/**" + - "auth/**" + - "billing/**" + - ".github/workflows/release.yml" + +# What data classification may go to which kind of model. "external_ai" means +# a hosted third-party model API; "local models" means self-hosted/on-prem. +data_handling: + public: + external_ai: allowed + internal: + external_ai: allowed + note: secrets and credentials stripped first + confidential: + external_ai: approved-providers-or-local-only + restricted: + external_ai: prohibited + note: agents should not access RESTRICTED data at all + +never_expose: + - api_keys + - passwords + - access_tokens + - private_keys + - production_db_exports + - customer_secrets + - sensitive_pii + +# Read-only vs read-write scope per agent role. See POLICY.md#agent-roles. +agent_roles: + planner: read_only + implementer: read_write_task_scoped + reviewer: read_only + documenter: knowledge_write + release_agent: approval_required diff --git a/.ai/risk-levels.yaml b/.ai/risk-levels.yaml new file mode 100644 index 0000000..ef1108b --- /dev/null +++ b/.ai/risk-levels.yaml @@ -0,0 +1,27 @@ +# Risk classification for changes. Requirements scale with risk — see +# POLICY.md#risk-levels for what each level requires (tests only vs. tests + +# ADR + human approval, etc). Validate against .ai/schemas/risk-levels.schema.json. + +low: + examples: + - documentation + - tests + - internal-refactor + +medium: + examples: + - dependency-upgrade + - api-behavior-change + +high: + examples: + - authentication + - database-migration + - billing + - production-infrastructure + +critical: + examples: + - secret-rotation + - destructive-data-change + - production-deployment diff --git a/.ai/schemas/commands.schema.json b/.ai/schemas/commands.schema.json new file mode 100644 index 0000000..13ea241 --- /dev/null +++ b/.ai/schemas/commands.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://devrig/.ai/schemas/commands.schema.json", + "title": "commands.yaml", + "type": "object", + "required": ["systems"], + "additionalProperties": false, + "properties": { + "systems": { + "type": "object", + "minProperties": 1, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "install": { "type": "string" }, + "test": { "type": "string" }, + "lint": { "type": "string" }, + "typecheck": { "type": "string" }, + "build": { "type": "string" } + } + } + } + } +} diff --git a/.ai/schemas/policies.schema.json b/.ai/schemas/policies.schema.json new file mode 100644 index 0000000..297115c --- /dev/null +++ b/.ai/schemas/policies.schema.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://devrig/.ai/schemas/policies.schema.json", + "title": "policies.yaml", + "type": "object", + "required": ["forbidden_actions", "approval_required", "protected_paths"], + "additionalProperties": false, + "properties": { + "forbidden_actions": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "approval_required": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "protected_paths": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "data_handling": { + "type": "object", + "additionalProperties": { + "type": "object", + "required": ["external_ai"], + "properties": { + "external_ai": { "type": "string" }, + "note": { "type": "string" } + } + } + }, + "never_expose": { "type": "array", "items": { "type": "string" } }, + "agent_roles": { + "type": "object", + "additionalProperties": { "type": "string" } + } + } +} diff --git a/.ai/schemas/risk-levels.schema.json b/.ai/schemas/risk-levels.schema.json new file mode 100644 index 0000000..6fa5879 --- /dev/null +++ b/.ai/schemas/risk-levels.schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://devrig/.ai/schemas/risk-levels.schema.json", + "title": "risk-levels.yaml", + "type": "object", + "required": ["low", "medium", "high", "critical"], + "additionalProperties": false, + "properties": { + "low": { "$ref": "#/$defs/level" }, + "medium": { "$ref": "#/$defs/level" }, + "high": { "$ref": "#/$defs/level" }, + "critical": { "$ref": "#/$defs/level" } + }, + "$defs": { + "level": { + "type": "object", + "required": ["examples"], + "additionalProperties": false, + "properties": { + "examples": { "type": "array", "items": { "type": "string" } } + } + } + } +} diff --git a/.ai/schemas/systems.schema.json b/.ai/schemas/systems.schema.json new file mode 100644 index 0000000..01fa36c --- /dev/null +++ b/.ai/schemas/systems.schema.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://devrig/.ai/schemas/systems.schema.json", + "title": "systems.yaml", + "type": "object", + "required": ["systems"], + "additionalProperties": false, + "properties": { + "systems": { + "type": "object", + "minProperties": 1, + "additionalProperties": { + "type": "object", + "required": ["repo", "purpose"], + "additionalProperties": false, + "properties": { + "repo": { "type": "string", "minLength": 1 }, + "purpose": { "type": "string", "minLength": 1 }, + "stack": { "type": "array", "items": { "type": "string" } }, + "depends_on": { "type": "array", "items": { "type": "string" } }, + "owns": { "type": "array", "items": { "type": "string" } } + } + } + } + } +} diff --git a/.ai/systems.yaml b/.ai/systems.yaml new file mode 100644 index 0000000..281abeb --- /dev/null +++ b/.ai/systems.yaml @@ -0,0 +1,22 @@ +# Structured mirror of AGENTS.md's Systems table — for scripts/CI to parse +# reliably (Markdown tables aren't). AGENTS.md stays the human-readable +# source; keep both in sync when you fill in your own systems. Validate +# against .ai/schemas/systems.schema.json. +# +# TODO: replace the example systems below with your own (one per repo in +# devrig.toml's `repos` list), then delete this comment block. + +systems: + api: + repo: example-api + purpose: Backend API + stack: [nestjs, postgresql] + depends_on: [] + owns: [] + + web: + repo: example-web + purpose: Web frontend + stack: [nextjs, tailwind] + depends_on: [api] + owns: [] diff --git a/.github/workflows/knowledge-check.yml b/.github/workflows/knowledge-check.yml new file mode 100644 index 0000000..72d25fd --- /dev/null +++ b/.github/workflows/knowledge-check.yml @@ -0,0 +1,29 @@ +name: Knowledge check + +on: + pull_request: + paths: + - "knowledge/**" + - ".ai/policies.yaml" + - "scripts/**" + +jobs: + validate-knowledge: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Validate frontmatter, links, ADR ids, and index freshness + run: node scripts/validate-knowledge.mjs + + - name: Require an ADR when a protected path changes + run: | + node scripts/check-adr-requirement.mjs \ + "${{ github.event.pull_request.base.sha }}" \ + "${{ github.event.pull_request.head.sha }}" diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..d188ed6 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,19 @@ +name: Validate + +on: + pull_request: + paths: + - ".ai/**" + +jobs: + validate-ai-config: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Validate .ai/*.yaml against .ai/schemas/ + run: node scripts/validate-ai-config.mjs diff --git a/POLICY.md b/POLICY.md index cab6118..1b0466c 100644 --- a/POLICY.md +++ b/POLICY.md @@ -1,8 +1,25 @@ # Workspace Policy Human-readable policy for agents and contributors working in this workspace. -This file states the rules; nothing here is automatically enforced yet -(that's tracked separately — see the note at the bottom). +The machine-readable mirror lives in `.ai/policies.yaml` and +`.ai/risk-levels.yaml` — keep both in sync when you edit either. CI enforces +what it can (`.github/workflows/validate.yml` validates the yaml against +`.ai/schemas/`; `.github/workflows/knowledge-check.yml` requires an ADR when a +protected path changes) — see [Enforcement status](#enforcement-status) for +what's still human-only. + +## Policy areas + +| Area | Question it answers | Where | +|---|---|---| +| Access | What may an agent read? | Everything in the workspace is readable by default; `RESTRICTED` data (below) is the one exception. | +| Actions | What can an agent modify, and what needs a human first? | [Forbidden actions](#forbidden-actions), [Approval-required actions](#approval-required-actions), [Agent roles](#agent-roles) | +| Data | What can be sent to external models? | [Data handling](#data-handling) | +| Quality | What must pass before a task is done? | [Definition of Done](#definition-of-done) | +| Knowledge | When must documentation change? | [ADR requirement](#adr-requirement), `knowledge/README.md` | +| Security | What's outright prohibited? | [Forbidden actions](#forbidden-actions), [Protected paths](#protected-paths) | +| Approval | When is a human required before proceeding? | [Approval-required actions](#approval-required-actions), [Risk levels](#risk-levels) | +| Audit | What evidence must be preserved? | [Verification evidence](#verification-evidence), [Sources and citations](#sources-and-citations) | ## Definition of Done @@ -64,6 +81,104 @@ or ADR not required: <one-line reason> ``` +## Forbidden actions + +An agent must never do any of the following, in this workspace or any +project repo, regardless of task or user instruction: + +- Commit secrets (API keys, tokens, `.env` files, credentials) +- Force-push the default branch +- Disable security checks (skip signature/webhook verification, remove auth checks) to make something pass +- Bypass required tests (`--no-verify`, commenting out a failing test, marking it skip) instead of fixing them +- Delete audit logs or verification evidence +- Modify production data directly (outside a reviewed migration/runbook) + +If asked to do one of these, refuse and explain why — see `.ai/policies.yaml`'s `forbidden_actions`. + +## Approval-required actions + +These require explicit human sign-off before proceeding, even if an agent is +technically capable of doing them: + +- Production deployment +- Authentication changes +- Billing changes +- Database migrations +- Secret rotation +- Destructive data changes + +See `.ai/policies.yaml`'s `approval_required` for the machine-readable list, +and [Agent roles](#agent-roles) for which roles hit this by default. + +## Protected paths + +Reading is always permitted. Modifying anything under these paths (see +`.ai/policies.yaml`'s `protected_paths` for the authoritative glob list — this +is the illustrative default) requires human approval: + +```text +infrastructure/production/** +migrations/** +auth/** +billing/** +.github/workflows/release.yml +``` + +`.github/workflows/knowledge-check.yml` enforces the mechanical half of this +for ADRs (protected path touched ⇒ an ADR must be in the same diff); it +can't judge whether human approval was actually obtained, so reviewers still +check that by hand. + +## Risk levels + +Requirements scale with risk. See `.ai/risk-levels.yaml` for the +machine-readable version. + +| Level | Examples | Minimum bar | +|---|---|---| +| Low | Documentation, tests, internal refactor | Definition of Done | +| Medium | Dependency upgrade, API behavior change | Definition of Done + explicit test coverage for the behavior change | +| High | Authentication, database migration, billing, production infrastructure | Definition of Done + ADR + human approval before merge | +| Critical | Secret rotation, destructive data change, production deployment | Definition of Done + ADR + human approval before **and** during execution (no unattended runs) | + +When a task's risk level is unclear, treat it as one level higher than your +first guess and say so — this is cheap insurance against under-classifying. + +## Data handling + +Classify data before sending anything to an external model provider: + +| Classification | External AI (hosted API) | +|---|---| +| `PUBLIC` | Allowed | +| `INTERNAL` | Allowed, with secrets/credentials stripped first | +| `CONFIDENTIAL` | Approved providers or local/self-hosted models only | +| `RESTRICTED` | Agent access prohibited outright | + +Never expose, to any model or in any doc/log an agent writes: API keys, +passwords, access tokens, private keys, production database exports, +customer secrets, or sensitive PII. See `.ai/policies.yaml`'s +`never_expose` / `data_handling` for the machine-readable version. + +## Agent roles + +Not every agent invocation needs full read-write access. Where your tooling +supports scoping it (e.g. a dedicated review agent, a read-only planning +pass): + +| Role | Scope | +|---|---| +| Planner | Read-only | +| Implementer | Read-write, scoped to the current task's repos/branch | +| Reviewer | Read-only diff analysis — independent from the implementer where possible | +| Documenter | Read-write to `knowledge/` | +| Release agent | Approval-required for every action (see [Approval-required actions](#approval-required-actions)) | + +See `.ai/policies.yaml`'s `agent_roles`. This workspace doesn't currently +enforce role separation mechanically (most agent tools run one role at a +time by convention, not by permission system) — treat it as a convention to +follow, not a control to rely on. + ## Confidence and uncertainty reporting When handing off work or answering a non-trivial question, state: @@ -102,7 +217,14 @@ This gives traceability and lets a human spot-check without re-deriving the answ --- -*Phase 2 will add machine-enforceable policy: `.ai/policies.yaml` (forbidden -actions, approval-required actions, protected paths), `.ai/risk-levels.yaml`, -and CLI/CI enforcement on top of this document. Until then, this file is the -only enforcement — agents and reviewers are expected to actually follow it.* +## Enforcement status + +| Rule | Enforced by | +|---|---| +| `.ai/*.yaml` matches its JSON Schema | CI (`.github/workflows/validate.yml`) | +| Knowledge frontmatter valid, links resolve, ADR ids unique, index fresh | CI (`.github/workflows/knowledge-check.yml`) | +| Protected path changed ⇒ ADR present in the same diff | CI (`.github/workflows/knowledge-check.yml`, via `scripts/check-adr-requirement.mjs`) — mechanical presence check only, not a judgment of adequacy | +| Everything else on this page (forbidden actions, approval-required actions, agent roles, data handling, DoD, verification evidence) | **Not mechanically enforced.** Agents and reviewers are expected to actually follow it; nothing in CI or the CLI currently blocks a violation. | + +Closing that last row — CLI wrappers or git hooks that check `.ai/policies.yaml` +before allowing an action — is future work, not yet built. diff --git a/README.md b/README.md index 7e88669..bb3a068 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,11 @@ workspace"** section carries this same checklist into your workspace: generated README's "What's inside" table in sync. - [ ] `POLICY.md` — adjust the Definition of Done and ADR triggers to match your team's actual bar (e.g. add a security-review requirement). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — replace + the example entries with your real systems/commands/owners (mirrors + `AGENTS.md`'s tables; `node scripts/validate-ai-config.mjs` checks the shape). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — adjust protected paths, + forbidden/approval-required actions, and risk examples for your project. - [ ] `.agents/skills/code-review/references/` and `.agents/skills/write-doc/references/` — one reference file per repo (copy `_example-repo.md`). The skills work without them but get much @@ -190,7 +195,9 @@ directly and re-run `./setup.sh`. | `devrig.toml` | Your project config — the one file every tool reads | | `setup.sh` | Idempotent bootstrap/update script | | `AGENTS.md` | Agent-agnostic source of truth (systems, commands, branch rules, retrieval policy) | -| `POLICY.md` | Definition of Done, ADR requirement, verification/confidence reporting | +| `POLICY.md` | Definition of Done, ADR requirement, risk/data/role policy, verification/confidence reporting | +| `.ai/` | Machine-readable mirror of the above (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`) plus their JSON Schemas in `.ai/schemas/` | +| `.github/workflows/` | CI: validates `.ai/*.yaml` against its schemas, and validates `knowledge/` (frontmatter, links, ADR ids, index freshness, protected-path ADR requirement) | | `CLAUDE.md` | Claude Code specifics; imports `AGENTS.md` | | `.agents/skills/` | Canonical workflow skills (agent-agnostic) | | `.claude/` | Claude Code settings, agents, skill symlinks | diff --git a/scripts/check-adr-requirement.mjs b/scripts/check-adr-requirement.mjs new file mode 100644 index 0000000..1930ad4 --- /dev/null +++ b/scripts/check-adr-requirement.mjs @@ -0,0 +1,73 @@ +#!/usr/bin/env node +// Fails if a diff touches a protected path (.ai/policies.yaml's +// protected_paths) without adding/changing anything under +// knowledge/decisions/ — a lightweight backstop for POLICY.md's ADR +// requirement. This catches the mechanical signal (protected path touched, +// no ADR in the same diff); it can't judge whether the ADR that WAS added +// actually covers the change — that's still a human/reviewer call. +// +// Usage: node scripts/check-adr-requirement.mjs <base-sha> <head-sha> + +import { readFileSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { execSync } from "node:child_process"; +import { parseYamlLite } from "./lib/yaml-lite.mjs"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); + +const [baseSha, headSha] = process.argv.slice(2); +if (!baseSha || !headSha) { + console.error("Usage: node scripts/check-adr-requirement.mjs <base-sha> <head-sha>"); + process.exit(2); +} + +function globToRegExp(glob) { + const escaped = glob + .split("**") + .map((part) => part.split("*").map((p) => p.replace(/[.+^${}()|[\]\\]/g, "\\$&")).join("[^/]*")) + .join(".*"); + return new RegExp(`^${escaped}$`); +} + +const policiesPath = join(ROOT, ".ai", "policies.yaml"); +let protectedPaths = []; +try { + const parsed = parseYamlLite(readFileSync(policiesPath, "utf8")); + protectedPaths = parsed.protected_paths ?? []; +} catch { + console.log("No .ai/policies.yaml protected_paths defined — skipping ADR-requirement check."); + process.exit(0); +} + +const changedFiles = execSync(`git -C "${ROOT}" diff --name-only ${baseSha} ${headSha}`) + .toString() + .trim() + .split("\n") + .filter(Boolean); + +const patterns = protectedPaths.map(globToRegExp); +const touchedProtected = changedFiles.filter((f) => patterns.some((re) => re.test(f))); + +if (touchedProtected.length === 0) { + console.log("No protected paths touched — ADR not required by this check."); + process.exit(0); +} + +const touchedAdr = changedFiles.some( + (f) => f.startsWith("knowledge/decisions/") && !f.endsWith("0000-template.md") +); + +if (touchedAdr) { + console.log(`Protected paths touched (${touchedProtected.join(", ")}) — ADR present in diff. OK.`); + process.exit(0); +} + +console.error( + `Protected path(s) touched without an ADR in the same diff:\n` + + touchedProtected.map((f) => ` - ${f}`).join("\n") + + `\n\nAdd an ADR under knowledge/decisions/ (see POLICY.md#adr-requirement), ` + + `or if this PR genuinely doesn't need one, note "ADR not required: <reason>" in the PR description ` + + `and have a human override this check.` +); +process.exit(1); diff --git a/scripts/lib/json-schema-lite.mjs b/scripts/lib/json-schema-lite.mjs new file mode 100644 index 0000000..b2fbd6f --- /dev/null +++ b/scripts/lib/json-schema-lite.mjs @@ -0,0 +1,69 @@ +// Minimal JSON Schema validator covering the subset used by .ai/schemas/*: +// type, required, properties, additionalProperties, items, minItems, +// minProperties, minLength, enum, and local $ref/$defs. Not general-purpose — +// enough to validate devrig's own config files without adding a dependency. + +function resolveRef(ref, root) { + const parts = ref.replace(/^#\//, "").split("/"); + return parts.reduce((node, part) => node?.[part], root); +} + +function typeOf(value) { + if (Array.isArray(value)) return "array"; + if (value === null) return "null"; + return typeof value; +} + +export function validate(schema, data, root = schema, path = "$") { + const errors = []; + if (schema.$ref) { + const resolved = resolveRef(schema.$ref, root); + if (!resolved) { + errors.push(`${path}: unresolved $ref "${schema.$ref}"`); + return errors; + } + return validate(resolved, data, root, path); + } + + if (schema.type && typeOf(data) !== schema.type) { + errors.push(`${path}: expected type "${schema.type}", got "${typeOf(data)}"`); + return errors; + } + + if (schema.enum && !schema.enum.includes(data)) { + errors.push(`${path}: value "${data}" not in enum [${schema.enum.join(", ")}]`); + } + + if (schema.type === "object" || (typeOf(data) === "object" && schema.properties)) { + for (const key of schema.required ?? []) { + if (!(key in data)) errors.push(`${path}: missing required property "${key}"`); + } + if (schema.minProperties && Object.keys(data).length < schema.minProperties) { + errors.push(`${path}: expected at least ${schema.minProperties} properties`); + } + for (const [key, value] of Object.entries(data)) { + if (schema.properties?.[key]) { + errors.push(...validate(schema.properties[key], value, root, `${path}.${key}`)); + } else if (schema.additionalProperties === false) { + errors.push(`${path}.${key}: unexpected property (additionalProperties: false)`); + } else if (schema.additionalProperties && typeof schema.additionalProperties === "object") { + errors.push(...validate(schema.additionalProperties, value, root, `${path}.${key}`)); + } + } + } + + if (schema.type === "array") { + if (schema.minItems && data.length < schema.minItems) { + errors.push(`${path}: expected at least ${schema.minItems} items, got ${data.length}`); + } + if (schema.items) { + data.forEach((item, i) => errors.push(...validate(schema.items, item, root, `${path}[${i}]`))); + } + } + + if (schema.type === "string" && schema.minLength && data.length < schema.minLength) { + errors.push(`${path}: string shorter than minLength ${schema.minLength}`); + } + + return errors; +} diff --git a/scripts/lib/yaml-lite.mjs b/scripts/lib/yaml-lite.mjs new file mode 100644 index 0000000..d820662 --- /dev/null +++ b/scripts/lib/yaml-lite.mjs @@ -0,0 +1,111 @@ +// Minimal indentation-based YAML reader for the flat/nested-map config +// shape used under .ai/ (mappings, block sequences, inline `[a, b]` lists, +// scalars). Not a general YAML parser — no anchors, multiline strings, +// flow mappings, or inline comments after a value. Good enough because +// devrig owns the shape of every file this reads. + +function stripComments(text) { + return text + .split("\n") + .filter((line) => line.trim() !== "" && !line.trim().startsWith("#")); +} + +function indentOf(line) { + return line.match(/^ */)[0].length; +} + +function parseScalar(raw) { + const s = raw.trim(); + if (s === "" || s === "null" || s === "~") return null; + if (s === "true") return true; + if (s === "false") return false; + if (s.startsWith("[") && s.endsWith("]")) { + const inner = s.slice(1, -1).trim(); + if (inner === "") return []; + return inner.split(",").map((item) => parseScalar(item.trim())); + } + if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s); + if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) { + return s.slice(1, -1); + } + return s; +} + +function splitKeyValue(content) { + const idx = content.indexOf(":"); + if (idx === -1) return null; + const key = content.slice(0, idx).trim(); + const rest = content.slice(idx + 1).trim(); + return [key, rest]; +} + +export function parseYamlLite(text) { + const rawLines = stripComments(text); + const lines = rawLines.map((line) => ({ indent: indentOf(line), content: line.trim() })); + + function parseBlock(pos, indent) { + if (pos >= lines.length || lines[pos].indent !== indent) { + return { value: null, pos }; + } + const isSequence = lines[pos].content === "-" || lines[pos].content.startsWith("- "); + if (isSequence) { + const arr = []; + while (pos < lines.length && lines[pos].indent === indent) { + const { content } = lines[pos]; + if (content !== "-" && !content.startsWith("- ")) break; + const itemContent = content === "-" ? "" : content.slice(2); + if (itemContent === "") { + const next = lines[pos + 1]; + if (next && next.indent > indent) { + const child = parseBlock(pos + 1, next.indent); + arr.push(child.value); + pos = child.pos; + continue; + } + arr.push(null); + pos++; + continue; + } + const kv = splitKeyValue(itemContent); + if (kv && kv[1] === "" && lines[pos + 1] && lines[pos + 1].indent > indent) { + // "- key:\n nested..." — rare; not used by devrig's own config files. + const child = parseBlock(pos + 1, lines[pos + 1].indent); + arr.push({ [kv[0]]: child.value }); + pos = child.pos; + } else { + arr.push(parseScalar(itemContent)); + pos++; + } + } + return { value: arr, pos }; + } + + const obj = {}; + while (pos < lines.length && lines[pos].indent === indent) { + const kv = splitKeyValue(lines[pos].content); + if (!kv) { + pos++; + continue; + } + const [key, rest] = kv; + if (rest === "") { + const next = lines[pos + 1]; + if (next && next.indent > indent) { + const child = parseBlock(pos + 1, next.indent); + obj[key] = child.value; + pos = child.pos; + continue; + } + obj[key] = null; + pos++; + continue; + } + obj[key] = parseScalar(rest); + pos++; + } + return { value: obj, pos }; + } + + if (lines.length === 0) return {}; + return parseBlock(0, lines[0].indent).value; +} diff --git a/scripts/validate-ai-config.mjs b/scripts/validate-ai-config.mjs new file mode 100644 index 0000000..f965ad6 --- /dev/null +++ b/scripts/validate-ai-config.mjs @@ -0,0 +1,65 @@ +#!/usr/bin/env node +// Validates every .ai/*.yaml file against its JSON Schema in .ai/schemas/. +// Run: node scripts/validate-ai-config.mjs +// Exits non-zero (and lists every error) if any file fails — used by +// .github/workflows/validate.yml. + +import { readFileSync, existsSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { parseYamlLite } from "./lib/yaml-lite.mjs"; +import { validate } from "./lib/json-schema-lite.mjs"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const AI_DIR = join(ROOT, ".ai"); + +const FILES = [ + { data: "systems.yaml", schema: "schemas/systems.schema.json" }, + { data: "commands.yaml", schema: "schemas/commands.schema.json" }, + { data: "policies.yaml", schema: "schemas/policies.schema.json" }, + { data: "risk-levels.yaml", schema: "schemas/risk-levels.schema.json" }, +]; + +let failed = false; + +for (const { data, schema } of FILES) { + const dataPath = join(AI_DIR, data); + const schemaPath = join(AI_DIR, schema); + if (!existsSync(dataPath)) { + console.log(`SKIP ${data} — not present`); + continue; + } + if (!existsSync(schemaPath)) { + console.error(`FAIL ${data} — no schema at .ai/${schema}`); + failed = true; + continue; + } + const parsed = parseYamlLite(readFileSync(dataPath, "utf8")); + const schemaJson = JSON.parse(readFileSync(schemaPath, "utf8")); + const errors = validate(schemaJson, parsed); + if (errors.length === 0) { + console.log(`PASS ${data}`); + } else { + console.error(`FAIL ${data}`); + for (const err of errors) console.error(` ${err}`); + failed = true; + } +} + +// ownership.yaml has no schema yet (Phase 2 didn't define one) — parse-check only. +const ownershipPath = join(AI_DIR, "ownership.yaml"); +if (existsSync(ownershipPath)) { + try { + parseYamlLite(readFileSync(ownershipPath, "utf8")); + console.log("PASS ownership.yaml (parses; no schema defined yet)"); + } catch (e) { + console.error(`FAIL ownership.yaml — ${e.message}`); + failed = true; + } +} + +if (failed) { + console.error("\n.ai config validation failed."); + process.exit(1); +} +console.log("\nAll .ai config files valid."); diff --git a/scripts/validate-knowledge.mjs b/scripts/validate-knowledge.mjs new file mode 100644 index 0000000..460ae9b --- /dev/null +++ b/scripts/validate-knowledge.mjs @@ -0,0 +1,138 @@ +#!/usr/bin/env node +// Validates knowledge/ against the frontmatter schema in knowledge/README.md: +// required fields present, enum values valid, canonical docs are +// human-reviewed, ADR ids/filenames match and are unique, internal links +// resolve, and index.md is up to date with the generated output. +// Run: node scripts/validate-knowledge.mjs — used by +// .github/workflows/knowledge-check.yml. + +import { readdirSync, statSync, readFileSync, existsSync } from "node:fs"; +import { join, relative, dirname, extname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { execSync } from "node:child_process"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const KNOWLEDGE_DIR = join(ROOT, "knowledge"); +const SKIP_FILES = new Set(["README.md", "index.md", "0000-template.md"]); + +const VALID_TYPES = ["architecture", "design", "decision", "runbook", "product", "release"]; +const VALID_STATUS = ["draft", "proposed", "accepted", "deprecated", "superseded", "archived"]; +const VALID_AUTHORITY = ["canonical", "supporting", "generated", "historical"]; +const VALID_AUTHORSHIP = ["human", "ai-assisted", "generated"]; + +function walk(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) out.push(...walk(full)); + else if (entry.endsWith(".md") && !SKIP_FILES.has(entry)) out.push(full); + } + return out; +} + +function parseFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return null; + const fm = {}; + for (const line of match[1].split("\n")) { + const kv = line.match(/^([A-Za-z_]+):\s*(.*)$/); + if (!kv) continue; + const [, key, rawValue] = kv; + let value = rawValue.trim(); + if (value.startsWith("[") && value.endsWith("]")) { + value = value + .slice(1, -1) + .split(",") + .map((s) => s.trim().replace(/^["']|["']$/g, "")) + .filter(Boolean); + } else { + value = value.replace(/^["']|["']$/g, ""); + if (value === "true") value = true; + else if (value === "false") value = false; + else if (value === "null" || value === "") value = null; + } + fm[key] = value; + } + return fm; +} + +const errors = []; +const files = walk(KNOWLEDGE_DIR); +const seenAdrIds = new Map(); + +for (const file of files) { + const relPath = relative(ROOT, file); + const content = readFileSync(file, "utf8"); + const fm = parseFrontmatter(content); + + if (!fm) { + errors.push(`${relPath}: missing frontmatter`); + continue; + } + + for (const field of ["id", "title", "type", "status", "authority", "authorship", "created", "last_reviewed"]) { + if (fm[field] === undefined || fm[field] === null || fm[field] === "") { + errors.push(`${relPath}: missing required frontmatter field "${field}"`); + } + } + if (fm.type && !VALID_TYPES.includes(fm.type)) errors.push(`${relPath}: invalid type "${fm.type}"`); + if (fm.status && !VALID_STATUS.includes(fm.status)) errors.push(`${relPath}: invalid status "${fm.status}"`); + if (fm.authority && !VALID_AUTHORITY.includes(fm.authority)) errors.push(`${relPath}: invalid authority "${fm.authority}"`); + if (fm.authorship && !VALID_AUTHORSHIP.includes(fm.authorship)) errors.push(`${relPath}: invalid authorship "${fm.authorship}"`); + if (fm.authority === "canonical" && fm.human_reviewed !== true) { + errors.push(`${relPath}: authority: canonical requires human_reviewed: true`); + } + if (fm.status === "superseded" && !fm.superseded_by) { + errors.push(`${relPath}: status: superseded requires a superseded_by id`); + } + + // Broken internal markdown links: [text](relative/path.md) + const linkRe = /\[[^\]]*\]\((?!https?:\/\/|#)([^)]+\.md)\)/g; + let m; + while ((m = linkRe.exec(content))) { + const target = join(dirname(file), m[1]); + if (!existsSync(target)) errors.push(`${relPath}: broken link to "${m[1]}"`); + } +} + +// ADR-specific checks: filename NNNN matches frontmatter id adr-NNNN, and ids are unique. +const decisionsDir = join(KNOWLEDGE_DIR, "decisions"); +if (existsSync(decisionsDir)) { + for (const entry of readdirSync(decisionsDir)) { + if (entry === "0000-template.md" || !entry.endsWith(".md")) continue; + const num = entry.match(/^(\d{4})-/)?.[1]; + const content = readFileSync(join(decisionsDir, entry), "utf8"); + const fm = parseFrontmatter(content); + if (!num) { + errors.push(`knowledge/decisions/${entry}: filename doesn't start with NNNN-`); + continue; + } + if (fm?.id && fm.id !== `adr-${num}`) { + errors.push(`knowledge/decisions/${entry}: frontmatter id "${fm.id}" doesn't match filename number (expected "adr-${num}")`); + } + if (fm?.id) { + if (seenAdrIds.has(fm.id)) { + errors.push(`knowledge/decisions/${entry}: duplicate ADR id "${fm.id}" (also in ${seenAdrIds.get(fm.id)})`); + } + seenAdrIds.set(fm.id, entry); + } + } +} + +// Generated index freshness: rebuild in-memory and diff against the committed file. +try { + execSync(`node "${join(ROOT, "scripts", "build-knowledge-index.mjs")}"`, { stdio: "pipe" }); + const gitDiff = execSync(`git -C "${ROOT}" status --porcelain -- knowledge/index.md`).toString().trim(); + if (gitDiff) { + errors.push(`knowledge/index.md is stale — run "node scripts/build-knowledge-index.mjs" and commit the result`); + } +} catch (e) { + errors.push(`could not check knowledge/index.md freshness: ${e.message}`); +} + +if (errors.length > 0) { + console.error(`Knowledge validation failed (${errors.length} issue(s)):\n`); + for (const e of errors) console.error(` - ${e}`); + process.exit(1); +} +console.log(`Knowledge validation passed (${files.length} docs checked).`); From ccd2a51072760df5f88e91043fed63e56e2c95a7 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 03:36:46 +0900 Subject: [PATCH 5/9] feat(knowledge): task context bundles, handoffs, capture-learning, drift/consistency checks Roadmap Phase 3 (items 4-10 in the phase list; 34-40 in the numbered roadmap): - /start-task now persists gathered context to .ai/context/<TICKET>.json so /plan-task (or a fresh session) can reuse it instead of re-running retrieval. - knowledge/handoffs/ + a handoff template (write-doc) for interrupted-task working state; surfaced in the generated index under "Active Handoffs". - /capture-learning: after a PR merges, asks the reflective questions (ADR? runbook? command/dependency change? recurring bug? stale docs?), writes what's confirmed via /write-doc, and cleans up the task's handoff/context files. - scripts/detect-doc-drift.mjs: non-blocking warnings for systems.yaml/ devrig.toml mismatches, dangling related/superseded_by ids, and docs past their (new, optional) `review_interval` frontmatter field. Wired into knowledge-check.yml as an informational step. - /check-knowledge-consistency: semantic pass (commands vs package.json, ownership vs CODEOWNERS, architecture vs repos, runbooks vs scripts, API docs vs routes, ADRs vs implementation) that the mechanical scripts can't do. --- .agents/skills/capture-learning/SKILL.md | 69 ++++++++ .../check-knowledge-consistency/SKILL.md | 100 ++++++++++++ .agents/skills/plan-task/SKILL.md | 5 +- .agents/skills/start-task/SKILL.md | 26 ++++ .agents/skills/write-doc/SKILL.md | 2 + .agents/skills/write-doc/doc-style.md | 3 +- .agents/skills/write-doc/templates/handoff.md | 56 +++++++ .ai/context/.gitkeep | 0 .claude/skills/capture-learning | 1 + .claude/skills/check-knowledge-consistency | 1 + .github/workflows/knowledge-check.yml | 3 + CLAUDE.md | 9 +- README.md | 6 +- knowledge/README.md | 25 ++- knowledge/handoffs/.gitkeep | 0 knowledge/index.md | 4 + scripts/build-knowledge-index.mjs | 4 +- scripts/detect-doc-drift.mjs | 147 ++++++++++++++++++ scripts/validate-knowledge.mjs | 2 +- 19 files changed, 450 insertions(+), 13 deletions(-) create mode 100644 .agents/skills/capture-learning/SKILL.md create mode 100644 .agents/skills/check-knowledge-consistency/SKILL.md create mode 100644 .agents/skills/write-doc/templates/handoff.md create mode 100644 .ai/context/.gitkeep create mode 120000 .claude/skills/capture-learning create mode 120000 .claude/skills/check-knowledge-consistency create mode 100644 knowledge/handoffs/.gitkeep create mode 100644 scripts/detect-doc-drift.mjs diff --git a/.agents/skills/capture-learning/SKILL.md b/.agents/skills/capture-learning/SKILL.md new file mode 100644 index 0000000..92a7b3e --- /dev/null +++ b/.agents/skills/capture-learning/SKILL.md @@ -0,0 +1,69 @@ +--- +name: capture-learning +description: After a PR merges, examine the completed change and decide whether permanent project knowledge should be preserved — a new ADR, an updated runbook, a changed command/dependency in .ai/, or an architecture doc that's now stale — then write it and clean up the task's handoff/context files. Use when the user says "capture learnings from this", "what should we document from this merge", after merging a PR, or when closing out a ticket. +--- + +# Capture Learning + +> Project values (ticket prefix, default branch, repo list) come from +> `devrig.toml` and `AGENTS.md` at the workspace root — read them; never assume. + +Closes the loop in `AGENTS.md`'s lifecycle: implement → verify → review → PR → +merge → **capture learning** → better context for the next task. This is the +one point where the workspace's own knowledge improves from doing the work, +instead of staying static until someone remembers to update a doc. + +## Usage + +`/capture-learning` — the merged PR/ticket is inferred from the current session or branch. +`/capture-learning <PR-URL or TICKET-ID>` — explicit target. + +## Step 1 — Resolve what happened + +Gather, in parallel: + +1. The merged PR's diff and description: `gh pr view <num> --json title,body,files,commits` and `gh pr diff <num>` (same resolution as `/code-review`'s Step 1 if only a branch/ticket is given). +2. The task's persisted context, if it exists: `.ai/context/<TICKET-ID>.json`. +3. The task's handoff doc, if it exists: `knowledge/handoffs/<TICKET-ID>.md`. +4. Any `/verify-change` evidence from this session. + +## Step 2 — Ask the reflective questions + +Go through each; answer from the actual diff/PR body, not speculation: + +| Question | If yes | +|---|---| +| Did we make an architectural decision (a real fork in the road, not just "how we implemented it")? | Draft an ADR — `/write-doc adr <decision>` | +| Did we discover an operational lesson (something that would help whoever's on call next)? | Add/update a runbook — `/write-doc runbook for <task>` | +| Did a command change (new script, changed test/build/lint invocation)? | Update `.ai/commands.yaml` and `AGENTS.md`'s Commands table | +| Did a system or dependency relationship change? | Update `.ai/systems.yaml` and `AGENTS.md`'s Systems table | +| Did we solve a recurring bug worth remembering? | Note it in the relevant architecture/runbook doc's known-gaps section (and remove the gap if it's now fixed) | +| Did this make existing architecture/design documentation inaccurate? | Update that doc directly; bump its `last_reviewed` | + +If every answer is genuinely no, say so and stop — don't manufacture a doc +for a purely mechanical change. Manufactured documentation is worse than none +(it erodes trust in `authority: canonical`). + +## Step 3 — Confirm scope + +If more than one item came back "yes", list them and let the user pick via +`AskUserQuestion` (multi-select) which to write now vs. skip — don't silently +write everything without a chance to review the list first. + +## Step 4 — Write it + +For each confirmed item, follow `/write-doc`'s normal flow (template, frontmatter, style) — don't duplicate its logic here, just feed it the right doc type and content. Set `authorship: ai-assisted`, `human_reviewed: false` unless a human is actively co-authoring. + +## Step 5 — Close out the task's working state + +- If `knowledge/handoffs/<TICKET-ID>.md` exists, delete it (the task is done, not interrupted) or set `status: archived` if the team prefers keeping history. +- If `.ai/context/<TICKET-ID>.json` exists, delete it — it's no longer useful once the task is merged. + +## Step 6 — Regenerate and land + +1. `node scripts/build-knowledge-index.mjs`. +2. Land all changes from this run on **one** branch (`<ticket-id>-docs-capture-learning`) and suggest `/raise-pr` — do not commit to the default branch. + +## Output + +Report what was captured (or "nothing worth capturing, here's why") and what was cleaned up (handoff/context files removed). diff --git a/.agents/skills/check-knowledge-consistency/SKILL.md b/.agents/skills/check-knowledge-consistency/SKILL.md new file mode 100644 index 0000000..f940856 --- /dev/null +++ b/.agents/skills/check-knowledge-consistency/SKILL.md @@ -0,0 +1,100 @@ +--- +name: check-knowledge-consistency +description: Compare the knowledge base and .ai/ config against actual repo state — ADRs vs implementation, architecture docs vs repos, runbooks vs scripts, documented API contracts vs actual routes, commands.yaml vs package.json, ownership.yaml vs CODEOWNERS — and report drift. Use when the user asks "are the docs still accurate", "find outdated documentation", "check knowledge consistency", or periodically as a health check. +--- + +# Check Knowledge Consistency + +> Project values (ticket prefix, default branch, repo list) come from +> `devrig.toml` and `AGENTS.md` at the workspace root — read them; never assume. + +Combines a mechanical pass (fast, deterministic) with a semantic pass (needs +an agent reading code) to catch documentation that's gone stale — the gap +`scripts/detect-doc-drift.mjs` can't close on its own because it can't read code. + +## Usage + +`/check-knowledge-consistency` — checks everything. +`/check-knowledge-consistency <system>` — scope to one system/repo. + +## Step 1 — Mechanical pass + +Run both, capture the output, don't re-derive what they already found: + +```bash +node scripts/validate-knowledge.mjs +node scripts/detect-doc-drift.mjs +``` + +## Step 2 — Semantic checks + +Run these per affected system/repo (in parallel where independent). Only +check repos that are actually cloned locally — note as "not checked (repo not +cloned)" for any that aren't, rather than skipping silently. + +**Commands ↔ package.json** — for each system in `.ai/commands.yaml`, read +that repo's `package.json` `scripts` and confirm every referenced `npm run +<script>` exists. Flag any command in `.ai/commands.yaml` that would fail. + +**Ownership ↔ CODEOWNERS** — if the repo has `.github/CODEOWNERS`, compare +the paths/owners there against `.ai/ownership.yaml`'s `areas`. Flag areas +whose owners disagree, and CODEOWNERS entries with no corresponding area. + +**Architecture docs ↔ repos** — for each `architecture/` doc's "Repos +involved"/systems table, confirm every named repo still exists in +`.ai/systems.yaml`/`devrig.toml`, and spot-check a few "Source pointers" — +does the cited path/symbol still exist? Use `mcp__semble__search` or a direct +file check, not a full re-read of the repo. + +**Runbooks ↔ scripts** — for each numbered step that runs a command or +script, confirm the script/file it references still exists at that path. + +**API docs ↔ API routes** — for each documented endpoint/event in an +as-built doc's "Contracts" section, `mcp__semble__search` the backing repo +for that exact name. Flag anything not found (renamed/removed) and, if you +have time, anything found in code but undocumented (new surface). + +**ADRs ↔ implementation** — for `accepted` ADRs touching a system under +review, spot-check whether the "Decision" is still what the code actually +does. Flag contradictions — don't assume an old ADR is still followed just +because no one marked it superseded. + +## Step 3 — Report + +Group findings by drift type, most actionable first: + +```markdown +## Knowledge consistency — <scope> + +### Mechanical (validate-knowledge / detect-doc-drift) +<pass-through of Step 1's output, only if non-empty> + +### Commands vs package.json +- <repo>: `.ai/commands.yaml` `test` runs `npm run test:unit`, but package.json has no such script — <file:line or "not found"> + +### Ownership vs CODEOWNERS +- <finding, or "consistent"> + +### Architecture vs repos +- <finding, or "consistent"> + +### Runbooks vs scripts +- <finding, or "consistent"> + +### API docs vs routes +- <finding, or "consistent"> + +### ADRs vs implementation +- <finding, or "consistent"> +``` + +Omit a subsection only if it was genuinely not applicable (e.g. no CODEOWNERS +file exists at all) — write "consistent" rather than omitting a section that +was actually checked and found nothing wrong, so the reader knows it was +checked. + +## Step 4 — Next step + +For each finding, suggest either `/write-doc` (doc needs updating) or +`/capture-learning` (if this surfaced during a task's wrap-up) rather than +fixing it inline here — this skill's job is to find drift, not resolve it. diff --git a/.agents/skills/plan-task/SKILL.md b/.agents/skills/plan-task/SKILL.md index 57405eb..b4b7abd 100644 --- a/.agents/skills/plan-task/SKILL.md +++ b/.agents/skills/plan-task/SKILL.md @@ -22,7 +22,10 @@ text; on agent tools without a native plan mode, print it directly. ## Step 1 — Ensure context exists If `/start-task`'s "Context gathered" block is already in this session, use it. -Otherwise run its Step 4 (Gather context) now — don't plan on a guess. +Otherwise check for a persisted bundle at `.ai/context/<ISSUE-ID>.json` (from +a prior `/start-task` run, possibly in an earlier session) and use that. If +neither exists, run `/start-task`'s Step 4 (Gather context) now — don't plan +on a guess. ## Step 2 — Read what retrieval found diff --git a/.agents/skills/start-task/SKILL.md b/.agents/skills/start-task/SKILL.md index f5062e1..adacc34 100644 --- a/.agents/skills/start-task/SKILL.md +++ b/.agents/skills/start-task/SKILL.md @@ -156,3 +156,29 @@ Test plan: <suite(s) to run> Suggest `/plan-task` next for anything non-trivial (multi-repo, schema/auth changes, or unclear scope); small, well-scoped tasks can go straight to implementation. + +### 5. Persist the context bundle + +Write the same information as JSON to `.ai/context/<ISSUE-ID>.json` (uppercase +ticket id, e.g. `.ai/context/AC-143.json`), so `/plan-task` and any other +agent picking up this ticket later in the same session or a fresh one can +reuse it instead of re-running retrieval: + +```json +{ + "ticket": "<ISSUE-ID>", + "title": "<title>", + "systems": ["<system>", ...], + "documents": ["<relevant design doc paths>"], + "decisions": ["<related ADR paths>"], + "likely_files": ["<repo/path>", ...], + "dependencies": ["<external factors>"], + "risk": "low | medium | high | critical", + "test_plan": ["<suite(s)>"] +} +``` + +This is working state for the task's branch, not permanent knowledge — it's +fine to commit alongside the task's other changes, and there's no need to +clean it up specially (it becomes stale/irrelevant once the branch merges, +same as the branch itself). diff --git a/.agents/skills/write-doc/SKILL.md b/.agents/skills/write-doc/SKILL.md index 9983c04..a644c89 100644 --- a/.agents/skills/write-doc/SKILL.md +++ b/.agents/skills/write-doc/SKILL.md @@ -21,6 +21,7 @@ its `README.md`). Output always lands on a task branch and is handed to - `/write-doc <what>` — e.g. `/write-doc how invite links work`, `/write-doc runbook for deploying the api` - `/write-doc <TICKET-ID>` — design doc from a Linear ticket - `/write-doc adr <decision>` — record an architecture decision +- `/write-doc handoff` — write a handoff doc for unfinished work (see `knowledge/README.md#handoffs`) - `/write-doc fill` — gap-fill mode: inventory missing docs and propose what to write next ## Doc-type decision table @@ -33,6 +34,7 @@ its `README.md`). Output always lands on a task branch and is handed to | Record/justify a decision ("we chose X over Y") | `decisions/` | copy `decisions/0000-template.md` | `NNNN-<short-title>.md` (next number) | | Operational procedure (deploy, restore, incident) | `runbooks/` | [templates/runbook.md](templates/runbook.md) | `<verb-slug>.md` (e.g. `deploy-api.md`) | | Product behavior, personas, terminology, plan rules | `product/` | [templates/product-doc.md](templates/product-doc.md) | `<topic-slug>.md` | +| Handing off unfinished work to another session/agent | `handoffs/` | [templates/handoff.md](templates/handoff.md) | `<ticket-id>.md` | | "Fill missing docs" / "what's undocumented" | (varies) | [Gap-fill mode](#gap-fill-mode) | (per pick) | Tie-breakers: not-yet-built → design doc; already shipped → as-built; "why did/should we" → ADR; "how do I operate/recover" → runbook. **If the intent is ambiguous between design (future) and as-built (present), ask the user one question before writing — the two land in different folders and must not be mixed.** diff --git a/.agents/skills/write-doc/doc-style.md b/.agents/skills/write-doc/doc-style.md index ed05cf9..b678074 100644 --- a/.agents/skills/write-doc/doc-style.md +++ b/.agents/skills/write-doc/doc-style.md @@ -20,7 +20,7 @@ Every field is required unless marked optional. See `knowledge/README.md` for th --- id: <kebab-slug> # decisions/ use adr-NNNN; others use the filename stem title: <Title> -type: architecture | design | decision | runbook | product | release +type: architecture | design | decision | runbook | product | release | handoff status: draft | proposed | accepted | deprecated | superseded | archived authority: canonical | supporting | generated | historical systems: [<system-name>, ...] # from AGENTS.md's Systems table; [] if workspace-wide @@ -32,6 +32,7 @@ last_reviewed: YYYY-MM-DD tags: [<tag>, ...] # optional related: [<doc-id>, ...] # optional — ids of related docs/ADRs superseded_by: <doc-id> # optional — only when status: superseded +review_interval: 180d # optional — see knowledge/README.md --- ``` diff --git a/.agents/skills/write-doc/templates/handoff.md b/.agents/skills/write-doc/templates/handoff.md new file mode 100644 index 0000000..d351a55 --- /dev/null +++ b/.agents/skills/write-doc/templates/handoff.md @@ -0,0 +1,56 @@ +--- +id: <ticket-id-slug> +title: "<TICKET-ID> Handoff" +type: handoff +status: accepted +authority: supporting +systems: [<system-name>, ...] +owners: [] +authorship: ai-assisted +human_reviewed: false +created: <YYYY-MM-DD> +last_reviewed: <YYYY-MM-DD> +tags: [] +--- + +# <TICKET-ID> Handoff + +> Delete this file (or set `status: archived`) once the task finishes — +> handoffs are working state for an interrupted task, not permanent knowledge. + +## Objective + +<!-- What this task is trying to achieve, in 1-2 sentences. --> + +## Completed + +<!-- What's actually done and verified — not "mostly done", be specific. --> + +## Current state + +<!-- Branch name(s), what's committed vs. uncommitted, what's deployed where. --> + +## Decisions + +<!-- Non-obvious choices made mid-task and why, so the next agent doesn't +re-litigate or accidentally reverse them. --> + +## Files changed + +<!-- repo/path — one line each, grouped by repo. --> + +## Tests run + +<!-- What was verified and how — reuse /verify-change's evidence format if it ran. --> + +## Remaining work + +<!-- Concrete next steps, in the order they should happen. --> + +## Known problems + +<!-- Anything broken, flaky, or half-finished that the next agent needs to know about. --> + +## Risks + +<!-- Anything risky per POLICY.md's risk levels that the next agent should treat carefully. --> diff --git a/.ai/context/.gitkeep b/.ai/context/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.claude/skills/capture-learning b/.claude/skills/capture-learning new file mode 120000 index 0000000..6802585 --- /dev/null +++ b/.claude/skills/capture-learning @@ -0,0 +1 @@ +../../.agents/skills/capture-learning \ No newline at end of file diff --git a/.claude/skills/check-knowledge-consistency b/.claude/skills/check-knowledge-consistency new file mode 120000 index 0000000..8f1e9a4 --- /dev/null +++ b/.claude/skills/check-knowledge-consistency @@ -0,0 +1 @@ +../../.agents/skills/check-knowledge-consistency \ No newline at end of file diff --git a/.github/workflows/knowledge-check.yml b/.github/workflows/knowledge-check.yml index 72d25fd..24b85a9 100644 --- a/.github/workflows/knowledge-check.yml +++ b/.github/workflows/knowledge-check.yml @@ -27,3 +27,6 @@ jobs: node scripts/check-adr-requirement.mjs \ "${{ github.event.pull_request.base.sha }}" \ "${{ github.event.pull_request.head.sha }}" + + - name: Surface documentation drift (informational — never fails) + run: node scripts/detect-doc-drift.mjs diff --git a/CLAUDE.md b/CLAUDE.md index 859724f..456ef33 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,8 +18,13 @@ This workspace also configures Claude-Code-only tooling not covered by `AGENTS.m report evidence per `POLICY.md`, before `/raise-pr` - `/raise-pr` — branch, commit, push, and open PRs for every affected repo - `/code-review` — review a PR, branch, or local diff (full or light mode) - - `/write-doc` — write design docs, as-builts, ADRs, and runbooks into the - knowledge base + - `/write-doc` — write design docs, as-builts, ADRs, runbooks, and handoffs + into the knowledge base + - `/capture-learning` — after a PR merges, decide what permanent knowledge + (ADR, runbook, `.ai/` config) should be preserved, then clean up the + task's handoff/context files + - `/check-knowledge-consistency` — compare knowledge/`.ai/` against actual + repo state (commands, ownership, architecture, runbooks, API contracts, ADRs) - `/create-ticket` — file well-formed epics, stories, tasks, and bugs - `/graphify` — build or query a repo's knowledge graph (see the **Knowledge graph** section in `AGENTS.md` for when to reach for it) diff --git a/README.md b/README.md index bb3a068..aaae2c1 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ stay untracked. Everything is configured from a single **`devrig.toml`** file. | | What you get | |---|---| -| 🧠 | **AI workflow skills** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (agent-agnostic in `.agents/skills/`, symlinked for Claude Code, opencode configured too) | +| 🧠 | **AI workflow skills** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (agent-agnostic in `.agents/skills/`, symlinked for Claude Code, opencode configured too) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — semantic code search agents use via MCP instead of grep-and-read | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — a knowledge graph per repo that agents query instead of grepping, kept fresh by git hooks | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — token-optimizing command proxy for Claude Code | @@ -196,7 +196,7 @@ directly and re-run `./setup.sh`. | `setup.sh` | Idempotent bootstrap/update script | | `AGENTS.md` | Agent-agnostic source of truth (systems, commands, branch rules, retrieval policy) | | `POLICY.md` | Definition of Done, ADR requirement, risk/data/role policy, verification/confidence reporting | -| `.ai/` | Machine-readable mirror of the above (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`) plus their JSON Schemas in `.ai/schemas/` | +| `.ai/` | Machine-readable mirror of the above (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), their JSON Schemas in `.ai/schemas/`, and per-task context bundles in `.ai/context/` (written by `/start-task`) | | `.github/workflows/` | CI: validates `.ai/*.yaml` against its schemas, and validates `knowledge/` (frontmatter, links, ADR ids, index freshness, protected-path ADR requirement) | | `CLAUDE.md` | Claude Code specifics; imports `AGENTS.md` | | `.agents/skills/` | Canonical workflow skills (agent-agnostic) | @@ -205,7 +205,7 @@ directly and re-run `./setup.sh`. | `.mcp.json` / `opencode.json` | MCP servers (issue tracker, semble) | | `git-hooks/` | Shared hooks for every repo (`core.hooksPath`): protected-branch pre-commit / pre-push, plus the graphify graph rebuilds | | `knowledge/` | Markdown knowledge base (architecture, decisions, design, runbooks, product, releases) — see `knowledge/index.md` | -| `scripts/` | Workspace maintenance scripts (e.g. `build-knowledge-index.mjs`) | +| `scripts/` | Workspace maintenance scripts — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs` | | `<repo>/` (untracked) | Your project repos, cloned by `setup.sh` | ## Adding a skill diff --git a/knowledge/README.md b/knowledge/README.md index 9bd816a..dde10a7 100644 --- a/knowledge/README.md +++ b/knowledge/README.md @@ -16,6 +16,7 @@ of the workspace). | `runbooks/` | Operational guides: deploys, incident response, environment setup | | `product/` | Product context: personas, feature specs, terminology, UX audits | | `releases/` | Release notes and store submission notes | +| `handoffs/` | Working state for an interrupted task — see [Handoffs](#handoffs) | ## Index @@ -29,9 +30,18 @@ the status of any doc: node scripts/build-knowledge-index.mjs ``` -`/write-doc` runs this automatically as its last step. Agents doing broad -"what do we know about X" retrieval should check `index.md` before searching, -per the retrieval policy in `AGENTS.md`. +`/write-doc` and `/capture-learning` run this automatically as their last +step. Agents doing broad "what do we know about X" retrieval should check +`index.md` before searching, per the retrieval policy in `AGENTS.md`. + +## Handoffs + +`handoffs/` holds working state for a task interrupted mid-flight — enough +that a different agent (or the same one, in a fresh session) can pick it up +without rediscovering everything. It is **not permanent knowledge**: once the +task finishes, delete the handoff or set its `status: archived`. A handoff +that's still `status: accepted` signals unfinished work — `knowledge/index.md` +surfaces these so they don't get silently forgotten. ## Conventions @@ -56,7 +66,7 @@ whole doc: --- id: <kebab-slug> # decisions/ use adr-NNNN; others use the filename stem title: <Title> -type: architecture | design | decision | runbook | product | release +type: architecture | design | decision | runbook | product | release | handoff status: draft | proposed | accepted | deprecated | superseded | archived authority: canonical | supporting | generated | historical systems: [<system-name>, ...] # names from AGENTS.md's Systems table; [] if workspace-wide @@ -68,9 +78,16 @@ last_reviewed: YYYY-MM-DD tags: [<tag>, ...] # optional related: [<doc-id>, ...] # optional superseded_by: <doc-id> # optional — only when status: superseded +review_interval: 180d # optional — how often this doc should be re-checked --- ``` +`review_interval` (optional, e.g. `90d`, `180d`, `365d`) drives the freshness +warning in `scripts/detect-doc-drift.mjs`: if `last_reviewed` plus the +interval is in the past, the doc surfaces as stale. Add it to anything whose +accuracy decays — architecture, runbooks, product behavior — skip it on docs +that don't go stale the same way (most ADRs, once accepted, don't need one). + ### Status — is it current? | Status | Meaning | diff --git a/knowledge/handoffs/.gitkeep b/knowledge/handoffs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/knowledge/index.md b/knowledge/index.md index 4967d29..b7f01bc 100644 --- a/knowledge/index.md +++ b/knowledge/index.md @@ -23,6 +23,10 @@ _None yet._ _None yet._ +## Active Handoffs (unfinished work) + +_None yet._ + ## Recently Reviewed - [System Overview](architecture/overview.md) — draft diff --git a/scripts/build-knowledge-index.mjs b/scripts/build-knowledge-index.mjs index 2c91662..fdb0ee4 100644 --- a/scripts/build-knowledge-index.mjs +++ b/scripts/build-knowledge-index.mjs @@ -84,7 +84,8 @@ const designs = withFm.filter((d) => d.type === "design" && ["draft", "proposed" const decisions = withFm.filter((d) => d.type === "decision" && d.status === "accepted"); const runbooks = withFm.filter((d) => d.type === "runbook" && !["deprecated", "superseded", "archived"].includes(d.status)); const product = withFm.filter((d) => d.type === "product" && !["deprecated", "superseded", "archived"].includes(d.status)); -const deprecated = withFm.filter((d) => ["deprecated", "superseded", "archived"].includes(d.status)); +const handoffs = withFm.filter((d) => d.type === "handoff" && d.status !== "archived"); +const deprecated = withFm.filter((d) => d.type !== "handoff" && ["deprecated", "superseded", "archived"].includes(d.status)); const recent = [...withFm] .filter((d) => d.last_reviewed || d.created) @@ -101,6 +102,7 @@ ${section("Active Designs", designs, link)} ${section("Accepted Decisions", decisions, link)} ${section("Operational Runbooks", runbooks, link)} ${section("Product Knowledge", product, link)} +${section("Active Handoffs (unfinished work)", handoffs, link)} ${section("Recently Reviewed", recent, link)} ${section("Deprecated / Superseded / Archived", deprecated, link)} ${missing.length > 0 ? `## Missing frontmatter\n\nThese docs have no frontmatter and are excluded from the sections above — add it (see \`knowledge/README.md\`):\n\n${missing.map((d) => `- ${d.path}`).join("\n")}\n` : ""}`; diff --git a/scripts/detect-doc-drift.mjs b/scripts/detect-doc-drift.mjs new file mode 100644 index 0000000..50ff238 --- /dev/null +++ b/scripts/detect-doc-drift.mjs @@ -0,0 +1,147 @@ +#!/usr/bin/env node +// Surfaces likely-stale knowledge — this is a WARNING tool, not a gate: it +// always exits 0. Wire it into CI as a non-blocking step, or run it by hand +// before a knowledge review. Checks: +// - systems.yaml entries with no matching devrig.toml repo (renamed/removed) +// - devrig.toml repos with no systems.yaml entry (undocumented system) +// - dangling `related:`/`superseded_by` frontmatter ids (doc renamed/removed) +// - docs past their `review_interval` since `last_reviewed` +// +// What this can't check from a template repo alone (needs real cloned repos +// with real code): stale command definitions vs. actual package.json +// scripts, and "removed API still documented" — flagged below as manual +// follow-ups, not attempted. + +import { readdirSync, statSync, readFileSync, existsSync } from "node:fs"; +import { join, relative, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { parseYamlLite } from "./lib/yaml-lite.mjs"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const KNOWLEDGE_DIR = join(ROOT, "knowledge"); +const SKIP_FILES = new Set(["README.md", "index.md", "0000-template.md"]); + +function walk(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) out.push(...walk(full)); + else if (entry.endsWith(".md") && !SKIP_FILES.has(entry)) out.push(full); + } + return out; +} + +function parseFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return null; + const fm = {}; + for (const line of match[1].split("\n")) { + const kv = line.match(/^([A-Za-z_]+):\s*(.*)$/); + if (!kv) continue; + const [, key, rawValue] = kv; + let value = rawValue.trim(); + if (value.startsWith("[") && value.endsWith("]")) { + value = value + .slice(1, -1) + .split(",") + .map((s) => s.trim().replace(/^["']|["']$/g, "")) + .filter(Boolean); + } else { + value = value.replace(/^["']|["']$/g, ""); + } + fm[key] = value; + } + return fm; +} + +function parseToml(text) { + // Just enough to read [project].repos = [...] from devrig.toml. + const match = text.match(/repos\s*=\s*\[([^\]]*)\]/); + if (!match) return []; + return match[1] + .split(",") + .map((s) => s.trim().replace(/^["']|["']$/g, "")) + .filter(Boolean); +} + +function addDays(dateStr, amount, unit) { + const d = new Date(dateStr); + if (isNaN(d)) return null; + const days = unit === "y" ? amount * 365 : unit === "m" ? amount * 30 : amount; + d.setDate(d.getDate() + days); + return d; +} + +const warnings = []; + +// --- systems.yaml vs devrig.toml --- +const tomlPath = join(ROOT, "devrig.toml"); +const systemsPath = join(ROOT, ".ai", "systems.yaml"); +if (existsSync(tomlPath) && existsSync(systemsPath)) { + const repos = parseToml(readFileSync(tomlPath, "utf8")); + const systems = parseYamlLite(readFileSync(systemsPath, "utf8")).systems ?? {}; + const systemRepos = new Set(Object.values(systems).map((s) => s.repo)); + + for (const repo of repos) { + if (!systemRepos.has(repo)) { + warnings.push(`devrig.toml repo "${repo}" has no matching entry in .ai/systems.yaml`); + } + } + for (const [name, sys] of Object.entries(systems)) { + if (sys.repo && repos.length > 0 && !repos.includes(sys.repo)) { + warnings.push(`.ai/systems.yaml system "${name}" points at repo "${sys.repo}", which isn't in devrig.toml's repos list (renamed or removed?)`); + } + } +} + +// --- dangling related/superseded_by ids --- +const files = walk(KNOWLEDGE_DIR); +const docsById = new Map(); +const docs = []; +for (const file of files) { + const fm = parseFrontmatter(readFileSync(file, "utf8")); + if (!fm) continue; + docs.push({ file, fm }); + if (fm.id) docsById.set(fm.id, file); +} + +for (const { file, fm } of docs) { + const relPath = relative(ROOT, file); + const relatedIds = Array.isArray(fm.related) ? fm.related : fm.related ? [fm.related] : []; + for (const id of relatedIds) { + if (id && !docsById.has(id)) { + warnings.push(`${relPath}: related id "${id}" doesn't match any doc's frontmatter id`); + } + } + if (fm.superseded_by && fm.superseded_by !== "null" && !docsById.has(fm.superseded_by)) { + warnings.push(`${relPath}: superseded_by "${fm.superseded_by}" doesn't match any doc's frontmatter id`); + } +} + +// --- freshness: last_reviewed + review_interval vs today --- +const today = new Date(); +for (const { file, fm } of docs) { + if (!fm.review_interval || !fm.last_reviewed) continue; + const match = fm.review_interval.match(/^(\d+)([dmy])$/); + if (!match) continue; + const dueDate = addDays(fm.last_reviewed, Number(match[1]), match[2]); + if (dueDate && dueDate < today) { + const daysOverdue = Math.round((today - dueDate) / (1000 * 60 * 60 * 24)); + warnings.push(`${relative(ROOT, file)}: stale — last reviewed ${fm.last_reviewed}, review_interval ${fm.review_interval}, ${daysOverdue} day(s) overdue`); + } +} + +// --- what this script can't check without real repos --- +const manualFollowUps = [ + "Command drift: whether .ai/commands.yaml's commands still match each repo's actual package.json scripts (needs cloned repos).", + "Removed-API-still-documented: whether documented endpoints/events still exist in code (needs semantic code reading — see /check-knowledge-consistency).", +]; + +console.log(`Doc drift check — ${warnings.length} warning(s):\n`); +for (const w of warnings) console.log(` ⚠ ${w}`); +if (warnings.length === 0) console.log(" (none)"); + +console.log(`\nNot checked here (needs cloned repos / semantic reading — use /check-knowledge-consistency):`); +for (const f of manualFollowUps) console.log(` - ${f}`); + +process.exit(0); // warning tool — never fails the build diff --git a/scripts/validate-knowledge.mjs b/scripts/validate-knowledge.mjs index 460ae9b..564fe2f 100644 --- a/scripts/validate-knowledge.mjs +++ b/scripts/validate-knowledge.mjs @@ -15,7 +15,7 @@ const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); const KNOWLEDGE_DIR = join(ROOT, "knowledge"); const SKIP_FILES = new Set(["README.md", "index.md", "0000-template.md"]); -const VALID_TYPES = ["architecture", "design", "decision", "runbook", "product", "release"]; +const VALID_TYPES = ["architecture", "design", "decision", "runbook", "product", "release", "handoff"]; const VALID_STATUS = ["draft", "proposed", "accepted", "deprecated", "superseded", "archived"]; const VALID_AUTHORITY = ["canonical", "supporting", "generated", "historical"]; const VALID_AUTHORSHIP = ["human", "ai-assisted", "generated"]; From acfe7e31c4ca79ab6ebfd3885913b579ea487d16 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 03:43:43 +0900 Subject: [PATCH 6/9] feat(observability): generated architecture views, run trails, evals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roadmap Phase 4 (items 43-48 in the numbered roadmap; graphify/knowledge graphs were already in place from before this project): - scripts/generate-architecture-views.mjs builds knowledge/generated/ system-map.md (Mermaid dependency graph) and ownership-map.md from .ai/systems.yaml / ownership.yaml, authority: generated. Wired into /capture-learning's regenerate step. - .ai/runs/<TICKET-ID>/ is a per-task observability trail written incrementally by /start-task (context.json), /plan-task (plan.md), /verify-change (verification.md), /raise-pr (changed-files.txt), and /capture-learning (summary.md) — documented in the new .ai/README.md. - evals/ (retrieval.yaml, architecture.yaml, workflows.yaml, semble-vs-graphify.md) — question sets and a comparison methodology, scored on retrieval accuracy, source correctness, token consumption, answer completeness, and hallucination rate. - AGENTS.md gets a Context efficiency section, tying the retrieval policy to .ai/context/ reuse and the rtk toggle. - Fixed a real bug in scripts/lib/yaml-lite.mjs: block-sequence items that are multi-key mappings (e.g. "- id: x\n category: y") were silently truncated to their first key — only exercised once evals/*.yaml used that shape, since .ai/*.yaml's existing sequences are all plain scalars. --- .agents/skills/capture-learning/SKILL.md | 14 ++- .agents/skills/plan-task/SKILL.md | 4 + .agents/skills/raise-pr/SKILL.md | 6 ++ .agents/skills/start-task/SKILL.md | 5 + .agents/skills/verify-change/SKILL.md | 5 + .ai/README.md | 39 ++++++++ .ai/runs/.gitkeep | 0 AGENTS.md | 17 ++++ README.md | 5 +- evals/README.md | 48 ++++++++++ evals/architecture.yaml | 34 +++++++ evals/retrieval.yaml | 27 ++++++ evals/semble-vs-graphify.md | 73 +++++++++++++++ evals/workflows.yaml | 27 ++++++ knowledge/README.md | 5 + knowledge/generated/ownership-map.md | 23 +++++ knowledge/generated/system-map.md | 34 +++++++ knowledge/index.md | 4 + scripts/generate-architecture-views.mjs | 113 +++++++++++++++++++++++ scripts/lib/yaml-lite.mjs | 26 +++++- 20 files changed, 503 insertions(+), 6 deletions(-) create mode 100644 .ai/README.md create mode 100644 .ai/runs/.gitkeep create mode 100644 evals/README.md create mode 100644 evals/architecture.yaml create mode 100644 evals/retrieval.yaml create mode 100644 evals/semble-vs-graphify.md create mode 100644 evals/workflows.yaml create mode 100644 knowledge/generated/ownership-map.md create mode 100644 knowledge/generated/system-map.md create mode 100644 scripts/generate-architecture-views.mjs diff --git a/.agents/skills/capture-learning/SKILL.md b/.agents/skills/capture-learning/SKILL.md index 92a7b3e..c0a9af0 100644 --- a/.agents/skills/capture-learning/SKILL.md +++ b/.agents/skills/capture-learning/SKILL.md @@ -59,10 +59,18 @@ For each confirmed item, follow `/write-doc`'s normal flow (template, frontmatte - If `knowledge/handoffs/<TICKET-ID>.md` exists, delete it (the task is done, not interrupted) or set `status: archived` if the team prefers keeping history. - If `.ai/context/<TICKET-ID>.json` exists, delete it — it's no longer useful once the task is merged. -## Step 6 — Regenerate and land +## Step 6 — Close the observability trail -1. `node scripts/build-knowledge-index.mjs`. -2. Land all changes from this run on **one** branch (`<ticket-id>-docs-capture-learning`) and suggest `/raise-pr` — do not commit to the default branch. +Write `.ai/runs/<TICKET-ID>/summary.md` — the final entry in that ticket's +observability trail (see `.ai/README.md`): what was captured as permanent +knowledge (with paths), what was skipped and why, and what was cleaned up. +This closes the run; nothing else writes to `.ai/runs/<TICKET-ID>/` after this. + +## Step 7 — Regenerate and land + +1. If `.ai/systems.yaml` or `.ai/ownership.yaml` changed: `node scripts/generate-architecture-views.mjs`. +2. `node scripts/build-knowledge-index.mjs`. +3. Land all changes from this run on **one** branch (`<ticket-id>-docs-capture-learning`) and suggest `/raise-pr` — do not commit to the default branch. ## Output diff --git a/.agents/skills/plan-task/SKILL.md b/.agents/skills/plan-task/SKILL.md index b4b7abd..ef56622 100644 --- a/.agents/skills/plan-task/SKILL.md +++ b/.agents/skills/plan-task/SKILL.md @@ -109,6 +109,10 @@ Present the plan and wait for the user to approve, edit, or redirect before implementing. Treat this as a real gate, not a formality — a plan the user hasn't seen is not an approved plan. +Once approved, write the final plan (as approved, including any edits the +user made) to `.ai/runs/<ISSUE-ID>/plan.md` — the next entry in that ticket's +observability trail (see `.ai/README.md`). + ## Step 5 — Hand off Once approved, implement against the plan directly, or note that diff --git a/.agents/skills/raise-pr/SKILL.md b/.agents/skills/raise-pr/SKILL.md index 2ff47e7..d9b7657 100644 --- a/.agents/skills/raise-pr/SKILL.md +++ b/.agents/skills/raise-pr/SKILL.md @@ -319,3 +319,9 @@ Print the full PR URL for every affected repo: > - repo-b: https://github.com/<owner>/repo-b/pull/<number>" If the CLI returned a URL, use that directly. If only a PR number was returned, construct the URL from the known owner/repo/number. + +--- + +## Step 11 — Record changed files + +For each affected repo, append `git diff --stat $(git merge-base HEAD origin/<BASE>)..HEAD` to `.ai/runs/<ISSUE-ID>/changed-files.txt` (one section per repo, headed by the repo name) — the next entry in that ticket's observability trail (see `.ai/README.md`). diff --git a/.agents/skills/start-task/SKILL.md b/.agents/skills/start-task/SKILL.md index adacc34..9dfe30e 100644 --- a/.agents/skills/start-task/SKILL.md +++ b/.agents/skills/start-task/SKILL.md @@ -182,3 +182,8 @@ This is working state for the task's branch, not permanent knowledge — it's fine to commit alongside the task's other changes, and there's no need to clean it up specially (it becomes stale/irrelevant once the branch merges, same as the branch itself). + +Also write the identical JSON to `.ai/runs/<ISSUE-ID>/context.json` — this +starts that ticket's observability trail (see `.ai/README.md`), which +`/plan-task`, `/verify-change`, `/raise-pr`, and `/capture-learning` each add +to as the task progresses. diff --git a/.agents/skills/verify-change/SKILL.md b/.agents/skills/verify-change/SKILL.md index cee2927..6c33f9c 100644 --- a/.agents/skills/verify-change/SKILL.md +++ b/.agents/skills/verify-change/SKILL.md @@ -92,6 +92,11 @@ Any line that isn't PASS must show the actual failure output (or a short excerpt of it), not just "FAIL" — the next step is fixing it, not re-asserting success. +Once every affected repo passes, append the full evidence (all repos) to +`.ai/runs/<ISSUE-ID>/verification.md` — the next entry in that ticket's +observability trail (see `.ai/README.md`). Don't write a failing run to it; +only the passing result that actually gates `/raise-pr`. + ## Step 6 — Stop on failure If anything fails, fix it and re-run this skill from Step 2 for that repo — diff --git a/.ai/README.md b/.ai/README.md new file mode 100644 index 0000000..d1c4560 --- /dev/null +++ b/.ai/README.md @@ -0,0 +1,39 @@ +# .ai/ — machine-readable workspace metadata + +Structured mirror of `AGENTS.md`/`POLICY.md`, for scripts/CI to parse +reliably (Markdown tables aren't machine-parseable). The Markdown files stay +the human-readable source of truth — keep both in sync when you edit either. + +| File / folder | Mirrors | Validated by | +|---|---|---| +| `systems.yaml` | `AGENTS.md`'s Systems table | `scripts/validate-ai-config.mjs` | +| `commands.yaml` | `AGENTS.md`'s Commands table | `scripts/validate-ai-config.mjs` | +| `ownership.yaml` | (no Markdown equivalent yet) | parsed, not schema-checked | +| `policies.yaml` | `POLICY.md`'s forbidden/approval-required/protected-path/data-handling/role sections | `scripts/validate-ai-config.mjs` | +| `risk-levels.yaml` | `POLICY.md`'s Risk levels table | `scripts/validate-ai-config.mjs` | +| `schemas/` | JSON Schemas for the four files above | used by `validate-ai-config.mjs` | +| `context/<TICKET-ID>.json` | Compact, reusable task context — written by `/start-task`, read by `/plan-task` | not validated (ephemeral working state) | +| `runs/<TICKET-ID>/` | Observability trail for one task's full lifecycle — see below | not validated (audit trail, not config) | + +## `runs/<TICKET-ID>/` + +Written incrementally across a task's lifecycle so you can see what an agent +actually did without digging through chat history: + +| File | Written by | Contents | +|---|---|---| +| `context.json` | `/start-task` | Same shape as `.ai/context/<TICKET-ID>.json` | +| `plan.md` | `/plan-task` | The plan as approved (Step 4 of that skill) | +| `verification.md` | `/verify-change` | The verification evidence block(s) | +| `changed-files.txt` | `/raise-pr` | `git diff --stat` per affected repo | +| `summary.md` | `/capture-learning` | What was captured as permanent knowledge, and what was cleaned up | + +None of this is sensitive-prompt or secret data — just which steps ran, what +was decided, and what changed. Don't put secrets, tokens, or raw user data in +any of these files (see `POLICY.md`'s data-handling rules). + +This is a record, not a gate — nothing currently reads it back automatically +to enforce sequencing. Its value is *"which searches were useful, how often +did tests fail, where did agents get stuck"* — the kind of question you can +only answer if the trail exists. Directories accumulate one per ticket; clean +up old ones periodically the same way you'd prune old branches. diff --git a/.ai/runs/.gitkeep b/.ai/runs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/AGENTS.md b/AGENTS.md index c8f131e..3e3508c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,6 +77,23 @@ Prefer `authority: canonical` docs over `supporting`, `generated`, or `historical` ones when they conflict (see `knowledge/README.md`). Never treat a `deprecated`, `superseded`, or `archived` doc as current guidance. +## Context efficiency + +- Search before recursively reading — grep-and-read a whole repo is a last + resort, not a first move. +- Read only the files retrieval actually surfaced as relevant. +- Prefer narrow ranges on very large files instead of reading the whole thing. +- Don't reread a file you haven't changed since you last read it this session. +- Summarize large logs/command output rather than pasting it verbatim into + later reasoning. +- Reuse previously gathered task context — check `.ai/context/<TICKET-ID>.json` + (written by `/start-task`) before re-running retrieval from scratch. +- Avoid loading generated/vendor files (`graphify-out/`, build output, + `node_modules/`, lockfiles) unless specifically debugging them. + +If the `rtk` toggle in `devrig.toml` is on, `rtk gain` shows measured token +savings from this discipline — see the root `README.md`'s rtk section for setup/usage. + ## Knowledge graph (graphify) Enabled by the `graphify` toggle in `devrig.toml`. There is no single diff --git a/README.md b/README.md index aaae2c1..bc114e0 100644 --- a/README.md +++ b/README.md @@ -204,8 +204,9 @@ directly and re-run `./setup.sh`. | `.opencode/` | opencode agents and plugin config | | `.mcp.json` / `opencode.json` | MCP servers (issue tracker, semble) | | `git-hooks/` | Shared hooks for every repo (`core.hooksPath`): protected-branch pre-commit / pre-push, plus the graphify graph rebuilds | -| `knowledge/` | Markdown knowledge base (architecture, decisions, design, runbooks, product, releases) — see `knowledge/index.md` | -| `scripts/` | Workspace maintenance scripts — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs` | +| `knowledge/` | Markdown knowledge base (architecture, decisions, design, runbooks, product, releases, handoffs, generated) — see `knowledge/index.md` | +| `evals/` | Questions with known-good answers, for measuring retrieval accuracy/hallucination rate over time — see `evals/README.md` | +| `scripts/` | Workspace maintenance scripts — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (untracked) | Your project repos, cloned by `setup.sh` | ## Adding a skill diff --git a/evals/README.md b/evals/README.md new file mode 100644 index 0000000..7ec4131 --- /dev/null +++ b/evals/README.md @@ -0,0 +1,48 @@ +# Evals + +Questions with known-good answers, used to measure whether this workspace is +actually getting easier for agents to work in over time — not just whether it +*feels* more organized. + +## Files + +| File | Category | +|---|---| +| `retrieval.yaml` | Direct retrieval, dependency questions — "where is X", "what depends on Y" | +| `architecture.yaml` | Architecture understanding, historical decisions, impact analysis — "why was X chosen", "what breaks if I change Y" | +| `workflows.yaml` | Operational questions — "how do I run tests", "what must I do before Z" | +| `semble-vs-graphify.md` | Methodology for comparing retrieval tools on the same question set | + +Each entry needs `expected_sources` filled in with real paths once your +`knowledge/`, `AGENTS.md`, and repos have real content — the versions +committed here are templates with the illustrative example questions from +the workspace roadmap, not yet wired to a specific project. + +## Running an eval by hand + +There's no automated eval harness wired up yet (that's real future work — see +[Automating this](#automating-this)). Until then: + +1. Start a fresh agent session (no prior context from working on the answer). +2. Ask it the `question` verbatim. +3. Score the answer against these dimensions: + +| Dimension | What it measures | How to score | +|---|---|---| +| Retrieval accuracy | Did it find the right source(s) at all? | Compare cited sources to `expected_sources` | +| Source correctness | Are the cited sources actually authoritative (not a stale/superseded doc)? | Check `authority`/`status` of each cited doc | +| Token consumption | How much context did it burn getting there? | Rough count from the session, or `rtk gain` if using rtk | +| Answer completeness | Did it answer the whole question, or just part? | Judgment call against the question's intent | +| Hallucination rate | Did it state anything as fact that isn't traceable to a source it read? | Check every factual claim against `expected_sources` or the actual repo | + +4. Record the result (pass/partial/fail per dimension) somewhere you can + compare over time — a spreadsheet is fine to start. + +## Automating this + +Once this matters enough to run regularly: script the "ask fresh agent, grade +against `expected_sources`" loop (the `Workflow` tool's `agent()` + +`schema` option is a natural fit — one eval item per agent call, graded by a +judge agent comparing its cited sources against `expected_sources`). Not +built yet; this file's job for now is to make sure the *questions* exist so +scripting the runner later is straightforward. diff --git a/evals/architecture.yaml b/evals/architecture.yaml new file mode 100644 index 0000000..cf99668 --- /dev/null +++ b/evals/architecture.yaml @@ -0,0 +1,34 @@ +# Architecture understanding, historical decisions, and impact analysis. +# Fill in expected_sources with real paths once your knowledge base has +# real content. See evals/README.md for how to run and score these. + +evals: + - id: architecture-001 + category: architecture-understanding + question: "Why was this architecture selected?" + expected_sources: + - knowledge/architecture/overview.md + - knowledge/decisions/ + notes: "TODO: needs at least one accepted ADR explaining a real architectural choice." + + - id: architecture-002 + category: historical-decisions + question: "Which ADR controls authentication, and is it still followed?" + expected_sources: + - knowledge/decisions/ + notes: "Good answer checks the ADR's status (accepted/superseded) and spot-checks the code, per /check-knowledge-consistency." + + - id: architecture-003 + category: impact-analysis + question: "What happens if I change the location payload?" + expected_sources: + - knowledge/architecture/ + - knowledge/design/ + notes: "TODO: replace 'location payload' with a real shared data model in your system. Good answer names every consumer, not just the producer." + + - id: architecture-004 + category: impact-analysis + question: "What must I do before modifying the database schema?" + expected_sources: + - POLICY.md + notes: "Good answer cites POLICY.md's ADR requirement and Definition of Done, not just 'write a migration'." diff --git a/evals/retrieval.yaml b/evals/retrieval.yaml new file mode 100644 index 0000000..132897a --- /dev/null +++ b/evals/retrieval.yaml @@ -0,0 +1,27 @@ +# Direct retrieval and dependency questions. Fill in expected_sources with +# real paths once your knowledge base / .ai config have real content. +# See evals/README.md for how to run and score these. + +evals: + - id: retrieval-001 + category: direct-retrieval + question: "Which repo owns authentication?" + expected_sources: + - .ai/ownership.yaml + - AGENTS.md + notes: "TODO: replace with your actual auth-owning system once ownership.yaml is filled in." + + - id: retrieval-002 + category: dependency-questions + question: "Which systems depend on the API?" + expected_sources: + - .ai/systems.yaml + - knowledge/generated/system-map.md + notes: "Answer should list every system whose depends_on includes the api system." + + - id: retrieval-003 + category: direct-retrieval + question: "Which ADR controls authentication?" + expected_sources: + - knowledge/decisions/ + notes: "TODO: fill in once an auth ADR exists. Until then, the correct answer is 'none found'." diff --git a/evals/semble-vs-graphify.md b/evals/semble-vs-graphify.md new file mode 100644 index 0000000..32116b2 --- /dev/null +++ b/evals/semble-vs-graphify.md @@ -0,0 +1,73 @@ +# Semble vs. Graphify: evaluation methodology + +> This lives in `evals/`, not `knowledge/` — it's a methodology doc for +> running the comparison, not part of the frontmatter-tracked knowledge base. +> If you run this and reach a verdict, that verdict belongs in +> `knowledge/decisions/` as an ADR (see the bottom of this file), with real +> frontmatter. + +> This is a methodology, not a verdict — run it against your own repos before +> deciding whether to run Semble alone, Graphify alone, or both. Don't decide +> based on marketing; decide based on your own eval results. + +## Why compare at all + +`AGENTS.md` currently tells agents to reach for both: Semble for "where is +the information" and Graphify for relationship/impact questions. That's a +reasonable default, but it's untested against real usage. This eval exists to +find out whether that default holds, or whether one tool covers most of what +you need and the other is dead weight (extra retrieval policy an agent has to +hold in its head, for marginal benefit). + +## Method + +1. Assemble **~30 real questions** — pull from `evals/retrieval.yaml`, + `architecture.yaml`, `workflows.yaml`, plus real questions you or your team + have actually asked while working in this codebase. Cover all six + categories: + + | Category | Example | + |---|---| + | Direct retrieval | "Where is X implemented?" | + | Architecture understanding | "Why was X chosen?" | + | Dependency questions | "What depends on X?" | + | Historical decision questions | "Which ADR controls X?" | + | Impact analysis | "What breaks if I change X?" | + | Operational questions | "How do I run X?" | + +2. For each question, run it three ways, each in a **fresh session** (no + context carried over between runs, and no run sees another run's answer): + - Semble only (disable/ignore Graphify for this run) + - Graphify only (disable/ignore Semble for this run) + - Both available (today's default) + +3. Score each run against `evals/README.md`'s five dimensions: retrieval + accuracy, source correctness, token consumption, answer completeness, + hallucination rate. + +4. Tabulate per category, not just overall — a tool can win on "dependency + questions" and lose on "direct retrieval". The aggregate number hides that. + +## Recording results + +```markdown +## Results — <date> + +| Category | Semble only | Graphify only | Both | +|---|---|---|---| +| Direct retrieval | | | | +| Architecture understanding | | | | +| Dependency questions | | | | +| Historical decisions | | | | +| Impact analysis | | | | +| Operational | | | | + +## Verdict + +<Keep both / Semble only / Graphify only / Needs another round>, and why. +``` + +Once you have real results, promote the verdict to an ADR +(`knowledge/decisions/`) — this is exactly the kind of architectural choice +`POLICY.md`'s ADR requirement is for, and it should be revisited if the +codebase or the tools change enough to invalidate the original numbers. diff --git a/evals/workflows.yaml b/evals/workflows.yaml new file mode 100644 index 0000000..f2254c8 --- /dev/null +++ b/evals/workflows.yaml @@ -0,0 +1,27 @@ +# Operational questions — the kind a new contributor asks in their first +# week. Fill in expected_sources with real paths once your knowledge base +# and .ai config have real content. See evals/README.md for how to run and +# score these. + +evals: + - id: workflows-001 + category: operational + question: "How do I run mobile tests?" + expected_sources: + - AGENTS.md + - .ai/commands.yaml + notes: "TODO: replace 'mobile' with a real system name from your Systems table. Good answer gives the exact command, not 'check the README'." + + - id: workflows-002 + category: operational + question: "Where is the production deployment process documented?" + expected_sources: + - knowledge/runbooks/ + notes: "TODO: needs at least one deploy runbook. Until then, the correct answer is 'not yet documented' — flagging that gap is itself a correct answer." + + - id: workflows-003 + category: operational + question: "What must I do before modifying the database schema?" + expected_sources: + - POLICY.md + notes: "Duplicate of architecture-004 by design — a good answer should be consistent regardless of how the question is framed." diff --git a/knowledge/README.md b/knowledge/README.md index dde10a7..ab97a63 100644 --- a/knowledge/README.md +++ b/knowledge/README.md @@ -17,6 +17,7 @@ of the workspace). | `product/` | Product context: personas, feature specs, terminology, UX audits | | `releases/` | Release notes and store submission notes | | `handoffs/` | Working state for an interrupted task — see [Handoffs](#handoffs) | +| `generated/` | Views generated from `.ai/*.yaml` (system map, ownership map) — `authority: generated`, never hand-edited | ## Index @@ -34,6 +35,10 @@ node scripts/build-knowledge-index.mjs step. Agents doing broad "what do we know about X" retrieval should check `index.md` before searching, per the retrieval policy in `AGENTS.md`. +Similarly, `generated/`'s contents come from `scripts/generate-architecture-views.mjs` +— run it after editing `.ai/systems.yaml` or `.ai/ownership.yaml`, then +regenerate `index.md` since the generated docs are new inputs to it. + ## Handoffs `handoffs/` holds working state for a task interrupted mid-flight — enough diff --git a/knowledge/generated/ownership-map.md b/knowledge/generated/ownership-map.md new file mode 100644 index 0000000..3842d99 --- /dev/null +++ b/knowledge/generated/ownership-map.md @@ -0,0 +1,23 @@ +--- +id: ownership-map +title: Ownership Map (generated) +type: architecture +status: accepted +authority: generated +systems: [] +owners: [] +authorship: generated +human_reviewed: false +created: 2026-08-16 +last_reviewed: 2026-08-16 +tags: [generated] +--- + +# Ownership Map + +> Generated from `.ai/ownership.yaml` by `scripts/generate-architecture-views.mjs`. +> Do not edit by hand — edit the source file and regenerate. + +| Area | Systems | Owners | +|---|---|---| +| authentication | api, web | backend-team | diff --git a/knowledge/generated/system-map.md b/knowledge/generated/system-map.md new file mode 100644 index 0000000..67f3734 --- /dev/null +++ b/knowledge/generated/system-map.md @@ -0,0 +1,34 @@ +--- +id: system-map +title: System Map (generated) +type: architecture +status: accepted +authority: generated +systems: [] +owners: [] +authorship: generated +human_reviewed: false +created: 2026-08-16 +last_reviewed: 2026-08-16 +tags: [generated] +--- + +# System Map + +> Generated from `.ai/systems.yaml` by `scripts/generate-architecture-views.mjs`. +> Do not edit by hand — edit the source file and regenerate. `authority: generated`: +> treat this as a lead to verify, not a citation (see `knowledge/README.md`). + +## Dependency graph + +```mermaid +flowchart LR + api --> web +``` + +## Systems + +| System | Repo | Purpose | Stack | Depends on | +|---|---|---|---|---| +| api | example-api | Backend API | nestjs, postgresql | — | +| web | example-web | Web frontend | nextjs, tailwind | api | diff --git a/knowledge/index.md b/knowledge/index.md index b7f01bc..bc9c0b3 100644 --- a/knowledge/index.md +++ b/knowledge/index.md @@ -6,6 +6,8 @@ ## Architecture - [System Overview](architecture/overview.md) — draft +- [Ownership Map (generated)](generated/ownership-map.md) — accepted +- [System Map (generated)](generated/system-map.md) — accepted ## Active Designs @@ -29,6 +31,8 @@ _None yet._ ## Recently Reviewed +- [Ownership Map (generated)](generated/ownership-map.md) — accepted +- [System Map (generated)](generated/system-map.md) — accepted - [System Overview](architecture/overview.md) — draft ## Deprecated / Superseded / Archived diff --git a/scripts/generate-architecture-views.mjs b/scripts/generate-architecture-views.mjs new file mode 100644 index 0000000..ea637a9 --- /dev/null +++ b/scripts/generate-architecture-views.mjs @@ -0,0 +1,113 @@ +#!/usr/bin/env node +// Generates architecture views from .ai/systems.yaml and .ai/ownership.yaml +// instead of hand-maintaining diagrams that drift from reality. Writes: +// knowledge/generated/system-map.md — Mermaid dependency graph + repo table +// knowledge/generated/ownership-map.md — area -> systems -> owners table +// Run: node scripts/generate-architecture-views.mjs (after editing .ai/systems.yaml +// or .ai/ownership.yaml). Output is authority: generated — a lead to verify +// against AGENTS.md/POLICY.md, never a citation on its own (see knowledge/README.md). + +import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { parseYamlLite } from "./lib/yaml-lite.mjs"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const GENERATED_DIR = join(ROOT, "knowledge", "generated"); +mkdirSync(GENERATED_DIR, { recursive: true }); + +function existingCreatedDate(outputPath) { + if (!existsSync(outputPath)) return null; + const match = readFileSync(outputPath, "utf8").match(/^created:\s*(.+)$/m); + return match ? match[1].trim() : null; +} + +function frontmatter(id, title, outputPath) { + const today = new Date().toISOString().slice(0, 10); + const created = existingCreatedDate(outputPath) ?? today; + return `--- +id: ${id} +title: ${title} +type: architecture +status: accepted +authority: generated +systems: [] +owners: [] +authorship: generated +human_reviewed: false +created: ${created} +last_reviewed: ${today} +tags: [generated] +--- +`; +} + +const systemsPath = join(ROOT, ".ai", "systems.yaml"); +if (existsSync(systemsPath)) { + const systems = parseYamlLite(readFileSync(systemsPath, "utf8")).systems ?? {}; + const names = Object.keys(systems); + + const mermaidEdges = names + .flatMap((name) => { + const deps = systems[name].depends_on ?? []; + return deps.map((dep) => ` ${dep} --> ${name}`); + }) + .join("\n"); + + const table = names + .map((name) => { + const s = systems[name]; + return `| ${name} | ${s.repo ?? ""} | ${s.purpose ?? ""} | ${(s.stack ?? []).join(", ")} | ${(s.depends_on ?? []).join(", ") || "—"} |`; + }) + .join("\n"); + + const systemMapPath = join(GENERATED_DIR, "system-map.md"); + const content = `${frontmatter("system-map", "System Map (generated)", systemMapPath)} +# System Map + +> Generated from \`.ai/systems.yaml\` by \`scripts/generate-architecture-views.mjs\`. +> Do not edit by hand — edit the source file and regenerate. \`authority: generated\`: +> treat this as a lead to verify, not a citation (see \`knowledge/README.md\`). + +## Dependency graph + +\`\`\`mermaid +flowchart LR +${mermaidEdges || " %% no dependencies declared in .ai/systems.yaml"} +\`\`\` + +## Systems + +| System | Repo | Purpose | Stack | Depends on | +|---|---|---|---|---| +${table} +`; + writeFileSync(systemMapPath, content); + console.log("Wrote knowledge/generated/system-map.md"); +} else { + console.log("SKIP system-map.md — .ai/systems.yaml not found"); +} + +const ownershipPath = join(ROOT, ".ai", "ownership.yaml"); +if (existsSync(ownershipPath)) { + const areas = parseYamlLite(readFileSync(ownershipPath, "utf8")).areas ?? {}; + const rows = Object.entries(areas) + .map(([area, def]) => `| ${area} | ${(def.systems ?? []).join(", ")} | ${(def.owners ?? []).join(", ")} |`) + .join("\n"); + + const ownershipMapPath = join(GENERATED_DIR, "ownership-map.md"); + const content = `${frontmatter("ownership-map", "Ownership Map (generated)", ownershipMapPath)} +# Ownership Map + +> Generated from \`.ai/ownership.yaml\` by \`scripts/generate-architecture-views.mjs\`. +> Do not edit by hand — edit the source file and regenerate. + +| Area | Systems | Owners | +|---|---|---| +${rows} +`; + writeFileSync(ownershipMapPath, content); + console.log("Wrote knowledge/generated/ownership-map.md"); +} else { + console.log("SKIP ownership-map.md — .ai/ownership.yaml not found"); +} diff --git a/scripts/lib/yaml-lite.mjs b/scripts/lib/yaml-lite.mjs index d820662..49e7dba 100644 --- a/scripts/lib/yaml-lite.mjs +++ b/scripts/lib/yaml-lite.mjs @@ -10,6 +10,30 @@ function stripComments(text) { .filter((line) => line.trim() !== "" && !line.trim().startsWith("#")); } +// "- key: value" list items (a block sequence of mappings, e.g. evals/*.yaml) +// need their sibling keys (on following lines, indented to align with "key:") +// recognized as part of the SAME mapping. Splitting "- key: value" into a +// bare "-" line plus a "key: value" line at the aligned indent lets the +// normal mapping-parse path pick up those siblings, instead of the sequence +// loop bailing out after the first line (whose content indent is deeper than +// the "-" it's attached to). +function expandDashKeyValueLines(lines) { + const out = []; + for (const line of lines) { + const m = line.match(/^(\s*)-\s+(.*)$/); + if (m) { + const [, indent, rest] = m; + if (splitKeyValue(rest)) { + out.push(`${indent}-`); + out.push(`${indent} ${rest}`); + continue; + } + } + out.push(line); + } + return out; +} + function indentOf(line) { return line.match(/^ */)[0].length; } @@ -40,7 +64,7 @@ function splitKeyValue(content) { } export function parseYamlLite(text) { - const rawLines = stripComments(text); + const rawLines = expandDashKeyValueLines(stripComments(text)); const lines = rawLines.map((line) => ({ indent: indentOf(line), content: line.trim() })); function parseBlock(pos, indent) { From 25a8eb81e137cfc94f3aad9b6c4e90df2c31f76a Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 12:57:06 +0900 Subject: [PATCH 7/9] fix(setup): update setup.sh's own hardcoded skill list and customize checklist Found via an end-to-end dry run (create-devrig -> setup.sh) of this PR's branch: setup.sh's final "Workflow skills available" printout and the generated project README's "Customize this workspace" checklist still only listed the original 5 skills / fields, missing /plan-task, /verify-change, /capture-learning, /check-knowledge-consistency, and the new .ai/*.yaml + POLICY.md customization steps. CLAUDE.md and this repo's own README.md were already updated in earlier commits; this script's own output wasn't. --- setup.sh | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/setup.sh b/setup.sh index 2947ad2..3779be1 100755 --- a/setup.sh +++ b/setup.sh @@ -431,8 +431,13 @@ out += [ "", "One-time steps after the first `setup.sh` run:", "", - "- [ ] Fill the **Systems** table above and in `AGENTS.md` (one row per repo:", - " what it is, stack), plus `AGENTS.md`'s **Testing** section.", + "- [ ] Fill the **Systems** and **Commands** tables in `AGENTS.md` (one row per", + " repo: what it is, stack, depends on; install/test/lint/typecheck/build),", + " plus its **Testing** section.", + "- [ ] Mirror the same values into `.ai/systems.yaml`, `.ai/commands.yaml`, and", + " `.ai/ownership.yaml` — `node scripts/validate-ai-config.mjs` checks the shape.", + "- [ ] Adjust `POLICY.md` / `.ai/policies.yaml` and `.ai/risk-levels.yaml` (Definition", + " of Done, ADR triggers, protected paths) to match your team's actual bar.", "- [ ] Add one reference file per repo in `.agents/skills/code-review/references/`", " and `.agents/skills/write-doc/references/` (copy `_example-repo.md`).", ] @@ -927,11 +932,15 @@ EOF cat <<EOF Workflow skills available inside Claude Code: - /start-task $TICKET_PREFIX-123 fetch ticket, assign it, sync $DEFAULT_BRANCH - /raise-pr branch, commit, push and open PRs for all affected repos - /code-review review a PR, branch, or local diff - /write-doc write design docs / ADRs / runbooks into knowledge/ - /create-ticket file well-formed epics, stories, tasks, bugs + /start-task $TICKET_PREFIX-123 fetch ticket, assign it, sync $DEFAULT_BRANCH, gather context + /plan-task turn gathered context into a written plan before implementing + /verify-change run tests/lint/typecheck/build, report evidence per POLICY.md + /raise-pr branch, commit, push and open PRs for all affected repos + /code-review review a PR, branch, or local diff + /write-doc write design docs / ADRs / runbooks / handoffs into knowledge/ + /capture-learning after a merge, decide what permanent knowledge to preserve + /check-knowledge-consistency compare knowledge/.ai/ against actual repo state + /create-ticket file well-formed epics, stories, tasks, bugs VS Code: Open $PROJECT_NAME.code-workspace to work across all repos in one window From 95067ca3ec2d613c58245c3fff6bc5563443a3f1 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 13:58:52 +0900 Subject: [PATCH 8/9] docs: sync translated READMEs with the roadmap changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the README.md diff from this branch (skills-table row, Customize this workspace checklist, Layout table) into all 8 translations — es, fr, hi, ja, ko, pt-BR, si, zh-CN — matching this repo's existing translation-sync convention (see bd4f1e1 for the same pattern applied to the graphify feature). --- docs/README.es.md | 16 ++++++++++++---- docs/README.fr.md | 16 ++++++++++++---- docs/README.hi.md | 16 ++++++++++++---- docs/README.ja.md | 16 ++++++++++++---- docs/README.ko.md | 16 ++++++++++++---- docs/README.pt-BR.md | 16 ++++++++++++---- docs/README.si.md | 16 ++++++++++++---- docs/README.zh-CN.md | 16 ++++++++++++---- 8 files changed, 96 insertions(+), 32 deletions(-) diff --git a/docs/README.es.md b/docs/README.es.md index 0aac0aa..9c2eeb2 100644 --- a/docs/README.es.md +++ b/docs/README.es.md @@ -28,7 +28,7 @@ Este repo solo versiona las herramientas — tus repos de proyecto los clona | | Qué obtienes | |---|---| -| 🧠 | **Skills de flujo de trabajo con IA** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (independientes del agente, en `.agents/skills/`, con symlinks para Claude Code; opencode también configurado) | +| 🧠 | **Skills de flujo de trabajo con IA** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (independientes del agente, en `.agents/skills/`, con symlinks para Claude Code; opencode también configurado) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — búsqueda semántica de código que los agentes usan vía MCP en lugar de grep y lectura de archivos | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — un grafo de conocimiento por repo que los agentes consultan en lugar de hacer grep, mantenido al día por hooks de git | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — proxy de comandos que optimiza tokens para Claude Code | @@ -148,7 +148,10 @@ README de proyecto). Lo que queda es el conocimiento que solo tú tienes — la sección **"Customize this workspace"** del README generado lleva esta misma lista de tareas a tu workspace: -- [ ] `AGENTS.md` — rellena la tabla **Systems** (una fila por repo: qué es, stack) y la sección **Testing**. Es la fuente de verdad que lee cada skill. Mantén sincronizada la tabla "What's inside" del README generado. +- [ ] `AGENTS.md` — rellena la tabla **Systems** (una fila por repo: qué es, stack, de qué depende), la tabla **Commands** y la sección **Testing**. Es la fuente de verdad que lee cada skill. Mantén sincronizada la tabla "What's inside" del README generado. +- [ ] `POLICY.md` — ajusta la Definition of Done y los triggers de ADR según el nivel de exigencia real de tu equipo (p. ej. añade un requisito de revisión de seguridad). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — reemplaza las entradas de ejemplo por tus sistemas/comandos/responsables reales (reflejan las tablas de `AGENTS.md`; `node scripts/validate-ai-config.mjs` verifica el formato). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — ajusta las rutas protegidas, las acciones prohibidas/que requieren aprobación, y los ejemplos de riesgo para tu proyecto. - [ ] `.agents/skills/code-review/references/` y `.agents/skills/write-doc/references/` — un archivo de referencia por repo (copia `_example-repo.md`). Las skills funcionan sin ellos, pero con ellos son mucho más precisas. - [ ] Si `issue_tracker` es `linear`: verifica la tabla de "Convenciones" de `.agents/skills/create-ticket/SKILL.md` contra tu workspace de Linear (equipos, proyectos, etiquetas). Si es `jira` u `other`: adapta las llamadas `mcp__linear__*` de `/start-task`, `/raise-pr` y `/create-ticket` a las herramientas MCP de tu gestor (cada skill lo señala al principio). - [ ] Elimina o ajusta lo que un toggle haya deshabilitado (p. ej. quita las notas de semble de `CLAUDE.md` si no lo usas). @@ -162,14 +165,19 @@ repo), edita `devrig.toml` directamente y vuelve a ejecutar `./setup.sh`. |---|---| | `devrig.toml` | Tu configuración de proyecto — el único archivo que leen todas las herramientas | | `setup.sh` | Script de arranque/actualización idempotente | -| `AGENTS.md` | Fuente de verdad independiente del agente (sistemas, reglas de ramas, convenciones) | +| `AGENTS.md` | Fuente de verdad independiente del agente (sistemas, comandos, reglas de ramas, política de retrieval) | +| `POLICY.md` | Definition of Done, requisito de ADR, política de riesgo/datos/roles, formatos de evidencia de verificación/confianza | +| `.ai/` | Reflejo legible por máquina de lo anterior (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), sus JSON Schemas en `.ai/schemas/`, y paquetes de contexto por tarea en `.ai/context/` (escritos por `/start-task`) | +| `.github/workflows/` | CI: valida `.ai/*.yaml` contra sus schemas, y valida `knowledge/` (frontmatter, enlaces, ids de ADR, frescura del índice, requisito de ADR en rutas protegidas) | | `CLAUDE.md` | Específicos de Claude Code; importa `AGENTS.md` | | `.agents/skills/` | Skills de flujo de trabajo canónicas (independientes del agente) | | `.claude/` | Ajustes de Claude Code, agentes, symlinks de skills | | `.opencode/` | Agentes y configuración de plugin de opencode | | `.mcp.json` / `opencode.json` | Servidores MCP (gestor de tickets, semble) | | `git-hooks/` | Hooks compartidos por todos los repos (`core.hooksPath`): pre-commit / pre-push de ramas protegidas, más las reconstrucciones del grafo de graphify | -| `knowledge/` | Base de conocimiento en markdown (arquitectura, decisiones, diseño, runbooks, producto, releases) | +| `knowledge/` | Base de conocimiento en markdown (arquitectura, decisiones, diseño, runbooks, producto, releases, handoffs, generated) — ver `knowledge/index.md` | +| `evals/` | Preguntas con respuestas de referencia, para medir precisión de retrieval/tasa de alucinación a lo largo del tiempo — ver `evals/README.md` | +| `scripts/` | Scripts de mantenimiento del workspace — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (sin seguimiento) | Tus repos de proyecto, clonados por `setup.sh` | ## Añadir una skill diff --git a/docs/README.fr.md b/docs/README.fr.md index 070024f..03a1f75 100644 --- a/docs/README.fr.md +++ b/docs/README.fr.md @@ -28,7 +28,7 @@ fichier **`devrig.toml`**. | | Ce que vous obtenez | |---|---| -| 🧠 | **Skills de workflow IA** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (indépendantes de l'agent, dans `.agents/skills/`, avec des liens symboliques pour Claude Code ; opencode est aussi configuré) | +| 🧠 | **Skills de workflow IA** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (indépendantes de l'agent, dans `.agents/skills/`, avec des liens symboliques pour Claude Code ; opencode est aussi configuré) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — recherche sémantique de code que les agents utilisent via MCP au lieu de grep et lecture de fichiers | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — un graphe de connaissances par dépôt que les agents interrogent au lieu de faire un grep, tenu à jour par des hooks git | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — proxy de commandes optimisant les tokens pour Claude Code | @@ -150,7 +150,10 @@ votre projet). Ce qui reste, c'est la connaissance que vous seul possédez — la section **« Customize this workspace »** du README généré reprend cette même checklist dans votre workspace : -- [ ] `AGENTS.md` — remplissez le tableau **Systems** (une ligne par dépôt : rôle, stack) et la section **Testing**. C'est la source de vérité que lit chaque skill. Gardez le tableau « What's inside » du README généré synchronisé. +- [ ] `AGENTS.md` — remplissez le tableau **Systems** (une ligne par dépôt : rôle, stack, dépendances), le tableau **Commands**, et la section **Testing**. C'est la source de vérité que lit chaque skill. Gardez le tableau « What's inside » du README généré synchronisé. +- [ ] `POLICY.md` — ajustez la Definition of Done et les déclencheurs d'ADR pour correspondre au niveau d'exigence réel de votre équipe (par ex. ajoutez une exigence de revue de sécurité). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — remplacez les entrées d'exemple par vos systèmes/commandes/propriétaires réels (miroir des tableaux d'`AGENTS.md` ; `node scripts/validate-ai-config.mjs` vérifie la structure). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — ajustez les chemins protégés, les actions interdites/soumises à approbation, et les exemples de risques pour votre projet. - [ ] `.agents/skills/code-review/references/` et `.agents/skills/write-doc/references/` — un fichier de référence par dépôt (copiez `_example-repo.md`). Les skills fonctionnent sans, mais elles sont bien plus affûtées avec. - [ ] Si `issue_tracker` vaut `linear` : vérifiez le tableau des « Conventions » de `.agents/skills/create-ticket/SKILL.md` avec votre workspace Linear (équipes, projets, labels). S'il vaut `jira` ou `other` : adaptez les appels `mcp__linear__*` de `/start-task`, `/raise-pr` et `/create-ticket` aux outils MCP de votre gestionnaire (chaque skill le signale en haut de fichier). - [ ] Supprimez ou ajustez ce qu'une option a désactivé (par ex. retirez les notes semble de `CLAUDE.md` si vous ne l'utilisez pas). @@ -164,14 +167,19 @@ ajouter un dépôt), éditez `devrig.toml` directement et relancez `./setup.sh`. |---|---| | `devrig.toml` | Votre configuration projet — le seul fichier que lit chaque outil | | `setup.sh` | Script de bootstrap/mise à jour idempotent | -| `AGENTS.md` | Source de vérité indépendante de l'agent (systèmes, règles de branches, conventions) | +| `AGENTS.md` | Source de vérité indépendante de l'agent (systèmes, commandes, règles de branches, politique de recherche) | +| `POLICY.md` | Definition of Done, exigence d'ADR, politique risques/données/rôles, rapport de vérification/confiance | +| `.ai/` | Miroir lisible par machine de ce qui précède (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), leurs schémas JSON dans `.ai/schemas/`, et les paquets de contexte par tâche dans `.ai/context/` (écrits par `/start-task`) | +| `.github/workflows/` | CI : valide les `.ai/*.yaml` par rapport à leurs schémas, et valide `knowledge/` (frontmatter, liens, ids d'ADR, fraîcheur de l'index, exigence d'ADR sur chemin protégé) | | `CLAUDE.md` | Spécificités Claude Code ; importe `AGENTS.md` | | `.agents/skills/` | Skills de workflow canoniques (indépendantes de l'agent) | | `.claude/` | Réglages Claude Code, agents, liens symboliques de skills | | `.opencode/` | Agents et configuration de plugin opencode | | `.mcp.json` / `opencode.json` | Serveurs MCP (gestionnaire de tickets, semble) | | `git-hooks/` | Hooks partagés par tous les dépôts (`core.hooksPath`) : pre-commit / pre-push de branches protégées, plus les reconstructions du graphe graphify | -| `knowledge/` | Base de connaissances markdown (architecture, décisions, conception, runbooks, produit, releases) | +| `knowledge/` | Base de connaissances markdown (architecture, décisions, conception, runbooks, produit, releases, handoffs, generated) — voir `knowledge/index.md` | +| `evals/` | Questions avec réponses de référence, pour mesurer la précision de recherche/le taux d'hallucination dans le temps — voir `evals/README.md` | +| `scripts/` | Scripts de maintenance du workspace — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (non suivi) | Vos dépôts de projet, clonés par `setup.sh` | ## Ajouter une skill diff --git a/docs/README.hi.md b/docs/README.hi.md index e41facc..171b410 100644 --- a/docs/README.hi.md +++ b/docs/README.hi.md @@ -27,7 +27,7 @@ version करता है — आपके प्रोजेक्ट repos | | आपको क्या मिलता है | |---|---| -| 🧠 | **AI वर्कफ़्लो skills** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (agent-agnostic, `.agents/skills/` में, Claude Code के लिए symlink; opencode भी कॉन्फ़िगर है) | +| 🧠 | **AI वर्कफ़्लो skills** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (agent-agnostic, `.agents/skills/` में, Claude Code के लिए symlink; opencode भी कॉन्फ़िगर है) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — semantic code search, जिसे agents grep-और-पढ़ने की जगह MCP के ज़रिए इस्तेमाल करते हैं | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — हर repo के लिए एक knowledge graph, जिसे agent grep के बजाय query करते हैं और git hooks उसे ताज़ा रखते हैं | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — Claude Code के लिए token बचाने वाला command proxy | @@ -145,7 +145,10 @@ devrig की टेम्पलेट फ़ाइलें हटाता ह **"Customize this workspace"** सेक्शन यही चेकलिस्ट आपके workspace में ले आता है: -- [ ] `AGENTS.md` — **Systems** टेबल (हर repo की एक पंक्ति: क्या है, stack) और **Testing** सेक्शन भरें। यही वह source of truth है जिसे हर skill पढ़ती है। जनरेट किए गए README की "What's inside" टेबल को भी साथ में अपडेट रखें। +- [ ] `AGENTS.md` — **Systems** टेबल (हर repo की एक पंक्ति: क्या है, stack, किस पर निर्भर है), **Commands** टेबल, और **Testing** सेक्शन भरें। यही वह source of truth है जिसे हर skill पढ़ती है। जनरेट किए गए README की "What's inside" टेबल को भी साथ में अपडेट रखें। +- [ ] `POLICY.md` — Definition of Done और ADR triggers को अपनी टीम के असली मापदंड से मिलाएं (जैसे security-review की ज़रूरत जोड़ना)। +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — उदाहरण की entries को अपने असली systems/commands/owners से बदलें (यह `AGENTS.md` की टेबलों को mirror करता है; `node scripts/validate-ai-config.mjs` उसका ढांचा जांचता है)। +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — protected paths, forbidden/approval-required actions, और risk के उदाहरण अपने प्रोजेक्ट के हिसाब से समायोजित करें। - [ ] `.agents/skills/code-review/references/` और `.agents/skills/write-doc/references/` — हर repo के लिए एक reference फ़ाइल (`_example-repo.md` कॉपी करें)। इनके बिना भी skills चलती हैं, पर इनके साथ कहीं तेज़ धार होती हैं। - [ ] अगर `issue_tracker` `linear` है: `.agents/skills/create-ticket/SKILL.md` की "Conventions" टेबल को अपने Linear workspace (teams, projects, labels) से सत्यापित करें। अगर `jira` या `other` है: `/start-task`, `/raise-pr`, और `/create-ticket` की `mcp__linear__*` calls को अपने tracker के MCP tool names में बदलें (हर skill इसे शुरुआत में बताती है)। - [ ] जो कुछ किसी toggle ने बंद किया है उसे हटाएँ या समायोजित करें (जैसे semble इस्तेमाल न करने पर `CLAUDE.md` से उसके नोट हटाएँ)। @@ -159,14 +162,19 @@ devrig की टेम्पलेट फ़ाइलें हटाता ह |---|---| | `devrig.toml` | आपका प्रोजेक्ट कॉन्फ़िग — वह एक फ़ाइल जिसे हर टूल पढ़ता है | | `setup.sh` | Idempotent bootstrap/update स्क्रिप्ट | -| `AGENTS.md` | Agent-agnostic source of truth (systems, branch नियम, conventions) | +| `AGENTS.md` | Agent-agnostic source of truth (systems, commands, branch नियम, retrieval policy) | +| `POLICY.md` | Definition of Done, ADR requirement, risk/data/role policy, verification/confidence reporting | +| `.ai/` | ऊपर वाली फ़ाइलों का machine-readable mirror (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), उनके JSON Schemas `.ai/schemas/` में, और per-task context bundles `.ai/context/` में (`/start-task` द्वारा लिखे गए) | +| `.github/workflows/` | CI: `.ai/*.yaml` को उसके schemas से validate करता है, और `knowledge/` को validate करता है (frontmatter, links, ADR ids, index freshness, protected-path ADR requirement) | | `CLAUDE.md` | Claude Code विशेष; `AGENTS.md` import करता है | | `.agents/skills/` | Canonical workflow skills (agent-agnostic) | | `.claude/` | Claude Code settings, agents, skill symlinks | | `.opencode/` | opencode agents और plugin config | | `.mcp.json` / `opencode.json` | MCP सर्वर (issue tracker, semble) | | `git-hooks/` | सभी repos के लिए साझा hooks (`core.hooksPath`): protected-branch pre-commit / pre-push, साथ ही graphify के graph rebuild | -| `knowledge/` | Markdown नॉलेज बेस (architecture, decisions, design, runbooks, product, releases) | +| `knowledge/` | Markdown नॉलेज बेस (architecture, decisions, design, runbooks, product, releases, handoffs, generated) — देखें `knowledge/index.md` | +| `evals/` | जाने-पहचाने सही उत्तरों वाले सवाल, समय के साथ retrieval accuracy/hallucination rate मापने के लिए — देखें `evals/README.md` | +| `scripts/` | Workspace maintenance scripts — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (untracked) | आपके प्रोजेक्ट repos, `setup.sh` द्वारा cloned | ## नई skill जोड़ना diff --git a/docs/README.ja.md b/docs/README.ja.md index 1149347..fe59ce9 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -28,7 +28,7 @@ devrig は*メタリポジトリ*です。プロジェクトのすべてのリ | | 含まれるもの | |---|---| -| 🧠 | **AI ワークフロースキル** — `/start-task`、`/raise-pr`、`/code-review`、`/write-doc`、`/create-ticket`(エージェント非依存で `.agents/skills/` に配置、Claude Code 用に symlink、opencode も設定済み) | +| 🧠 | **AI ワークフロースキル** — `/start-task`、`/plan-task`、`/verify-change`、`/raise-pr`、`/code-review`、`/write-doc`、`/capture-learning`、`/check-knowledge-consistency`、`/create-ticket`(エージェント非依存で `.agents/skills/` に配置、Claude Code 用に symlink、opencode も設定済み) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — grep とファイル読みの代わりにエージェントが MCP 経由で使うセマンティックコード検索 | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — リポジトリごとのナレッジグラフ。エージェントは grep の代わりにこれを問い合わせ、git フックが常に最新に保つ | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — Claude Code のトークンを節約するコマンドプロキシ | @@ -146,7 +146,10 @@ devrig のテンプレートファイルの削除、プロジェクト README **「Customize this workspace」** セクションが、このチェックリストをそのまま あなたのワークスペースに引き継ぎます: -- [ ] `AGENTS.md` — **Systems** テーブル(リポジトリごとに1行:役割、スタック)と **Testing** セクションを記入。すべてのスキルが読む唯一の情報源です。生成された README の「What's inside」テーブルも合わせて更新してください。 +- [ ] `AGENTS.md` — **Systems** テーブル(リポジトリごとに1行:役割、スタック、依存関係)、**Commands** テーブル、**Testing** セクションを記入。すべてのスキルが読む唯一の情報源です。生成された README の「What's inside」テーブルも合わせて更新してください。 +- [ ] `POLICY.md` — Definition of Done と ADR のトリガー条件を、あなたのチームの実際の基準に合わせて調整(例:セキュリティレビューの要件を追加)。 +- [ ] `.ai/systems.yaml`、`.ai/commands.yaml`、`.ai/ownership.yaml` — サンプルの内容を実際のシステム/コマンド/オーナーに置き換える(`AGENTS.md` のテーブルと対応します。形式は `node scripts/validate-ai-config.mjs` で検証できます)。 +- [ ] `.ai/policies.yaml`、`.ai/risk-levels.yaml` — protected paths、forbidden/approval-required actions、リスクの例を自分のプロジェクトに合わせて調整。 - [ ] `.agents/skills/code-review/references/` と `.agents/skills/write-doc/references/` — リポジトリごとにリファレンスファイルを1つ(`_example-repo.md` をコピー)。なくても動きますが、あると格段に鋭くなります。 - [ ] `issue_tracker` が `linear` の場合:`.agents/skills/create-ticket/SKILL.md` の「規約」テーブルを自分の Linear ワークスペース(チーム、プロジェクト、ラベル)と照合。`jira` や `other` の場合:`/start-task`、`/raise-pr`、`/create-ticket` の `mcp__linear__*` 呼び出しを自分のトラッカーの MCP ツール名に合わせて調整(各スキルの冒頭にその旨の記載あり)。 - [ ] トグルで無効化したものを削除・調整(例:semble を使わないなら `CLAUDE.md` から関連記述を削除)。 @@ -160,14 +163,19 @@ devrig のテンプレートファイルの削除、プロジェクト README |---|---| | `devrig.toml` | プロジェクト設定 — すべてのツールが読む唯一のファイル | | `setup.sh` | 冪等なブートストラップ/更新スクリプト | -| `AGENTS.md` | エージェント非依存の唯一の情報源(システム、ブランチルール、規約) | +| `AGENTS.md` | エージェント非依存の唯一の情報源(システム、コマンド、ブランチルール、リトリーバルポリシー) | +| `POLICY.md` | Definition of Done、ADR の要件、リスク/データ/ロールに関するポリシー、検証/確信度レポートの形式 | +| `.ai/` | 上記の機械可読なミラー(`systems.yaml`、`commands.yaml`、`ownership.yaml`、`policies.yaml`、`risk-levels.yaml`)と、`.ai/schemas/` の JSON Schema、`.ai/context/` のタスクごとのコンテキストバンドル(`/start-task` が書き込む) | +| `.github/workflows/` | CI:`.ai/*.yaml` をスキーマと照合して検証し、`knowledge/`(フロントマター、リンク、ADR の ID、インデックスの鮮度、protected path での ADR 要件)を検証 | | `CLAUDE.md` | Claude Code 固有の内容。`AGENTS.md` をインポート | | `.agents/skills/` | 正規のワークフロースキル(エージェント非依存) | | `.claude/` | Claude Code の設定、エージェント、スキルの symlink | | `.opencode/` | opencode のエージェントとプラグイン設定 | | `.mcp.json` / `opencode.json` | MCP サーバー(課題管理ツール、semble) | | `git-hooks/` | 全リポジトリ共有のフック(`core.hooksPath`):保護ブランチ用 pre-commit / pre-push と、graphify のグラフ再構築 | -| `knowledge/` | markdown ナレッジベース(アーキテクチャ、決定、設計、runbook、プロダクト、リリース) | +| `knowledge/` | markdown ナレッジベース(アーキテクチャ、決定、設計、runbook、プロダクト、リリース、handoff、generated)— `knowledge/index.md` を参照 | +| `evals/` | 検索精度/ハルシネーション率を継続的に測定するための、模範解答つきの質問集 — `evals/README.md` を参照 | +| `scripts/` | ワークスペース保守用スクリプト — `build-knowledge-index.mjs`、`validate-knowledge.mjs`、`validate-ai-config.mjs`、`detect-doc-drift.mjs`、`check-adr-requirement.mjs`、`generate-architecture-views.mjs` | | `<repo>/`(未追跡) | `setup.sh` がクローンするプロジェクトリポジトリ | ## スキルの追加 diff --git a/docs/README.ko.md b/docs/README.ko.md index ce3226d..929e2eb 100644 --- a/docs/README.ko.md +++ b/docs/README.ko.md @@ -27,7 +27,7 @@ devrig는 *메타 레포*입니다. 프로젝트의 모든 저장소와 그 사 | | 제공되는 것 | |---|---| -| 🧠 | **AI 워크플로우 스킬** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (에이전트 독립적으로 `.agents/skills/`에 위치, Claude Code용 심볼릭 링크, opencode도 설정됨) | +| 🧠 | **AI 워크플로우 스킬** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (에이전트 독립적으로 `.agents/skills/`에 위치, Claude Code용 심볼릭 링크, opencode도 설정됨) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — grep과 파일 읽기 대신 에이전트가 MCP로 사용하는 시맨틱 코드 검색 | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — 레포마다 하나씩 생기는 지식 그래프. 에이전트가 grep 대신 이걸 질의하고, git 훅이 항상 최신으로 유지 | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — Claude Code의 토큰을 절약하는 명령어 프록시 | @@ -143,7 +143,10 @@ Help me go from this description to a working workspace: — 생성된 README의 **"Customize this workspace"** 섹션이 이 체크리스트를 그대로 워크스페이스로 옮겨 옵니다: -- [ ] `AGENTS.md` — **Systems** 표(저장소마다 한 줄: 역할, 스택)와 **Testing** 섹션 작성. 모든 스킬이 읽는 단일 정보원입니다. 생성된 README의 "What's inside" 표도 함께 최신 상태로 유지하세요. +- [ ] `AGENTS.md` — **Systems** 표(저장소마다 한 줄: 역할, 스택, 무엇에 의존하는지), **Commands** 표, **Testing** 섹션 작성. 모든 스킬이 읽는 단일 정보원입니다. 생성된 README의 "What's inside" 표도 함께 최신 상태로 유지하세요. +- [ ] `POLICY.md` — Definition of Done과 ADR 트리거를 팀의 실제 기준에 맞게 조정하세요(예: 보안 검토 요구사항 추가). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — 예시 항목을 실제 시스템/명령어/소유자로 교체하세요(`AGENTS.md`의 표를 그대로 반영; `node scripts/validate-ai-config.mjs`로 형식을 검증할 수 있습니다). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — 프로젝트에 맞게 보호 경로, 금지/승인 필요 작업, 위험 예시를 조정하세요. - [ ] `.agents/skills/code-review/references/`와 `.agents/skills/write-doc/references/` — 저장소마다 레퍼런스 파일 하나(`_example-repo.md` 복사). 없어도 동작하지만 있으면 훨씬 정밀해집니다. - [ ] `issue_tracker`가 `linear`라면: `.agents/skills/create-ticket/SKILL.md`의 "컨벤션" 표를 Linear 워크스페이스(팀, 프로젝트, 라벨)와 대조하세요. `jira`나 `other`라면: `/start-task`, `/raise-pr`, `/create-ticket`의 `mcp__linear__*` 호출을 트래커의 MCP 도구 이름에 맞게 조정하세요(각 스킬 상단에 안내가 있습니다). - [ ] 토글로 비활성화한 것들 삭제·조정(예: semble을 쓰지 않으면 `CLAUDE.md`에서 관련 내용 제거). @@ -157,14 +160,19 @@ Help me go from this description to a working workspace: |---|---| | `devrig.toml` | 프로젝트 설정 — 모든 도구가 읽는 단 하나의 파일 | | `setup.sh` | 멱등한 부트스트랩/업데이트 스크립트 | -| `AGENTS.md` | 에이전트 독립적 단일 정보원(시스템, 브랜치 규칙, 컨벤션) | +| `AGENTS.md` | 에이전트 독립적 단일 정보원(시스템, 명령어, 브랜치 규칙, 검색 정책) | +| `POLICY.md` | Definition of Done, ADR 요구사항, 위험/데이터/역할 정책, 검증/신뢰도 보고 | +| `.ai/` | 위 내용의 기계 판독 가능한 사본(`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), `.ai/schemas/`의 JSON 스키마, `/start-task`가 작성하는 `.ai/context/`의 태스크별 컨텍스트 번들 | +| `.github/workflows/` | CI: `.ai/*.yaml`을 스키마로 검증하고, `knowledge/`를 검증(프런트매터, 링크, ADR id, 인덱스 최신성, 보호 경로 ADR 요구사항) | | `CLAUDE.md` | Claude Code 전용 내용; `AGENTS.md`를 임포트 | | `.agents/skills/` | 표준 워크플로우 스킬(에이전트 독립적) | | `.claude/` | Claude Code 설정, 에이전트, 스킬 심볼릭 링크 | | `.opencode/` | opencode 에이전트 및 플러그인 설정 | | `.mcp.json` / `opencode.json` | MCP 서버(이슈 트래커, semble) | | `git-hooks/` | 모든 레포가 공유하는 훅(`core.hooksPath`): 보호 브랜치 pre-commit / pre-push, 그리고 graphify 그래프 재빌드 | -| `knowledge/` | markdown 지식 베이스(아키텍처, 결정, 설계, 런북, 제품, 릴리스) | +| `knowledge/` | markdown 지식 베이스(아키텍처, 결정, 설계, 런북, 제품, 릴리스, 인수인계, 생성물) — `knowledge/index.md` 참고 | +| `evals/` | 검색 정확도/환각률을 시간에 따라 측정하기 위한, 정답이 있는 질문 모음 — `evals/README.md` 참고 | +| `scripts/` | 워크스페이스 유지보수 스크립트 — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (미추적) | `setup.sh`가 클론하는 프로젝트 저장소 | ## 스킬 추가하기 diff --git a/docs/README.pt-BR.md b/docs/README.pt-BR.md index 5aee1bb..c921276 100644 --- a/docs/README.pt-BR.md +++ b/docs/README.pt-BR.md @@ -28,7 +28,7 @@ de um único arquivo **`devrig.toml`**. | | O que você ganha | |---|---| -| 🧠 | **Skills de fluxo de trabalho com IA** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (independentes de agente, em `.agents/skills/`, com symlinks para o Claude Code; opencode também configurado) | +| 🧠 | **Skills de fluxo de trabalho com IA** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (independentes de agente, em `.agents/skills/`, com symlinks para o Claude Code; opencode também configurado) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — busca semântica de código que os agentes usam via MCP em vez de grep e leitura de arquivos | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — um grafo de conhecimento por repo que os agentes consultam em vez de fazer grep, mantido atualizado por hooks do git | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — proxy de comandos que otimiza tokens para o Claude Code | @@ -147,7 +147,10 @@ remove os arquivos do template do devrig, gera o README do seu projeto). O que resta é o conhecimento que só você tem — a seção **"Customize this workspace"** do README gerado leva essa mesma checklist para o seu workspace: -- [ ] `AGENTS.md` — preencha a tabela **Systems** (uma linha por repo: o que é, stack) e a seção **Testing**. É a fonte de verdade que toda skill lê. Mantenha a tabela "What's inside" do README gerado sincronizada. +- [ ] `AGENTS.md` — preencha a tabela **Systems** (uma linha por repo: o que é, stack, do que depende), a tabela **Commands** e a seção **Testing**. É a fonte de verdade que toda skill lê. Mantenha a tabela "What's inside" do README gerado sincronizada. +- [ ] `POLICY.md` — ajuste a Definition of Done e os gatilhos de ADR para o padrão real do seu time (ex.: adicione uma exigência de revisão de segurança). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — substitua os exemplos pelos seus sistemas/comandos/donos reais (espelham as tabelas do `AGENTS.md`; `node scripts/validate-ai-config.mjs` verifica o formato). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — ajuste os caminhos protegidos, as ações proibidas/que exigem aprovação e os exemplos de risco para o seu projeto. - [ ] `.agents/skills/code-review/references/` e `.agents/skills/write-doc/references/` — um arquivo de referência por repo (copie `_example-repo.md`). As skills funcionam sem eles, mas ficam muito mais afiadas com eles. - [ ] Se `issue_tracker` for `linear`: verifique a tabela de "Convenções" de `.agents/skills/create-ticket/SKILL.md` contra seu workspace do Linear (times, projetos, labels). Se for `jira` ou `other`: adapte as chamadas `mcp__linear__*` de `/start-task`, `/raise-pr` e `/create-ticket` para as ferramentas MCP do seu gestor (cada skill sinaliza isso no topo). - [ ] Remova ou ajuste o que um toggle desabilitou (ex.: remova as notas do semble do `CLAUDE.md` se você não usa). @@ -161,14 +164,19 @@ repo), edite `devrig.toml` diretamente e rode `./setup.sh` de novo. |---|---| | `devrig.toml` | Sua configuração de projeto — o único arquivo que toda ferramenta lê | | `setup.sh` | Script de bootstrap/atualização idempotente | -| `AGENTS.md` | Fonte de verdade independente de agente (sistemas, regras de branch, convenções) | +| `AGENTS.md` | Fonte de verdade independente de agente (sistemas, comandos, regras de branch, política de retrieval) | +| `POLICY.md` | Definition of Done, exigência de ADR, política de risco/dados/papéis, relatórios de verificação/confiança | +| `.ai/` | Espelho legível por máquina do acima (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), seus JSON Schemas em `.ai/schemas/`, e pacotes de contexto por tarefa em `.ai/context/` (gravados pelo `/start-task`) | +| `.github/workflows/` | CI: valida os `.ai/*.yaml` contra seus schemas, e valida o `knowledge/` (frontmatter, links, ids de ADR, atualização do índice, exigência de ADR em caminhos protegidos) | | `CLAUDE.md` | Específicos do Claude Code; importa `AGENTS.md` | | `.agents/skills/` | Skills de fluxo de trabalho canônicas (independentes de agente) | | `.claude/` | Configurações do Claude Code, agentes, symlinks de skills | | `.opencode/` | Agentes e configuração de plugin do opencode | | `.mcp.json` / `opencode.json` | Servidores MCP (gestor de tickets, semble) | | `git-hooks/` | Hooks compartilhados por todos os repos (`core.hooksPath`): pre-commit / pre-push de branches protegidas, mais as reconstruções do grafo do graphify | -| `knowledge/` | Base de conhecimento em markdown (arquitetura, decisões, design, runbooks, produto, releases) | +| `knowledge/` | Base de conhecimento em markdown (arquitetura, decisões, design, runbooks, produto, releases, handoffs, generated) — veja `knowledge/index.md` | +| `evals/` | Perguntas com respostas conhecidas, para medir a precisão de retrieval/taxa de alucinação ao longo do tempo — veja `evals/README.md` | +| `scripts/` | Scripts de manutenção do workspace — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (não rastreado) | Seus repos de projeto, clonados pelo `setup.sh` | ## Adicionando uma skill diff --git a/docs/README.si.md b/docs/README.si.md index 59ff384..7bdf140 100644 --- a/docs/README.si.md +++ b/docs/README.si.md @@ -28,7 +28,7 @@ devrig යනු *meta-repo* එකකි: ඔබේ ව්‍යාපෘති | | ඔබට ලැබෙන දේ | |---|---| -| 🧠 | **AI workflow skills** — `/start-task`, `/raise-pr`, `/code-review`, `/write-doc`, `/create-ticket` (agent-agnostic ලෙස `.agents/skills/` තුළ, Claude Code සඳහා symlink කර ඇත; opencode ද වින්‍යාස කර ඇත) | +| 🧠 | **AI workflow skills** — `/start-task`, `/plan-task`, `/verify-change`, `/raise-pr`, `/code-review`, `/write-doc`, `/capture-learning`, `/check-knowledge-consistency`, `/create-ticket` (agent-agnostic ලෙස `.agents/skills/` තුළ, Claude Code සඳහා symlink කර ඇත; opencode ද වින්‍යාස කර ඇත) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — grep කර ගොනු කියවීම වෙනුවට agents MCP හරහා භාවිත කරන semantic code search | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — repo එකකට එකක් වන knowledge graph; agents grep කිරීම වෙනුවට එය query කරයි, git hooks එය නැවුම්ව තබා ගනී | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — Claude Code සඳහා token ඉතිරි කරන command proxy | @@ -148,7 +148,10 @@ Help me go from this description to a working workspace: **"Customize this workspace"** කොටස මෙම පිරික්සුම් ලැයිස්තුවම ඔබේ workspace එකට ගෙන එයි: -- [ ] `AGENTS.md` — **Systems** වගුව (repo එකකට එක පේළියක්: එය කුමක්ද, stack) සහ **Testing** කොටස පුරවන්න. සෑම skill එකක්ම කියවන source of truth මෙයයි. generate වූ README හි "What's inside" වගුවද යාවත්කාලීනව තබා ගන්න. +- [ ] `AGENTS.md` — **Systems** වගුව (repo එකකට එක පේළියක්: එය කුමක්ද, stack, කුමක් මත රඳා පවතීද), **Commands** වගුව, සහ **Testing** කොටස පුරවන්න. සෑම skill එකක්ම කියවන source of truth මෙයයි. generate වූ README හි "What's inside" වගුවද යාවත්කාලීනව තබා ගන්න. +- [ ] `POLICY.md` — ඔබේ කණ්ඩායමේ සැබෑ ප්‍රමිතියට ගැලපෙන පරිදි Definition of Done සහ ADR trigger සකසන්න (උදා: security-review අවශ්‍යතාවක් එකතු කිරීම). +- [ ] `.ai/systems.yaml`, `.ai/commands.yaml`, `.ai/ownership.yaml` — උදාහරණ ඇතුළත් කිරීම් ඔබේ සැබෑ systems/commands/owners වලින් ප්‍රතිස්ථාපනය කරන්න (`AGENTS.md` හි වගු පිළිබිඹු කරයි; `node scripts/validate-ai-config.mjs` මගින් හැඩය පරීක්ෂා කරයි). +- [ ] `.ai/policies.yaml`, `.ai/risk-levels.yaml` — ඔබේ ව්‍යාපෘතිය සඳහා protected paths, forbidden/approval-required actions, සහ risk උදාහරණ සකසන්න. - [ ] `.agents/skills/code-review/references/` සහ `.agents/skills/write-doc/references/` — repo එකකට එක reference ගොනුවක් (`_example-repo.md` copy කරන්න). ඒවා නැතිවත් skills ක්‍රියා කරයි, නමුත් ඒවා සමඟ බෙහෙවින් තියුණුයි. - [ ] `issue_tracker` `linear` නම්: `.agents/skills/create-ticket/SKILL.md` හි "Conventions" වගුව ඔබේ Linear workspace එක (teams, projects, labels) සමඟ තහවුරු කරන්න. `jira` හෝ `other` නම්: `/start-task`, `/raise-pr`, සහ `/create-ticket` හි `mcp__linear__*` calls ඔබේ tracker එකේ MCP tool නම් වලට ගැලපෙන ලෙස සකසන්න (එය සෑම skill එකකම මුලින්ම සඳහන් වේ). - [ ] Toggle එකකින් අක්‍රීය කළ දේ ඉවත් කරන්න හෝ සකසන්න (උදා: semble භාවිත නොකරන්නේ නම් `CLAUDE.md` වෙතින් ඒ පිළිබඳ සටහන් ඉවත් කරන්න). @@ -162,14 +165,19 @@ Help me go from this description to a working workspace: |---|---| | `devrig.toml` | ඔබේ ව්‍යාපෘති වින්‍යාසය — සෑම මෙවලමක්ම කියවන එකම ගොනුව | | `setup.sh` | Idempotent bootstrap/update script | -| `AGENTS.md` | Agent-agnostic source of truth (systems, branch නීති, conventions) | +| `AGENTS.md` | Agent-agnostic source of truth (systems, commands, branch නීති, retrieval policy) | +| `POLICY.md` | Definition of Done, ADR අවශ්‍යතාව, risk/data/role policy, verification/confidence reporting | +| `.ai/` | ඉහත සඳහන් දේවල machine-readable පිළිබිඹුව (`systems.yaml`, `commands.yaml`, `ownership.yaml`, `policies.yaml`, `risk-levels.yaml`), ඒවායේ JSON Schemas `.ai/schemas/` හි, සහ `.ai/context/` හි task-context bundles (`/start-task` මගින් ලියනු ලැබේ) | +| `.github/workflows/` | CI: `.ai/*.yaml` එහි schemas අනුව validate කරයි, සහ `knowledge/` validate කරයි (frontmatter, links, ADR ids, index freshness, protected-path ADR requirement) | | `CLAUDE.md` | Claude Code විශේෂිත; `AGENTS.md` import කරයි | | `.agents/skills/` | සම්මත workflow skills (agent-agnostic) | | `.claude/` | Claude Code settings, agents, skill symlinks | | `.opencode/` | opencode agents සහ plugin config | | `.mcp.json` / `opencode.json` | MCP servers (issue tracker, semble) | | `git-hooks/` | සියලු repos බෙදාගන්නා hooks (`core.hooksPath`): protected-branch pre-commit / pre-push, සහ graphify graph නැවත ගොඩනැඟීම් | -| `knowledge/` | Markdown දැනුම් පදනම (architecture, decisions, design, runbooks, product, releases) | +| `knowledge/` | Markdown දැනුම් පදනම (architecture, decisions, design, runbooks, product, releases, handoffs, generated) — `knowledge/index.md` බලන්න | +| `evals/` | කාලයත් සමඟ retrieval accuracy/hallucination rate මැනීම සඳහා දන්නා-නිවැරදි පිළිතුරු සහිත ප්‍රශ්න — `evals/README.md` බලන්න | +| `scripts/` | Workspace maintenance scripts — `build-knowledge-index.mjs`, `validate-knowledge.mjs`, `validate-ai-config.mjs`, `detect-doc-drift.mjs`, `check-adr-requirement.mjs`, `generate-architecture-views.mjs` | | `<repo>/` (untracked) | `setup.sh` මගින් clone වන ඔබේ ව්‍යාපෘති repos | ## Skill එකක් එකතු කිරීම diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md index ec3f031..a15ce05 100644 --- a/docs/README.zh-CN.md +++ b/docs/README.zh-CN.md @@ -24,7 +24,7 @@ devrig 是一个*元仓库(meta-repo)*:一个文件夹容纳项目的所 | | 你将获得 | |---|---| -| 🧠 | **AI 工作流技能** — `/start-task`、`/raise-pr`、`/code-review`、`/write-doc`、`/create-ticket`(与具体 agent 无关,存放于 `.agents/skills/`,为 Claude Code 建立符号链接,同时配置了 opencode) | +| 🧠 | **AI 工作流技能** — `/start-task`、`/plan-task`、`/verify-change`、`/raise-pr`、`/code-review`、`/write-doc`、`/capture-learning`、`/check-knowledge-consistency`、`/create-ticket`(与具体 agent 无关,存放于 `.agents/skills/`,为 Claude Code 建立符号链接,同时配置了 opencode) | | 🔍 | **[semble](https://github.com/MinishLab/semble)** — 语义代码搜索,agent 通过 MCP 使用它替代 grep+逐个读取文件 | | 🕸️ | **[graphify](https://github.com/Graphify-Labs/graphify)** — 每个仓库一张知识图谱,agent 查询它而不是 grep,由 git 钩子保持最新 | | ⚡ | **[rtk](https://github.com/rtk-ai/rtk)** — 为 Claude Code 优化 token 消耗的命令代理 | @@ -128,7 +128,10 @@ Help me go from this description to a working workspace: 模板文件、生成你的项目 README)。剩下的是只有你才知道的信息 — 生成的 README 中 **"Customize this workspace"** 一节把同样的清单带到了你的工作区里: -- [ ] `AGENTS.md` — 填写 **Systems** 表(每个仓库一行:它是什么、技术栈)和 **Testing** 部分。这是所有技能读取的唯一信息源。同时保持生成的 README 中 "What's inside" 表的同步。 +- [ ] `AGENTS.md` — 填写 **Systems** 表(每个仓库一行:它是什么、技术栈、依赖什么)、**Commands** 表,以及 **Testing** 部分。这是所有技能读取的唯一信息源。同时保持生成的 README 中 "What's inside" 表的同步。 +- [ ] `POLICY.md` — 根据你团队的实际标准调整 Definition of Done 和 ADR 触发条件(例如加入安全审查要求)。 +- [ ] `.ai/systems.yaml`、`.ai/commands.yaml`、`.ai/ownership.yaml` — 用你真实的系统/命令/负责人替换示例条目(与 `AGENTS.md` 的表格对应;`node scripts/validate-ai-config.mjs` 会校验格式)。 +- [ ] `.ai/policies.yaml`、`.ai/risk-levels.yaml` — 为你的项目调整受保护路径、禁止/需审批的操作,以及风险等级示例。 - [ ] `.agents/skills/code-review/references/` 和 `.agents/skills/write-doc/references/` — 每个仓库一个参考文件(复制 `_example-repo.md`)。没有它们技能也能用,但有了会锐利得多。 - [ ] 若 `issue_tracker` 是 `linear`:对照你的 Linear 工作区核实 `.agents/skills/create-ticket/SKILL.md` 的"约定"表(团队、项目、标签)。若是 `jira` 或 `other`:把 `/start-task`、`/raise-pr`、`/create-ticket` 中的 `mcp__linear__*` 调用适配为你的工单系统的 MCP 工具名(每个技能文件顶部都有提示)。 - [ ] 删除或调整被开关禁用的内容(例如不用 semble 就从 `CLAUDE.md` 删除相关说明)。 @@ -142,14 +145,19 @@ Help me go from this description to a working workspace: |---|---| | `devrig.toml` | 项目配置 — 所有工具读取的唯一文件 | | `setup.sh` | 幂等的引导/更新脚本 | -| `AGENTS.md` | 与 agent 无关的唯一信息源(系统、分支规则、约定) | +| `AGENTS.md` | 与 agent 无关的唯一信息源(系统、命令、分支规则、检索策略) | +| `POLICY.md` | Definition of Done、ADR 要求、风险/数据/角色策略、验证证据与置信度报告 | +| `.ai/` | 上述内容的机器可读镜像(`systems.yaml`、`commands.yaml`、`ownership.yaml`、`policies.yaml`、`risk-levels.yaml`),及 `.ai/schemas/` 中对应的 JSON Schema,以及 `.ai/context/` 中按任务生成的上下文包(由 `/start-task` 写入) | +| `.github/workflows/` | CI:校验 `.ai/*.yaml` 是否符合其 schema,并校验 `knowledge/`(frontmatter、链接、ADR 编号、索引是否最新、受保护路径的 ADR 要求) | | `CLAUDE.md` | Claude Code 专属内容;导入 `AGENTS.md` | | `.agents/skills/` | 规范的工作流技能(与 agent 无关) | | `.claude/` | Claude Code 设置、agent、技能符号链接 | | `.opencode/` | opencode 的 agent 和插件配置 | | `.mcp.json` / `opencode.json` | MCP 服务器(工单系统、semble) | | `git-hooks/` | 所有仓库共享的钩子(`core.hooksPath`):受保护分支的 pre-commit / pre-push,以及 graphify 的图谱重建 | -| `knowledge/` | markdown 知识库(架构、决策、设计、运维手册、产品、发布) | +| `knowledge/` | markdown 知识库(架构、决策、设计、运维手册、产品、发布、交接记录、生成内容)— 见 `knowledge/index.md` | +| `evals/` | 带有已知正确答案的问题集,用于长期衡量检索准确率/幻觉率 — 见 `evals/README.md` | +| `scripts/` | 工作区维护脚本 — `build-knowledge-index.mjs`、`validate-knowledge.mjs`、`validate-ai-config.mjs`、`detect-doc-drift.mjs`、`check-adr-requirement.mjs`、`generate-architecture-views.mjs` | | `<repo>/`(不跟踪) | 你的项目仓库,由 `setup.sh` 克隆 | ## 添加技能 From af247077ccaf9a41e812212e5219b355f8dfd416 Mon Sep 17 00:00:00 2001 From: Lakpriya Seneviratna <lakpriya1@yahoo.com> Date: Mon, 17 Aug 2026 14:00:41 +0900 Subject: [PATCH 9/9] fix(docs): use full-width parentheses in README.ja.md's new rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The translation-sync commit introduced 3 table rows using half-width `()` where the rest of the file consistently uses full-width `()` — a nit flagged by the fork that did the sync. Also restored a lost trailing pipe and the .github/workflows/ row that got dropped in my first fix attempt. --- docs/README.ja.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.ja.md b/docs/README.ja.md index fe59ce9..8c97181 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -163,10 +163,10 @@ devrig のテンプレートファイルの削除、プロジェクト README |---|---| | `devrig.toml` | プロジェクト設定 — すべてのツールが読む唯一のファイル | | `setup.sh` | 冪等なブートストラップ/更新スクリプト | -| `AGENTS.md` | エージェント非依存の唯一の情報源(システム、コマンド、ブランチルール、リトリーバルポリシー) | +| `AGENTS.md` | エージェント非依存の唯一の情報源(システム、コマンド、ブランチルール、リトリーバルポリシー) | | `POLICY.md` | Definition of Done、ADR の要件、リスク/データ/ロールに関するポリシー、検証/確信度レポートの形式 | -| `.ai/` | 上記の機械可読なミラー(`systems.yaml`、`commands.yaml`、`ownership.yaml`、`policies.yaml`、`risk-levels.yaml`)と、`.ai/schemas/` の JSON Schema、`.ai/context/` のタスクごとのコンテキストバンドル(`/start-task` が書き込む) | -| `.github/workflows/` | CI:`.ai/*.yaml` をスキーマと照合して検証し、`knowledge/`(フロントマター、リンク、ADR の ID、インデックスの鮮度、protected path での ADR 要件)を検証 | +| `.ai/` | 上記の機械可読なミラー(`systems.yaml`、`commands.yaml`、`ownership.yaml`、`policies.yaml`、`risk-levels.yaml`)と、`.ai/schemas/` の JSON Schema、`.ai/context/` のタスクごとのコンテキストバンドル(`/start-task` が書き込む) | +| `.github/workflows/` | CI:`.ai/*.yaml` をスキーマと照合して検証し、`knowledge/`(フロントマター、リンク、ADR の ID、インデックスの鮮度、protected path での ADR 要件)を検証 | | `CLAUDE.md` | Claude Code 固有の内容。`AGENTS.md` をインポート | | `.agents/skills/` | 正規のワークフロースキル(エージェント非依存) | | `.claude/` | Claude Code の設定、エージェント、スキルの symlink |