diff --git a/.gitignore b/.gitignore index 2fc1391..93f1208 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ +# VDD working files LOOP.md .scratch/ +CLAUDE.md +CONTEXT.md +docs/agents/ diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 308aaa6..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,121 +0,0 @@ -# Maintaining this repository - -This repository is a Claude Code plugin and its single-plugin marketplace. -Everything committed here is cloned onto every machine that installs it, and -`hooks/hooks.json` registers commands that run on those machines on every -`Bash`, `Read`, `Grep` and `WebFetch` tool call. Treat every change under -`hooks/`, `bin/`, `skills/` and `config/` as code shipped to users with no -staged rollout. - -## Working in this repository - -`master` is protected by a ruleset with no bypass, so nothing lands by pushing -to it. Branch, push the branch, open a PR, merge it yourself. To merge, a PR -needs the `verify` check green and squash as its merge method; it needs no -approvals. - -Every commit must be signed. Local commits inherit `commit.gpgsign`. - -Repository policy requires every action to be pinned to a full commit SHA with -the version as a trailing comment. A tag reference does not fail review, it -fails the run. - -Dependabot owns action versions and bumps them in one grouped PR monthly. -Bumping a SHA by hand only creates a conflict with the next one. - -Any change to shipped content (`hooks/`, `bin/`, `skills/`, `config/`) bumps -`version` in both `.claude-plugin/plugin.json` and -`.claude-plugin/marketplace.json` in the same PR. Installed copies refresh by -version compare, so an unbumped fix never reaches existing users. - -## What `verify` enforces - -`verify.yml` is the only CI. It fails a PR when: - -- any of `plugin.json`, `marketplace.json`, `hooks/hooks.json`, - `config/deny-rules.json` does not parse -- a marketplace plugin `source` is anything but a local `./` path -- a `SKILL.md` lacks `name` or `description` frontmatter, or two skills share a - `name` -- a hook command does not start with `${CLAUDE_PLUGIN_ROOT}/`, contains `..`, - or points at a file that is missing or not executable -- a symlink is tracked, or an executable is tracked outside `hooks/*.sh` and - `bin/*.sh` -- an `.mcp.json` declares an unpinned `npx` package -- `bash -n` or `shellcheck -S warning` fails on `hooks/*.sh` or `bin/*.sh` - -Keep `hooks/*.sh` and `bin/*.sh` at mode `100755`; a hook that loses its -executable bit is silently never run by Claude Code, and CI catches it. - -## Invariants - -Preserve these through any refactor: - -- **Hook commands resolve inside the plugin.** Every command in - `hooks/hooks.json` is `${CLAUDE_PLUGIN_ROOT}/...`. Absolute paths break on - every other machine; relative paths without the variable resolve against the - user's cwd. -- **No network from any script.** `output-guard.sh` scans tool output that can - contain live secrets; it runs `betterleaks` without `--validation` because - validation posts findings to provider APIs. The audit script prints paths, - rule ids and counts only, never matched text. -- **Fail closed on scanner error, fail open only when betterleaks is absent.** - `output-guard.sh` withholds the whole output on any betterleaks failure or on - a rescan hit after redaction. The missing-binary case is the single - deliberate fail-open, and it prints a visible warning. -- **`verify.yml` triggers on `pull_request`.** It runs PR-head code, so - `pull_request_target` would hand fork PRs write access and secrets. It keeps - `permissions: contents: read`, `persist-credentials: false` and - `timeout-minutes` on the job. -- **Marketplace `source` stays `./`.** A remote source delegates trust to - another repository on every install. -- **Only shell entrypoints are executable.** Anything else with the executable - bit, and any symlink, is refused by CI because it is redistributed verbatim. - -If a workflow that opens PRs is ever added: pass the PR body via `body-path`, -never through `GITHUB_OUTPUT`, and set `sign-commits: true` on -`peter-evans/create-pull-request` under the default `GITHUB_TOKEN`. A PAT keeps -the PR working and drops the signature without warning; the ruleset then -rejects the merge. - -## Gotchas - -- `bin/auth-guard-doctor.sh` holds a synthetic `ghp_`-shaped token literal for - its self-test. When this plugin is active in the session doing the editing, - its own `output-guard` rewrites that line to `[REDACTED:github-pat]` in tool - output. The file on disk is intact; verify with a count - (`grep -cE 'ghp_[A-Za-z0-9]{36}' bin/auth-guard-doctor.sh` prints `1`) - rather than by reading the line, and keep the literal in place. -- Skills install flat by frontmatter `name` under `npx skills`, so a second - skill with the same `name` clobbers the first. Names here are `doctor`, - `audit-transcripts`, `global-settings`; keep new ones unique and specific. -- `plugin.json` declares no `hooks` field; Claude Code auto-discovers - `hooks/hooks.json`. Moving or renaming that file disables both hooks. -- `bin/auth-guard-apply-settings.sh` is the only script that writes anything - durable outside the plugin directory (`~/.claude/settings.json`, with a - timestamped backup, and it sets `sandbox.enabled` to `true`). Its skill gates - it behind a dry run and explicit user confirmation; keep that flow. The one - benign exception is `bin/auth-guard-doctor.sh`, whose custom-checks self-test - writes a synthetic checks file to `$TMPDIR` and removes it again under a - `trap`; keep that file transient and keep the trap. -- Every script prepends `/opt/homebrew/bin:/usr/local/bin:$HOME/go/bin:$HOME/.local/bin` - to `PATH` because GUI-launched Claude Code inherits launchd's minimal PATH and - `jq` and `betterleaks` vanish. Keep the prepend when adding scripts. -- The `Read(**/...)` deny rules in `config/deny-rules.json` bind only inside - the project directory. Home-directory credential files are covered by the - `sandbox.credentials.files` entries in the same file, which is why both lists - exist. - -## Agent skills - -### Issue tracker - -Issues live as local markdown files under `.scratch//`. See `docs/agents/issue-tracker.md`. - -### Triage labels - -The five canonical triage labels are used as-is. See `docs/agents/triage-labels.md`. - -### Domain docs - -Single-context: one `CONTEXT.md` plus `docs/adr/` at the repo root. See `docs/agents/domain.md`. diff --git a/CONTEXT.md b/CONTEXT.md deleted file mode 100644 index b304b6f..0000000 --- a/CONTEXT.md +++ /dev/null @@ -1,29 +0,0 @@ -# Auth-Guard - -A Claude Code plugin that keeps credentials out of tool calls and transcripts: a PreToolUse guard blocks commands that would print secrets, a PostToolUse guard redacts secrets that slip through. - -## Language - -**Built-in check**: -A credential-leak pattern shipped in `secret-guard.sh` itself, curated by this repository. -_Avoid_: default rule, stock check - -**Custom check**: -A user-authored credential-leak pattern loaded from the user's custom-checks file and evaluated by the PreToolUse guard alongside the built-in checks. -_Avoid_: user rule, custom rule - -**Match mode**: -Which form of the command a check's regex runs against: `verb` matches the quote-stripped command (high confidence the named program is actually invoked), `any` matches the full normalized command including quoted segments. -_Avoid_: match type, target - -**Decision**: -The permission outcome a matching check produces: `deny` blocks the tool call, `ask` routes it to the user for confirmation. -_Avoid_: action, verdict, severity (severity orders decisions; the decision itself is deny or ask) - -**Check id**: -The short stable identifier of a built-in check (e.g. `gh-auth-token`), named in diagnostic output and in the override notice. -_Avoid_: rule id, check name (a name belongs to a custom check; an id to a built-in) - -**Override notice**: -The note appended to a decision when a custom deny preempts a built-in ask that would also have matched, naming the custom check and the shadowed built-in id. -_Avoid_: shadow warning, precedence message diff --git a/docs/agents/domain.md b/docs/agents/domain.md deleted file mode 100644 index 3524904..0000000 --- a/docs/agents/domain.md +++ /dev/null @@ -1,51 +0,0 @@ -# Domain Docs - -How the engineering skills should consume this repo's domain documentation when exploring the codebase. - -## Before exploring, read these - -- **`CONTEXT.md`** at the repo root, or -- **`CONTEXT-MAP.md`** at the repo root if it exists: it points at one `CONTEXT.md` per context. Read each one relevant to the topic. -- **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. - -If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. - -## File structure - -Single-context repo (most repos): - -``` -/ -├── CONTEXT.md -├── docs/adr/ -│ ├── 0001-event-sourced-orders.md -│ └── 0002-postgres-for-write-model.md -└── src/ -``` - -Multi-context repo (presence of `CONTEXT-MAP.md` at the root): - -``` -/ -├── CONTEXT-MAP.md -├── docs/adr/ ← system-wide decisions -└── src/ - ├── ordering/ - │ ├── CONTEXT.md - │ └── docs/adr/ ← context-specific decisions - └── billing/ - ├── CONTEXT.md - └── docs/adr/ -``` - -## Use the glossary's vocabulary - -When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. - -If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`). - -## Flag ADR conflicts - -If your output contradicts an existing ADR, surface it explicitly rather than silently overriding: - -> _Contradicts ADR-0007 (event-sourced orders), but worth reopening because…_ diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md deleted file mode 100644 index 0209a19..0000000 --- a/docs/agents/issue-tracker.md +++ /dev/null @@ -1,30 +0,0 @@ -# Issue tracker: Local Markdown - -Issues and specs for this repo live as markdown files in `.scratch/`. - -## Conventions - -- One feature per directory: `.scratch//` -- The spec is `.scratch//spec.md` -- Implementation issues are one file per ticket at `.scratch//issues/-.md`, numbered from `01`, never a single combined tickets file -- Triage state is recorded as a `Status:` line near the top of each issue file (see `triage-labels.md` for the role strings) -- Comments and conversation history append to the bottom of the file under a `## Comments` heading - -## When a skill says "publish to the issue tracker" - -Create a new file under `.scratch//` (creating the directory if needed). - -## When a skill says "fetch the relevant ticket" - -Read the file at the referenced path. The user will normally pass the path or the issue number directly. - -## Wayfinding operations - -Used by `/wayfinder`. The **map** is a file with one **child** file per ticket. - -- **Map**: `.scratch//map.md` (the Notes / Decisions-so-far / Fog body). -- **Child ticket**: `.scratch//issues/NN-.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`. -- **Blocking**: a `Blocked by: NN, NN` line near the top. A ticket is unblocked when every file it lists is `resolved`. -- **Frontier**: scan `.scratch//issues/` for files that are open, unblocked, and unclaimed; first by number wins. -- **Claim**: set `Status: claimed` and save before any work. -- **Resolve**: append the answer under an `## Answer` heading, set `Status: resolved`, then append a context pointer (gist + link) to the map's Decisions-so-far in `map.md`. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md deleted file mode 100644 index b716855..0000000 --- a/docs/agents/triage-labels.md +++ /dev/null @@ -1,15 +0,0 @@ -# Triage Labels - -The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. - -| Label in mattpocock/skills | Label in our tracker | Meaning | -| -------------------------- | -------------------- | ---------------------------------------- | -| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue | -| `needs-info` | `needs-info` | Waiting on reporter for more information | -| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent | -| `ready-for-human` | `ready-for-human` | Requires human implementation | -| `wontfix` | `wontfix` | Will not be actioned | - -When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. - -Edit the right-hand column to match whatever vocabulary you actually use.