diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8ef84fb..9ef8462 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,6 +1,6 @@ { "name": "agent-context-kit", - "description": "Self-hosted marketplace for the agent-context-kit plugin (directives, how-tos, scripts Agent Skills).", + "description": "Self-hosted marketplace for the agent-context-kit plugin (directives, how-tos, scripts, context-refactor Agent Skills).", "owner": { "name": "Stefano Falasca", "email": "stefano.falasca@gmail.com" @@ -9,7 +9,7 @@ { "name": "agent-context-kit", "source": "./", - "description": "Three Agent Skills (directives, how-tos, scripts) that give a coding agent persistent, discoverable context about a codebase, instead of re-deriving it every session.", + "description": "Four Agent Skills (directives, how-tos, scripts, context-refactor) that give a coding agent persistent, discoverable context about a codebase, instead of re-deriving it every session.", "version": "1.0.0", "license": "MIT" } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 0611b0c..fa77953 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agent-context-kit", - "description": "Three Agent Skills (directives, how-tos, scripts) that give a coding agent persistent, discoverable context about a codebase, instead of re-deriving it every session.", + "description": "Four Agent Skills (directives, how-tos, scripts, context-refactor) that give a coding agent persistent, discoverable context about a codebase, instead of re-deriving it every session.", "version": "1.0.0", "author": { "name": "Stefano Falasca", diff --git a/README.md b/README.md index ee7f07a..1004c57 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [Project page](https://falasca.engineering/agent-context-kit/) -Three [Agent Skills](https://agentskills.io/specification) that give a coding agent persistent, +Four [Agent Skills](https://agentskills.io/specification) that give a coding agent persistent, discoverable context about a codebase, instead of re-deriving it every session. `SKILL.md` is an open format — these work with any agent that supports it (Claude Code, Codex, Cursor, OpenCode, and many more; see [the `npx skills` supported-agents list](https://github.com/vercel-labs/skills#supported-agents)), @@ -19,22 +19,30 @@ not just one vendor's product: - **`scripts`** — discovery for a project's `scripts/` folders, using each script's own `--help` output as the source of truth (not a comment header that can drift). Lets an agent find and run existing automation instead of reinventing it inline. - -The three compose: a `how-to` step that's automatable should point at a `script` instead of +- **`context-refactor`** — a cross-cutting audit across all three systems above, for the judgment + calls none of them can make alone: a section embedded in the wrong kind of doc, a directive with + no backing enforcement script, a doc or script at the wrong level of the directory tree, or + near-duplicate scripts worth generalizing into one. Invoked directly when planning a refactor, + not proactively gated like the other three — see its `SKILL.md` for the interactive, + one-change-at-a-time flow. + +The first three compose: a `how-to` step that's automatable should point at a `script` instead of inlining a command; a `directive` about git conventions governs how both `add` and `maintain` -modes commit their own changes. Each skill also ships small discovery/description scripts +modes commit their own changes. Each ships small discovery/description scripts (`discover_*.py`, `describe_*.py`) that do cheap metadata extraction — frontmatter for docs, `--help` output for scripts — so the agent doesn't have to read every file's full body just to -figure out what's relevant to the current task. +figure out what's relevant to the current task. `context-refactor` sits on top, calling those same +discovery scripts by relative path rather than duplicating them. ## Why this exists Most of what makes an AI coding agent effective on a real, non-trivial codebase isn't the model — it's whether the codebase is *legible* to the agent: are conventions written down somewhere the agent will actually look, are operational procedures documented instead of tribal knowledge, is -existing automation discoverable instead of getting silently reimplemented every session. These -three skills are the minimum mechanism to make that true, ported out of a personal -multi-project workspace where they get exercised daily. +existing automation discoverable instead of getting silently reimplemented every session, and +whether that whole system stays coherent as the codebase grows (right doc in the right place, +duplication caught before it drifts). These four skills are the minimum mechanism to make that +true, ported out of a personal multi-project workspace where they get exercised daily. ## Requirements @@ -67,20 +75,22 @@ to any community-marketplace listing: /plugin install agent-context-kit@agent-context-kit ``` -**Namespacing caveat**: a plugin install bundles all three skills under this repo's plugin name. +**Namespacing caveat**: a plugin install bundles all four skills under this repo's plugin name. Skills installed this way are invoked as `/agent-context-kit:directives`, -`/agent-context-kit:how-tos`, and `/agent-context-kit:scripts` — not the bare `/directives`, -`/how-tos`, `/scripts` names used by the `npx skills add` and manual-clone routes above. Pick one -install route per agent setup; don't mix bare and namespaced expectations. +`/agent-context-kit:how-tos`, `/agent-context-kit:scripts`, and `/agent-context-kit:context-refactor` +— not the bare `/directives`, `/how-tos`, `/scripts`, `/context-refactor` names used by the +`npx skills add` and manual-clone routes above. Pick one install route per agent setup; don't mix +bare and namespaced expectations. ## Use in a project -Each skill's `SKILL.md` documents an `AGENTS.md` instruction block under a "## AGENTS.md -instruction" heading — copy it into the project's `AGENTS.md` (create the file if it doesn't -exist yet) so the agent proactively calls `context` mode before relevant work, instead of only -using the skill when explicitly asked. `AGENTS.md` is the canonical file, not `CLAUDE.md`; if the -project's agent is Claude Code, give its `CLAUDE.md` a single `@AGENTS.md` import line instead of -duplicating the block. +`directives`, `how-tos`, and `scripts` each document an `AGENTS.md` instruction block under a "## +AGENTS.md instruction" heading — copy it into the project's `AGENTS.md` (create the file if it +doesn't exist yet) so the agent proactively calls `context` mode before relevant work, instead of +only using the skill when explicitly asked. `AGENTS.md` is the canonical file, not `CLAUDE.md`; if +the project's agent is Claude Code, give its `CLAUDE.md` a single `@AGENTS.md` import line instead +of duplicating the block. `context-refactor` has no such block — it's an audit you invoke directly +when planning a refactor, not something that should fire on every task. From there, each skill is invoked by name inside an agent session — for example, as a slash command in Claude Code (bare name if installed via `npx skills add`/manual clone, namespaced @@ -90,6 +100,7 @@ command in Claude Code (bare name if installed via `npx skills add`/manual clone /directives context "add a new API endpoint" /how-tos context "cut a release" /scripts context "generate a report" +/context-refactor ``` or in `add`/`update`/`maintain`/`suggest` modes to create or audit docs and scripts — see each @@ -114,7 +125,8 @@ This repo's own conventions (OS independence, Agent Skills spec compliance, inst in [`docs/`](docs/) — read them before changing anything under `skills/`. Operational procedures for working on this repo itself (running the test suite, installing these skills for local testing) live in [`how-tos/`](how-tos/) — this repo dogfoods its own `directives`/`how-tos`/ -`scripts` skills on itself; its `AGENTS.md` carries all three skills' instruction blocks, and its +`scripts` skills on itself; its `AGENTS.md` carries all three skills' instruction blocks (not +`context-refactor`'s, per the note above), and its `CLAUDE.md` just imports it (`@AGENTS.md`). Tests for every script in this repo live in [`tests/`](tests/); the shipped skills themselves need only Python 3.9+ and Git, but running the test suite also needs `pyyaml` (frontmatter validation) on the host, or diff --git a/docs/install-conventions.md b/docs/install-conventions.md index 4744e02..a275aba 100644 --- a/docs/install-conventions.md +++ b/docs/install-conventions.md @@ -26,7 +26,7 @@ have needed to grow: A second route exists for Claude Code specifically: this repo self-hosts a Claude Code plugin marketplace (`.claude-plugin/marketplace.json`, `.claude-plugin/plugin.json`). Installing via -`/plugin install agent-context-kit@agent-context-kit` namespaces all three skills under the +`/plugin install agent-context-kit@agent-context-kit` namespaces all four skills under the plugin name (`/agent-context-kit:directives`, etc.) instead of the bare names `npx skills add` installs under — see [`how-tos/install-skills.md`](../how-tos/install-skills.md). There is no repo-maintained installer script; both routes are third-party (`npx skills`) or Claude diff --git a/how-tos/install-skills.md b/how-tos/install-skills.md index cb4c777..84cd21d 100644 --- a/how-tos/install-skills.md +++ b/how-tos/install-skills.md @@ -1,5 +1,5 @@ --- -description: Install this repo's skills (directives, how-tos, scripts) into an agent, at user or project scope +description: Install this repo's skills (directives, how-tos, scripts, context-refactor) into an agent, at user or project scope scope: root covers: [install, npx, skills, claude-code, plugin, marketplace, user-level, project-level, setup] --- @@ -38,20 +38,21 @@ This repo also self-hosts a Claude Code plugin marketplace at ``` Skills installed this way are namespaced under the plugin name — invoked as -`/agent-context-kit:directives`, `/agent-context-kit:how-tos`, `/agent-context-kit:scripts`, not -the bare `/directives`/`/how-tos`/`/scripts` names the step 1 route uses. Pick one install route -per agent setup. +`/agent-context-kit:directives`, `/agent-context-kit:how-tos`, `/agent-context-kit:scripts`, +`/agent-context-kit:context-refactor`, not the bare `/directives`/`/how-tos`/`/scripts`/ +`/context-refactor` names the step 1 route uses. Pick one install route per agent setup. ## 3. After installing: wire the `AGENTS.md` reminder blocks Installing the skills makes them available; it doesn't make an agent proactively call `context` -mode before relevant work. Each of `directives`/`how-tos` documents an instruction block under a -"## AGENTS.md instruction" heading in its own `SKILL.md` — copy that block into the project's -`AGENTS.md` (create the file if it doesn't exist yet). `AGENTS.md` is the canonical file, not -`CLAUDE.md`. If Claude Code is one of the agents in play, also give the project's `CLAUDE.md` a -single `@AGENTS.md` import line (Claude Code resolves that as an include) rather than duplicating -the block — other agents that support the emerging `AGENTS.md` cross-tool convention read it -directly, no import needed. +mode before relevant work. Each of `directives`/`how-tos`/`scripts` documents an instruction block +under a "## AGENTS.md instruction" heading in its own `SKILL.md` — copy that block into the +project's `AGENTS.md` (create the file if it doesn't exist yet). `AGENTS.md` is the canonical +file, not `CLAUDE.md`. If Claude Code is one of the agents in play, also give the project's +`CLAUDE.md` a single `@AGENTS.md` import line (Claude Code resolves that as an include) rather +than duplicating the block — other agents that support the emerging `AGENTS.md` cross-tool +convention read it directly, no import needed. `context-refactor` has no such block — it's invoked +directly when planning a refactor, not gated before every task. ## 4. Verify the install diff --git a/skills/context-refactor/SKILL.md b/skills/context-refactor/SKILL.md new file mode 100644 index 0000000..53c81f3 --- /dev/null +++ b/skills/context-refactor/SKILL.md @@ -0,0 +1,183 @@ +--- +name: context-refactor +description: "Review and guide refactors across a project's directives, how-tos, and scripts systems, catching cross-cutting problems no single one of those skills can see on its own: a section embedded in the wrong kind of doc, a directive with no backing enforcement script, a doc or script living at the wrong level of the directory tree, or near-duplicate scripts that are candidates for hoisting into one parametric script. Presents findings as a numbered, impact-ordered menu and walks through them one guided change at a time. Use when the user wants a cross-system audit or wants to plan a refactor that spans docs/ how-tos/ and scripts/ folders." +compatibility: "Requires Python 3.9+ and git, and the directives/how-tos/scripts skills installed alongside it in the same skills/ root (it calls their discover_*.py/describe_*.py scripts directly by relative path). Slash-command dispatch (/context-refactor ...) and cross-skill invocation via the Skill tool are Claude Code conventions; other agents can still follow these instructions and run the referenced scripts directly." +allowed-tools: Read Edit Write Glob Grep Bash Skill Agent +metadata: + claude-code-argument-hint: "[path] [directives,how-tos,scripts]" + claude-code-context: inline +--- + +You audit a project's `directives`, `how-tos`, and `scripts` systems together and guide the user +through fixing what you find, one change at a time. This is not a fourth `maintain` mode bolted +onto one of the other three skills — it is a separate, cross-cutting pass that only makes sense +with visibility into all three systems plus the directory hierarchy at once. + +## How this differs from the other three skills' `maintain` modes + +Each of `directives`, `how-tos`, and `scripts` already audits its own domain: frontmatter +completeness, staleness, broken `--help`, un-deferred automation. Those checks are single-domain +and largely mechanical — they don't require deciding whether something belongs in a *different* +system, or at a *different level* of the tree. This skill reuses those checks (by calling the same +discovery scripts) but adds four categories none of the three own individually. It never +duplicates a check the others already make — where one applies (e.g. `how-tos`' "un-deferred +automation" check), call that skill's `maintain` mode instead of reimplementing it. + +Every finding here is a judgment call, not a lint violation. Never batch-apply. Always walk +findings one at a time, with the user picking which change to make and how, before anything is +written. + +## Starting every invocation + +Run each sibling skill's discovery script (paths are relative to this file, per +[[os-independence]]): + +```bash +python3 ../directives/scripts/discover_docs.py +python3 ../how-tos/scripts/discover_docs.py +python3 ../scripts/scripts/discover_scripts.py +``` + +## Scope + +Optional arguments: a path to restrict the audit to (default: repo root) and a comma-separated +list of systems to include (default: all three — `directives,how-tos,scripts`). Filter the +discovery output to paths under the requested scope path before proceeding. + +## Phase 1 — Full-content inventory + +Unlike `directives`/`how-tos`' `context`/`maintain` modes (frontmatter only) or `scripts`' +(`--help` only), the checks below are section-level and require the actual body text. Read every +matched directive and how-to doc **in full**. For scripts, run `describe_scripts.py` for `--help` +output, and additionally read the source of any script that looks like a plausible duplicate of +another (Category 4 below) — `--help` text alone won't reveal that. + +## Phase 2 — Cross-cutting analysis + +Build a findings list. Each finding has: + +- **category**: `type-misclassification | enforcement-gap | placement | duplication` +- **scope**: `section | whole-file` +- **file**, and for section-scoped findings, the **heading text** and approximate line range +- **severity**: `high | medium | low` — used for impact ordering, not as a gate +- **summary**: one line +- **detail**: what was found and why it matters +- **options**: one or more concrete proposed actions (see below) — never just one forced answer + for Category 4 + +### Category 1 — Type misclassification + +Applies **at the section level**, not just to a whole doc — a directive can be broadly correct as +a directive and still contain one embedded section that's actually a procedure, or vice versa. + +- A directive (`docs/`) containing a numbered, ordered sequence of concrete steps (a procedure) → + that section belongs in a how-to, with a short reference left behind in the directive + ("see `how-tos/x.md` for steps"). +- A how-to (`how-tos/`) containing a standing rule with no ordered steps (a convention) → that + section belongs in a directive, with a reference left behind if the how-to still needs to invoke + it. +- A directive or how-to step that is fully mechanical and not yet pointed at a script — this + overlaps `how-tos`' own "un-deferred automation" check; when found in a how-to, prefer flagging + it there (or just running `how-tos maintain`) rather than duplicating the finding here. Only + raise it here when it's found in a **directive** (which has no `scripts`-deferral convention of + its own) or spans multiple docs. + +Whole-file misclassification (a whole doc filed in the wrong folder) is the same category but +`scope: whole-file` — simpler to detect and to fix. + +### Category 2 — Enforcement gaps + +A directive states a rule that is mechanically checkable (a naming convention, a required file, a +frontmatter shape) but no script in the project actually checks it. Flag it with a proposed script +sketch as the option — this is a proposal, not an assumption that enforcement is always wanted; +some rules are deliberately left to human review. + +### Category 3 — Placement / hierarchy level + +A doc or script lives higher or lower in the tree than where it's actually useful: + +- Something scoped to one subproject sitting at the repo root (too high — only relevant readers + have to see it in every unrelated discovery run). +- Something with cross-cutting relevance duplicated or buried inside a single subproject's + `docs/`/`how-tos/`/`scripts/` (too low — other subprojects that need it won't find it). + +The fix is a `git mv` plus fixing any relative-path references to the moved file (other docs' +`[[links]]`, a how-to's script-path reference, this skill's own sibling-script paths if it were +ever the one moved). + +### Category 4 — Duplication candidate for generalization + +Two or more scripts (or doc procedures) in sibling subprojects do near-identical things with minor +variation. This is explicitly a balance between simplicity/readability and avoiding drift — do not +pick a winner automatically. Always present the three options from the "placement" framing and let +the user choose: + +1. **Leave duplicated** — the variation is enough that one parametric version would be harder to + read than two clear ones. +2. **Add the missing one** — subproject B gets its own copy/adaptation of subproject A's + script/doc; no consolidation. +3. **Generalize and hoist** — make the logic parametric, move it to the lowest common ancestor + `scripts/`/`docs/`/`how-tos/` folder, and point both subprojects at it (via `scripts` skill + discovery, or a directive/how-to reference). + +## Phase 3 — Present findings menu + +Sort by severity/impact (high first) within each category, then present: + +``` +Found N findings: + +TYPE MISCLASSIFICATION + 1. [high] (docs/foo.md, section "## Deploying") + 2. [low] (how-tos/bar.md, whole file) + +ENFORCEMENT GAPS + 3. [medium] + +PLACEMENT + 4. [medium] + +DUPLICATION + 5. [high] (investments/scripts/fetch.py vs ledger/scripts/fetch.py) + +Which do you want to work on? Say a number, ask anything directly, or 'done'. +``` + +Omit empty categories. If there are no findings, say so and stop. + +## Phase 4 — Guided single-change loop + +For the finding the user picks: + +1. **Explain** — what was found, why it matters, quoting the relevant section or `--help`/source + excerpt. +2. **Propose** — the concrete action(s). For a section extraction, show the exact text block that + would move and the exact reference line that would stay behind. For Category 4, present all + three options and ask which one; don't assume "generalize" is always right. +3. **Confirm**, then **apply** — mostly inline, in this turn: + - **Section extraction**: `Skill(skill: "how-tos", args: 'add ""')` or + `Skill(skill: "directives", args: 'add ""')` seeded with the extracted content, + then `Edit` the source doc to replace the section with a reference line. + - **Whole-file reclassification**: `git mv` (never a plain filesystem move — this repo tracks + history), then the matching `Skill(... update ...)` call to fix frontmatter/format for the + new home. + - **Enforcement gap**: `Skill(skill: "scripts", args: 'add ""')`, then + `Skill(skill: "directives", args: 'update ""')` to add the reference to it. + - **Placement**: `git mv`, then `Grep` for and fix references to the old path. + - **Duplication → generalize**: parametrize the chosen script in place, `git mv` it to the + common ancestor's `scripts/` folder, then either `git rm` the sibling copy and update its + callers, or leave a thin wrapper if callers can't be updated in the same pass — say which you + did. + - Reserve `Agent(run_in_background: true)` for the rare case where the mechanical execution + spans many files (more than a handful of reference fixes) — offer it as an option for that + finding specifically, don't default to it. + - Follow the project's git conventions doc for branch/commit naming if one exists (check via + `describe_docs.py` for a doc with `git` in `covers`); otherwise use the same defaults as the + `directives` skill's "Large refactors" section. +4. **Re-render remaining findings** with that one removed, same format as Phase 3. If empty, move + to Phase 5. + +## Phase 5 — Summary + +One or two sentences: how many findings were found, how many were applied, how many were left for +later, and whether any generalization decisions are worth revisiting once more subprojects exist. diff --git a/skills/directives/SKILL.md b/skills/directives/SKILL.md index db1f7da..57e3f9f 100644 --- a/skills/directives/SKILL.md +++ b/skills/directives/SKILL.md @@ -42,6 +42,11 @@ deliberately-authored source. Don't silently follow the bundled default if a pro it; flag the contradiction (see `maintain` below) so one of them gets fixed or the project doc explicitly notes it supersedes the default. +A directive with an embedded section of ordered steps (that section belongs in a how-to instead), +a directive with no backing enforcement script, or a directive at the wrong level of the directory +tree are cross-cutting judgment calls spanning `how-tos`/`scripts`/the directory hierarchy — see +`context-refactor` rather than trying to fix them from inside `maintain` here. + ## Directive doc frontmatter Every directive doc must have YAML frontmatter with exactly these fields: diff --git a/skills/how-tos/SKILL.md b/skills/how-tos/SKILL.md index f74f5c6..388fdd9 100644 --- a/skills/how-tos/SKILL.md +++ b/skills/how-tos/SKILL.md @@ -29,6 +29,10 @@ frontmatter-only describe pass) applied to `how-tos/` instead of `docs/`. Unlike ships **no bundled defaults** — operational procedures are inherently project-specific, so there is nothing generic to fall back to. +A section embedded in the wrong kind of doc (a directive with steps that belong here, or a how-to +step that states a standing rule) is a cross-cutting concern spanning both skills — see +`context-refactor` rather than trying to fix it from inside `maintain` here. + All scripts this skill uses (`scripts/discover_docs.py`, `scripts/describe_docs.py`) are plain Python 3 (no bash/WSL required — this works the same on Linux, macOS, and Windows) and live in this skill's own `scripts/` directory, next to this `SKILL.md` file. Run them with diff --git a/skills/scripts/SKILL.md b/skills/scripts/SKILL.md index 72f4ca5..d4d4962 100644 --- a/skills/scripts/SKILL.md +++ b/skills/scripts/SKILL.md @@ -38,6 +38,11 @@ A script whose `--help` errors, hangs, or prints nothing is a bug in that script ## Optional tags header +Deciding whether a script belongs at its current level of the directory tree, or whether it's a +near-duplicate of a sibling subproject's script worth generalizing and hoisting, is a cross-cutting +judgment call spanning the directory hierarchy — see `context-refactor` rather than trying to fix +it from inside `maintain` here. + A script may optionally carry a single header line for cheap keyword pre-filtering, without having to execute anything: diff --git a/tests/test_npx_skills_install.py b/tests/test_npx_skills_install.py index fca48c7..c140c6d 100644 --- a/tests/test_npx_skills_install.py +++ b/tests/test_npx_skills_install.py @@ -11,7 +11,7 @@ from util import REPO_ROOT, run -SKILL_NAMES = {"directives", "how-tos", "scripts"} +SKILL_NAMES = {"directives", "how-tos", "scripts", "context-refactor"} @unittest.skipUnless( @@ -20,7 +20,7 @@ "repo's test harness runs in. Run via `python3 scripts/dev test`.", ) class NpxSkillsAddTest(unittest.TestCase): - def test_lists_all_three_skills(self): + def test_lists_all_skills(self): result = run(["npx", "--yes", "skills@latest", "add", REPO_ROOT, "--list"], timeout=120) self.assertEqual(result.returncode, 0, result.stderr) for name in SKILL_NAMES: