diff --git a/.claude/knowledge/_index.md b/.claude/knowledge/_index.md new file mode 100644 index 0000000..60eeafa --- /dev/null +++ b/.claude/knowledge/_index.md @@ -0,0 +1,13 @@ +# Knowledge Index + +## Architecture +- `architecture/skill-design-conventions.md` — Context economy as design principle; description budget + `skillListingBudgetFraction`; Trigger-line format +- `architecture/skill-composition.md` — Flag contracts (`--no-poll`/`--auto`), shared scripts, format contracts, soft coupling +- `architecture/model-economics.md` — Which model per skill and why (Haiku/Sonnet/session-model) + +## Features +- `features/backfill-and-origin-metadata.md` — `/backfill-knowledge` significance bar + origin-reconstruction cascade +- `features/statusline-integration.md` — Status-line segment: plugins can't own `statusLine.command`; marker-block injection + +## Deployment +- `deployment/ci-structure-checks.md` — `check-structure.py` as the single automated guard for a build-less repo diff --git a/.claude/knowledge/architecture/model-economics.md b/.claude/knowledge/architecture/model-economics.md new file mode 100644 index 0000000..2f9340a --- /dev/null +++ b/.claude/knowledge/architecture/model-economics.md @@ -0,0 +1,53 @@ +--- +title: "Model Economics: Picking the Model per Skill" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "branch: task/dogfood-knowledge-system" +updatedFrom: "branch: task/dogfood-knowledge-system" +pluginVersion: 1.8.0 +prime: true +--- + +# Model Economics + +Each subagent-backed skill picks its model from the **task shape and invocation +frequency**, not a default. The reasoning is recorded in each skill's "Model +rationale" section; this is the cross-cutting summary. + +## The assignments and why + +- **`/query` → Haiku** (the knowledge agent's `model: haiku`). The task is a + bounded lookup: read the index, pick relevant files, summarize. No reasoning + over ambiguous requirements, no architectural judgment. `/query` is invoked + *often* — potentially before every non-trivial change — so cost compounds; + Haiku keeps it cheap enough to stay usable, and fast (<2s). + +- **`/query` Explore fallback → session model (no override).** When knowledge + has a gap and the skill falls back to codebase exploration, that work is + open-ended (which files matter, when to stop) and needs session-model + reasoning quality. It runs rarely, so its higher cost is negligible. + +- **`/reindex` → Sonnet, background.** A semantic reasoning task — judging + duplicates, cross-links, frontmatter correctness across the whole graph. + Haiku would miss subtle overlaps; Opus is overkill for structured analysis. + Sonnet hits the quality/cost sweet spot. It runs `run_in_background: true` + because a thorough pass reads many files over 1–3 minutes; blocking the + session would be hostile. + +## The principle + +Match model tier to the *kind* of thinking required, then weight by how often +the skill runs: + +- **Bounded, mechanical, frequent** → cheapest capable model (Haiku). +- **Semantic judgment, occasional** → mid tier (Sonnet). +- **Open-ended reasoning, rare** → inherit the session model rather than pin a + tier. + +A second axis is **context hygiene**: `/query` and `/reindex` run as subagents +(not in-context) specifically to keep the main window clean — they read many +files and return a dense answer instead of dragging file contents into the +primary session. `/prime` is the deliberate inverse: it loads content *into* +the main context on purpose, so it runs in-context with no subagent. + +Related: [[skill-design-conventions]], [[skill-composition]]. diff --git a/.claude/knowledge/architecture/skill-composition.md b/.claude/knowledge/architecture/skill-composition.md new file mode 100644 index 0000000..aafb7d6 --- /dev/null +++ b/.claude/knowledge/architecture/skill-composition.md @@ -0,0 +1,69 @@ +--- +title: "Skill Composition: Flag Contracts, Shared Scripts, Soft Coupling" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "branch: task/dogfood-knowledge-system" +updatedFrom: "branch: task/dogfood-knowledge-system" +pluginVersion: 1.8.0 +prime: true +--- + +# Skill Composition + +Skills in this marketplace compose rather than duplicate. Three mechanisms make +that work, and a fourth keeps plugins loosely coupled so they can split apart +cleanly later. + +## 1. Flag contracts (one skill as another's subroutine) + +A skill that a parent invokes exposes flags that suppress interaction the parent +has already handled. The canonical example is `/rebase`, called as a subroutine +by `/open`, `/cycle`, and `/merge`, with `--no-poll` (the parent does its own +review polling) and `--auto` (the parent's invocation *is* the authorization, so +the subroutine skips menus it would otherwise show). + +The principle, not the exact flag mechanics (which live in +`plugins/pr-flow/skills/rebase/SKILL.md` and evolve there): a parent-authorized +flag removes **prompts**, never **safety stops**. Conflicts still abort, +missing-upstream still stops — `--auto` only drops the confirmation the parent +already implied by calling. Re-prompting after an explicit opt-in is its own +anti-pattern. Refer to the rebase skill for the current, authoritative +semantics rather than relying on this summary. + +## 2. Shared scripts as single source of truth + +Logic used by multiple skills lives in one script, not copied prose. +`plugins/pr-flow/scripts/claude-review.sh` (poll / latest / latest-after) is +shared by five skills — `/check`, `/cycle`, `/merge`, `/open`, `/rebase` +(note: `/fix` does **not** use it; it only consumes the review *format* below). +One implementation to harden — real-world fixes (fractional-seconds parsing, +merge-method detection from PR history, `mergeStateStatus` interpretation) land +once and all callers benefit. + +## 3. Format contracts between skills + +When one skill must parse another's output, the format is pinned in a shared +spec. `plugins/pr-flow/docs/REVIEW-OUTPUT-FORMAT.md` lets `/fix` deterministically +parse the findings table `/cycle` produces. The contract is the interface; +neither side reverse-engineers the other. + +## 4. Soft coupling for a future split + +Plugins detect each other generically, never by hard dependency. +pr-flow recognizes knowledge systems by convention (`.claude/knowledge/`, +`.cursor/rules/`, `AGENTS.md`, …) rather than importing the knowledge-system +plugin; `/merge` *offers* `/close` instead of calling it. This keeps the +plugins independently installable and is the right shape for an eventual +extraction (e.g. the Codex split). + +## Why extract-to-shared-spec is the standing remedy + +Duplicated logic across two skills drifts. The fix is always to pull the shared +part into one source the callers reference — exactly mechanisms 2 and 3. The +doc-readiness checks once duplicated between `/open` and `/merge` were resolved +this way: both now read `plugins/pr-flow/docs/READINESS-CHECKS.md` instead of +each carrying their own copy. When you see the same logic in two skills, that is +the move. + +Related: [[skill-design-conventions]]. See also the `cwd-safety` rule +(`.claude/rules/cwd-safety.md`). diff --git a/.claude/knowledge/architecture/skill-design-conventions.md b/.claude/knowledge/architecture/skill-design-conventions.md new file mode 100644 index 0000000..187f61e --- /dev/null +++ b/.claude/knowledge/architecture/skill-design-conventions.md @@ -0,0 +1,72 @@ +--- +title: "Skill Design Conventions & Context Economy" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "branch: task/dogfood-knowledge-system" +updatedFrom: "PR #8" +pluginVersion: 1.8.0 +prime: true +--- + +# Skill Design Conventions & Context Economy + +The governing design principle across every plugin in this marketplace: +**anything that lands in always-loaded session context is paid for in every +session, not just the one that uses the feature.** Always-loaded surfaces are +skill `description` frontmatter, auto-loaded rule files, `CLAUDE.md` content, +status-line output, and plugin metadata. Detail belongs in the file body the +model reads *on demand* when it invokes the skill — not in the activation +surface. + +## Why skill descriptions must stay short + +Each skill's `description` frontmatter is loaded into every session for +activation matching. It counts against `skillListingBudgetFraction` (default +1% of context). When the combined descriptions exceed that budget, Claude Code +**truncates** them — and a truncated description can stop matching its trigger +phrases, so the skill silently becomes harder to invoke. This is the concrete +failure mode that justifies the budget discipline; it is not a stylistic +preference. + +## The conventions + +The concrete rules — description length budget, the `Trigger:`-line structure, +English-only, no feature lists in the description — are stated as the +always-loaded source of truth in CLAUDE.md's "Skill descriptions: keep them +short" section. They are deliberately **not** restated here: a second copy in an +on-demand doc only drifts from the always-loaded one. This file captures the +*why* and the mechanism (above and below); CLAUDE.md is the checklist. + +## How to apply + +Before writing anything destined for an always-loaded surface, ask: does this +need to be always-on, or can it live in an on-demand body? Can the same meaning +be expressed in half the words? Is it already loaded somewhere else (avoid +duplication that drifts)? Err terse. The marketplace has lived this — see the +commit "Compact skill descriptions to fit listing budget." + +## Plugin-global vs per-project always-loaded surface + +A corollary of the cost principle: **a plugin should not ship always-loaded +rule files**. A rule bundled in the plugin (e.g. the former `auto-query.md` / +`auto-curate.md`) loads into *every* session of *every* project that has the +plugin installed — even projects that never use the feature. That is a tax the +non-user pays. + +The fix is to move that guidance into a **per-project file written by `/init`** +(`.claude/rules/knowledge-system-usage.md`): + +- It costs nothing for projects that haven't run `/init`. +- It is committed alongside the project, so it is team-shared and reviewable. +- A single per-project surface also resolves contradictions — two competing + plugin-global rules (inline-vs-`/query`) collapse into one authored file. + +The trade-off this creates is **staleness**: a committed project file can fall +behind the plugin's current guidance. Solved with a **template-version marker** +(`knowledge-system-usage template-vN`) carried in the file. The number is bumped +only when the template content changes (independent of plugin version), and +`/reindex` compares each project copy's marker against the plugin's current +number to flag drift — surfacing staleness without ever auto-mutating a +committed project file. + +Related: [[skill-composition]], [[model-economics]], [[ci-structure-checks]]. diff --git a/.claude/knowledge/deployment/ci-structure-checks.md b/.claude/knowledge/deployment/ci-structure-checks.md new file mode 100644 index 0000000..f330f6a --- /dev/null +++ b/.claude/knowledge/deployment/ci-structure-checks.md @@ -0,0 +1,43 @@ +--- +title: "CI Structure Checks" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "PR #6" +updatedFrom: "PR #6" +pluginVersion: 1.8.0 +prime: false +--- + +# CI Structure Checks + +This repo is declarative Markdown + JSON with **no build step**, so there is no +compiler to catch structural regressions — they stay invisible until live use. +`scripts/check-structure.py` is the **single automated guard**, run identically +in CI (`.github/workflows/structure-checks.yml`) and locally before pushing. + +## What it verifies + +The script groups its checks into four functions: + +1. **JSON validity + version sync** — every `plugin.json` / `marketplace.json` + parses, and each plugin's version matches between the two. Version drift is a + hard error, so it acts as a merge gate (the two-file version rule itself is + documented in CLAUDE.md's "Versioning" section). +2. **SKILL.md frontmatter** — required fields present, and the `description` + word budget (thresholds live in the script's `DESC_WORDS_*` constants). + Enforced mechanically because an over-budget description gets silently + truncated in sessions and can stop matching its triggers (see + [[skill-design-conventions]]). +3. **Internal `${CLAUDE_PLUGIN_ROOT}` references** — paths referenced in skills + actually exist, catching dangling cross-references. +4. **Shell script syntax** — bundled `.sh` files parse. + +## Why it exists + +The architecture review named "zero verification" the system's single biggest +risk: for a system whose "code" is prose, CI is the only substitute for a +compiler. This check closes the most common failure class (broken JSON, version +drift, dangling refs, budget violations) cheaply and mechanically. Keep it green; +it runs on every PR and push to main. + +Related: [[skill-design-conventions]]. diff --git a/.claude/knowledge/features/backfill-and-origin-metadata.md b/.claude/knowledge/features/backfill-and-origin-metadata.md new file mode 100644 index 0000000..4dda514 --- /dev/null +++ b/.claude/knowledge/features/backfill-and-origin-metadata.md @@ -0,0 +1,56 @@ +--- +title: "Backfill from History & Origin Metadata" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "PR #2" +updatedFrom: "PR #2" +pluginVersion: 1.8.0 +prime: false +--- + +# Backfill from History & Origin Metadata + +Two related knowledge-system capabilities for retroactively populating a +knowledge base and tracking where each entry came from. + +## `/backfill-knowledge` — mine merged PRs + +Bootstraps (or extends) a knowledge base from merged-PR history. Shape: + +- A **background Sonnet agent** fetches each PR's metadata, commits, and diff + and judges it against a **strict significance bar** — only new user-facing + features, architecture changes, or durable major insights pass. Bug fixes, + refactors, tests, deps-bumps, chores are rejected. Target acceptance is + ~10–20%; a bloated base is worse than a small one. +- The agent **never writes files** — it returns a candidate report. The user + approves a selection, then `/curate` runs per pick with `--origin "PR #"`. +- **Idempotency** comes from two sources unioned together: PR numbers already + anchored in `createdFrom`/`updatedFrom` frontmatter, plus a persistent log + (`.claude/logs/backfill-knowledge.md`). The log's "Skipped — not significant" + bucket is critical: without it, every run re-judges every rejected PR and + regenerates the same noise. + +## Origin metadata (`createdFrom` / `updatedFrom`) + +Knowledge files record their provenance so a later reader (or `/reindex`) knows +where the learning originated. The value is one of `"PR #"`, +`"branch: "`, or `"session: "`. + +The **reconstruction cascade** resolves a commit SHA to a PR. Its full, +authoritative definition lives in `/reindex` (step B) — that is the single +source; do not re-enumerate or reimplement it here. The shape: + +- **Primary (online):** `gh pr list --search --state merged`. GitHub knows + which PR a commit belongs to regardless of merge mode (merge, squash, + rebase-FF), so this covers virtually all online cases. +- **Offline fallbacks:** parse the commit subject — both the squash suffix + `(#)` and the classic merge-commit `Merge pull request #` form — and + the branch name, in the order `/reindex` defines. +- **Don't guess:** if nothing resolves unambiguously, the field is left **empty** + rather than filled with a guess. + +A `"branch: "` value is upgraded to `"PR #"` later by `/reindex` once +the branch merges — re-running the cascade on the same SHAs, never on the branch +name (the branch may be deleted post-merge). + +Related: [[skill-design-conventions]] (frontmatter as managed surface). diff --git a/.claude/knowledge/features/statusline-integration.md b/.claude/knowledge/features/statusline-integration.md new file mode 100644 index 0000000..65a86c3 --- /dev/null +++ b/.claude/knowledge/features/statusline-integration.md @@ -0,0 +1,51 @@ +--- +title: "Status-Line Integration" +createdAt: 2026-06-18 +updatedAt: 2026-06-19 +createdFrom: "PR #3" +updatedFrom: "PR #3" +pluginVersion: 1.8.0 +prime: false +--- + +# Status-Line Integration + +How the `/statusline` skill surfaces knowledge-system info (`[cks rules|knowledge]`) +in the Claude Code status line. + +## The design + +The status line is owned by the user's own `~/.claude/statusline.sh`. The +`/statusline` skill does **not** replace it — it requires an existing custom +status line and coexists with it: + +- **Marker-block injection**: the install step injects a delimited block into + the user's existing `~/.claude/statusline.sh` rather than overwriting it. + Re-running is idempotent (replace in place between markers); uninstall removes + the block. The same install step copies the renderer to + `~/.claude/cks-statusline.sh` (version-gated via a `CKS_STATUSLINE_VERSION` + line) and is atomic/restorable (session backup + post-write verify). +- **Standalone renderer**: the installed renderer at `~/.claude/cks-statusline.sh` + is independently usable — one arg (workspace dir), an ANSI-coloured block on + stdout, no trailing newline. A third-party status-line tool (ccstatusline, + CCometixLine, ccusage) can call it directly from its custom-command slot: + `bash "$HOME/.claude/cks-statusline.sh" "$DIR"`. (Its source lives in the + plugin at `scripts/statusline-cks.sh`.) +- **Per-project opt-out via sentinel**: a sentinel file disables the segment in + a given project, so opt-out is local and needs no global config mutation. + +## Where the logic lives + +All install/enable/disable/uninstall/status logic lives in one deterministic, +locally-testable script — `plugins/knowledge-system/scripts/statusline-install.sh` +— and the skill is a thin wrapper that parses the argument, runs the script, and +relays its output. The script is the source of truth; don't look in the SKILL.md +prose for the behavior. + +## Why this matters beyond statusline + +The "inject a marked block into a user-owned file you don't control" pattern +recurs — `/init` does the same to `CLAUDE.md`. Idempotent marker blocks are the +plugin's standard mechanism for editing files the user also edits. + +Related: [[skill-composition]] (shared-script single-source), [[ci-structure-checks]]. diff --git a/.claude/logs/backfill-knowledge.md b/.claude/logs/backfill-knowledge.md new file mode 100644 index 0000000..9fdf9c9 --- /dev/null +++ b/.claude/logs/backfill-knowledge.md @@ -0,0 +1,12 @@ +# Backfill Log + +## 2026-06-18 — knowledge-system v1.7.0 — range: --last 20 (11 merged PRs, #1–#12) + +Accepted (4): +- PR #2 → features/backfill-and-origin-metadata.md (new) +- PR #3 → features/statusline-integration.md (new) +- PR #6 → deployment/ci-structure-checks.md (new) +- PR #8 → architecture/skill-design-conventions.md (updated) + +Skipped — not significant (7): +- #1, #4, #5, #7, #9, #10, #12 diff --git a/.claude/rules/cwd-safety.md b/.claude/rules/cwd-safety.md new file mode 100644 index 0000000..c798968 --- /dev/null +++ b/.claude/rules/cwd-safety.md @@ -0,0 +1,23 @@ +--- +description: Never rely on persistent cwd in skills/scripts — use git -C, subshells, verify pwd +--- + +# CWD Safety in Skills & Scripts + +Skills run shell commands across multiple invocations, and the working +directory can drift — especially in worktree workflows where a skill operates +on the main repo and a worktree in the same run. Bugs distilled from +`work-system` (`kickoff`/`adopt`/`close`) gave these rules: + +- **Never `cd` persistently.** A bare `cd` changes state the next command + inherits, and a later command may assume a different directory. Working-dir + also does not reliably persist between separate tool calls. +- **Target the repo explicitly:** prefer `git -C ...` over `cd && + git ...`. +- **Scope directory changes to a subshell:** `( cd && ... )` so the + change cannot leak out. +- **Verify before acting:** when a command's correctness depends on location, + confirm with `pwd` / `git rev-parse --show-toplevel` rather than assuming. + +These are footgun-class bugs: they pass in the happy path and corrupt the wrong +repo in the edge case. Default to explicit-path commands. diff --git a/.claude/rules/knowledge-system-usage.md b/.claude/rules/knowledge-system-usage.md new file mode 100644 index 0000000..224fbb2 --- /dev/null +++ b/.claude/rules/knowledge-system-usage.md @@ -0,0 +1,45 @@ +--- +description: Knowledge system — when to consult/curate, index-load fallback, commands +--- + + + + +# Project Knowledge System + +## Auto-load fallback + +The knowledge index is injected via `@.claude/knowledge/_index.md` from +`CLAUDE.md` on session start. **If you do not see a "Knowledge Index" section +in your initial context, read `.claude/knowledge/_index.md` once with the Read +tool** before any `/query`. Once per session is enough — do not re-read. + +## Consult before diving in + +Check the index for relevant entries before exploring code when: starting in an +area untouched this conversation; the user asks "how does X work" (check +knowledge before grepping); a change affects how components interact; or you hit +unexpected behavior (look for a documented gotcha first). + +- **Index already names the file** → read it inline; no subagent for a known path. +- **Open-ended question** → `/query ""` — a cheap Haiku subagent + answers without pulling full files into context. + +Be selective — pull only the few relevant entries the index points to, never bulk-read the whole base. Skip for trivial or self-contained changes, or when you already have the context. + +## Curate at key moments + +Store a learning with `/curate "" [file...]` (it picks the right layer +and maintains frontmatter) when: about to push or open a PR (non-obvious +patterns, decisions, gotchas in the diff); after a surprising bug fix; the user +corrects your approach ("always do Y"); or you notice stale knowledge (fix it +promptly — wrong docs mislead a later `/query`). Capture the *why*, not volatile +values; skip trivia, secrets, and the obvious. + +## Other commands + +- `/prime [topic|--full]` — load foundational docs (architecture + overviews) + into context for real architectural work; beyond the always-loaded index. +- `/reindex` — thorough QA pass when indexes drift or cross-refs look stale. +- `/backfill-knowledge` — mine merged PR history for missing learnings (run + `/reindex` first so the idempotency check has up-to-date origin metadata). diff --git a/CLAUDE.md b/CLAUDE.md index e1fc345..2c055b5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,7 +68,13 @@ validity, version sync, SKILL.md frontmatter + description word budget, internal `${CLAUDE_PLUGIN_ROOT}` references, shell syntax). It runs in CI on every PR and push to main, and can be run locally before pushing. Keep it green. + ## Project Knowledge System -- **Rules** (`.claude/rules/`): Always active — coding style, patterns, dos/don'ts -- **Knowledge** (`.claude/knowledge/`): On demand — query with `/query` -- **Curate**: Use `/curate` to store new learnings after implementing features or fixing bugs + +The project's knowledge index is auto-loaded below. Query detailed +entries with `/query`, store new insights with `/curate`, run a QA pass +with `/reindex`. See `.claude/rules/knowledge-system-usage.md` for when +to use each and the full command list. + +@.claude/knowledge/_index.md +