A personal collection of Claude Code agents and skills, packaged as a marketplace of small, single-purpose plugins.
This is an opinionated set — it's the toolbox I actually use, grouped by what each tool is for rather than what it is. A few of these are honestly tuned to my own projects (Python/Django, an ADR + plan + exec workflow, a Context7 MCP), so they won't all drop cleanly into a different setup. I've flagged that per plugin below. Even where a tool doesn't fit you as-is, it might give you ideas for building your own.
Add the marketplace, then install the plugins you want:
/plugin marketplace add pySilver/cc-tools
/plugin install decide@silver-cc-tools
/plugin install git@silver-cc-tools
/plugin install research@silver-cc-tools
/plugin install basedpyright-lsp@silver-cc-tools
/plugin install pyrefly-lsp@silver-cc-tools
/plugin install tracking@silver-cc-tools
/plugin install huddle@silver-cc-tools
/plugin install output-styles@silver-cc-tools
Test a plugin locally before installing:
claude --plugin-dir plugins/decide
Validate the marketplace and a plugin:
claude plugin validate .
claude plugin validate ./plugins/decide
After install, components are namespaced by plugin: skills are invoked as /decide:interview-me, /git:finalize-feature-branch, /research:web-research. basedpyright-lsp and pyrefly-lsp have no command to invoke — each registers a language server that activates automatically when you open a .py/.pyi file. They claim the same extensions, so enable only one: with both on, the first server registered wins and the other never starts. output-styles has no command either — it adds Direct to the /config → Output style picker, where you select it.
Manual install (alternative)
Copy the files you want straight into your Claude Code config directory. Agents go under ~/.claude/agents/, skills under ~/.claude/skills/. Restart Claude Code afterward.
decide — interview-me + brief skills:
cp -r plugins/decide/skills/interview-me ~/.claude/skills/
cp -r plugins/decide/skills/brief ~/.claude/skills/git — finalize-feature-branch skill:
cp -r plugins/git/skills/finalize-feature-branch ~/.claude/skills/research — web-research skill:
cp -r plugins/research/skills/web-research ~/.claude/skills/huddle — there's nothing useful to copy: the skill calls bin/huddle, which only a plugin puts on PATH. Load it as a plugin directory instead (claude --plugin-dir plugins/huddle).
output-styles — the Direct output style:
cp plugins/output-styles/output-styles/direct.md ~/.claude/output-styles/basedpyright-lsp / pyrefly-lsp — there's nothing to copy: a language server isn't a skill or agent, so it can't be dropped into ~/.claude. Load one as a plugin directory instead:
claude --plugin-dir plugins/basedpyright-lsp
# or
claude --plugin-dir plugins/pyrefly-lspNote: installed manually, skills lose the plugin: namespace — invoke them by bare name (/interview-me, /web-research, etc.).
Plugin versions are intentionally omitted from the manifests, so every commit to this repo is a new version. The /plugin menu has two update paths:
/plugin→ Marketplaces → Update marketplace — pulls the latest catalog from the repo immediately. The reliable way to get updates./plugin→ Installed → Update now — uses a local cache that can lag. Use it as a fallback after updating the marketplace.
Enable /plugin → Marketplaces → Enable auto-update to refresh the catalog on each session start.
| Plugin | Description |
|---|---|
| decide | Pre-code design gates — intent interviews, risk triage, decision briefs |
| git | Finalize a feature branch — rebase, squash to one commit, verify, push |
| research | Grounded web research with source-quality discipline and inline citations |
| basedpyright-lsp | Python LSP (basedpyright) for Claude — navigation + diagnostics, from the project's pinned venv |
| pyrefly-lsp | Same, backed by pyrefly instead — pick whichever your type-check gate runs |
| tracking | Deferred-work backlog (docs/backlog/) — one slug-named file per item, git rm'd when fixed |
| huddle | Questions as a page in an agterm overlay — diagrams, trade-offs side by side, real code, sliders |
| agrev | Review a plan or other markdown document in plannotator, in an agterm session, round by round |
| peer-planning | Coarse-task plans, executed task by task with Codex reviewing each diff from the adjacent agterm pane |
| output-styles | Direct — peer-to-peer tone, plain English, choice-first, diagrams-first |
Two tools for the stretch before any code is written: one to find out what you actually want, and one to make the resulting fork readable.
| Component | Trigger | Description |
|---|---|---|
| skill | /decide:interview-me |
Extracts what you actually want — one question at a time, each carrying the agent's own guess, until it can predict your answers |
| skill | /decide:brief |
Rebuilds your context before you pick — one concrete failing run, why it became possible, the forks replayed against it, pointers last |
interview-me — the gate before anything gets drafted. What people ask for and what they want are different things: "build me a dashboard" is the conventional phrasing, not the problem, and the gap between the two is free to close now and expensive to close after code exists. The mechanism is one question at a time with the agent's own guess attached — you react to a wrong hypothesis far faster than you compose an answer from scratch, and attaching the guess is what forces the agent to commit to an assumption it can be visibly wrong about instead of quietly building on it. It opens with a one-sentence read of what you want and an honest confidence number, and every number under ~70% has to say what is still missing, so the score is a request for specific help rather than a mood. It listens for want vs. should want — "scalable", "clean architecture", "the standard approach" are answers that sound like a thoughtful answer instead of being one, and they get one probe: if you didn't have to justify this to anyone, what would you actually want? It closes with a six-line restate (Outcome / User / Why now / Success / Constraint / Out of scope) and an explicit yes — "whatever you think is best" is delegation, "sounds good" is ambiguous, and silence is not confirmation, so each of those re-asks instead of terminating. The stop condition is checkable rather than a vibe: can I predict your reaction to the next three questions I would ask? — with a floor, so several rounds of flat confidence ends the interview and reports that something foundational is missing rather than grinding on.
Produces intent, not a document. The deliverable is a confirmed statement of intent that an ADR, a brainstorm, or a planner then consumes; it deliberately writes no file by default and defers to the host project's documentation conventions if you want it persisted, rather than inventing a directory to hold it. Needs a live user — it declines to run in CI,
/loop, or an unattended plan executor and flags the underspecified ask as a blocker instead of guessing. Adapted from addyosmani/agent-skills (MIT); seeNOTICEfor what was kept and what changed.
brief — the format an agent should use when it hands a fork back to you. You wrote the design while fully focused; by the time an agent hits a judgement call three days later, the plan and the ADR are gone from your head, and a verdict built out of section names and internal terms asks you to reload a whole design from a pointer before you can read the question. This fixes the shape. First settle the problem — name the guard you reached for and what it leaves in place, run a root-cause or likelihood tool if one is available, and say plainly when the verdict is judgement rather than a checked result. Then five parts, in order: the story (one concrete run in time order, real values not variable names, ending badly, with one clause saying whether it was reproduced or derived — the two read identically and only one is evidence); the step back (2–5 lines: why this became possible, asking why until the answer is a decision someone made rather than a line of code, plus how far the same cause reaches — then landing on local, design, or unknown); the forks (two to four, cheapest first, each with its cost now and its cost if added later, each replaying the same story to its new ending, each labelled removes the cause or guards only); the recommendation (one option, one question, answerable in one word, plus an offer to expand any fork — offering to re-explain costs you nothing, a pointer asks you to go read); and the pointers last, one line, never inside the story.
The step back is what makes the menu safe to answer. A readable fork is still the wrong question when the fork itself is the artifact of an earlier bad split, and from inside a list of options you cannot tell which kind you are looking at — so the brief has to say it. When it lands on design, revising that decision is one of the forks, costed and replayed like the rest, and if it is genuinely off the table (shipped, needs a migration, the release is Friday) that line goes where the fork would have been rather than being omitted, which would let the menu imply it was never available. The "how far does it reach" clause is the other half: two options look equally reasonable until you know the same choice has four other exits nobody has hit yet. Both directions are errors — a step back that relabels the defect line as the cause tells you nothing, and one that manufactures a design flaw so the section has something to say is worse, so local ("the plan was right, this build diverged from it") is a one-line answer the format expects most of the time.
It deliberately does not fire for a failure the agent can fix itself, a yes/no on a step just described, work done in this session, or anything small and reversible — a five-part brief on a two-minute fork spends the attention the format exists to protect. Two send checks: could you pick an option without opening the plan, the ADR, or the code — and can you tell whether picking from this menu is patching over something? In Claude Code, the story, the step back, and the forks go in the message and the choice goes to AskUserQuestion, where each option description carries what we do + cost + removes or guards — an option description that is itself a pointer defeats the whole thing.
Pairs with the
Directoutput style (the output-styles plugin below). The style already says lead with the answer and skip trailing summaries; this skill is the documented exception — the story leads, and the closing question is the next action rather than a recap. Repo-agnostic; a root-cause or likelihood tool is used when one is present and skipped when not. It has eval coverage underplugins/decide/evals/— one case that it fires with the right shape, and two that it stays quiet, because the failure mode of this format is over-firing.
| Component | Trigger | Description |
|---|---|---|
| skill | /git:finalize-feature-branch [default-branch] |
Rebase onto the default branch, collapse to one commit, verify, merge into the default branch and push |
finalize-feature-branch — takes an approved feature branch to exactly one commit ahead of the default branch. It detects the default branch (or asks), previews what will change, fetches and rebases (resolving clean conflicts, aborting on unclear ones), collapses multiple commits via git reset --soft + commit (never interactive rebase), proposes a commit message derived from the branch name, verifies, then lands the branch. Each step confirms before acting. Repo-agnostic — plain git.
Two things it is opinionated about:
- Landing defaults to merge, not publish. The first offer is fast-forward the branch into the default branch locally and
git push origin <default>; publishing the feature branch with--force-with-leaseis the second option, for when a PR is wanted. The default branch is never force-pushed, and a rejected push stops the run rather than escalating. - From a worktree it lands on the remote instead. If another worktree holds the default branch, the local merge is impossible —
git checkoutandgit fetch . HEAD:<default>both refuse — so the first offer becomesgit push origin HEAD:<default>, the same fast-forward one hop earlier. It never rewrites the ref behind the other checkout's back, and afterwards it reports that worktree as behind, offering to fast-forward it only when it is clean. - The full test suite is skipped when the rebase pulled in nothing but documentation — and only then.
reset --softrewrites history, not the tree, so the only thing that can break a verified branch is incoming upstream work; the skill diffs the pre-fetch merge-base against the new default-branch tip to see exactly what that was. A resolved conflict, no passing suite earlier in the session, or a single unclassifiable file all force a full run..mdis not automatically documentation: files undertests/,requirements*.txt, doctested.rst, and repos that ship markdown as source are named as never-docs. Anything left unclassified prompts a question instead of a guess, and a skip is always reported with its reason.
| Component | Trigger | Description |
|---|---|---|
| skill | /research:web-research <question> |
Grounded web research with source-quality heuristics and inline citations |
web-research — answers questions from current, citable sources. It scopes the question, searches with precise terms (parallel queries for distinct angles), fetches primary sources with focused extraction, cross-checks claims that matter (versions, advisories, prices, breaking changes — one source is a lead, two is a fact), and cites sources inline. It prefers official docs, RFCs, and release notes over SEO aggregators and undated tutorials, and reports the answer rather than narrating the search.
Note: prefers a Context7 MCP for library/framework docs and
ghfor GitHub URLs when available, falling back to plain web search otherwise.
| Component | Trigger | Description |
|---|---|---|
| lsp | opening a .py/.pyi file |
Registers a basedpyright language server for Python |
basedpyright-lsp — gives Claude a Python language server (go-to-definition, find-references, hover, document/workspace symbols, call hierarchy, plus diagnostics) backed by basedpyright, the pyright fork. There's no command to run; the server starts when a Python file is opened.
Why this exists. Diagnostics are already covered twice over — by the editor's own LSP while a file is open, and by the git hook that runs basedpyright as the type-check gate at commit. What's missing is navigation for Claude in terminal-only sessions (no editor attached): jumping to a definition, finding references, walking a call hierarchy. That's this plugin's unique value. The catch is that diagnostics must not disagree with the gate, so the server is sourced from the same pinned basedpyright the gate uses rather than a global install that can drift to a different version.
It resolves the server binary in priority order, anchored to the project root (${CLAUDE_PROJECT_DIR}, falling back to cwd):
<root>/.venv/bin/basedpyright-langserver— the project's pinned basedpyright (matches the gate). Preferred.uv run --project <root> --no-sync basedpyright-langserver— when apyproject.tomlexists anduvis onPATH; resolves the project env without activating it and without an implicit sync.- a global
basedpyright-langserveronPATH— last resort (its version may differ from the project pin). - none found → exits non-zero with an install hint. It never auto-installs — adding basedpyright to the project's dev deps is your call, not the plugin's.
Replaces pyright-lsp@claude-plugins-official (which hardcodes pyright-langserver and looks it up on PATH only — it never finds a basedpyright that lives in a project venv). Disable any pyright/basedpyright LSP from another marketplace before enabling this one.
Tuned for my setup. Assumes a project venv at
.venv/and/or auv-managedpyproject.toml, and a basedpyright type-check gate to agree with. On a non-uv project with no.venv, only the global fallback applies — adjustbin/langserver.shfor other layouts (Poetry, conda, a differently-named venv).
| Component | Trigger | Description |
|---|---|---|
| lsp | opening a .py/.pyi file |
Registers a pyrefly language server for Python |
pyrefly-lsp — the same idea as basedpyright-lsp, backed by pyrefly (Meta's Rust-based Python type checker and language server) instead. Same discovery order, anchored to the project root (${CLAUDE_PROJECT_DIR}, falling back to cwd):
<root>/.venv/bin/pyrefly— the project's pinned pyrefly (matches the gate). Preferred.uv run --project <root> --no-sync pyrefly— when apyproject.tomlexists anduvis onPATH.- a global
pyreflyonPATH— last resort (its version may differ from the project pin). - none found → exits non-zero with an install hint. It never auto-installs.
Started as pyrefly lsp (pyrefly speaks stdio by default — no --stdio flag). Unlike the basedpyright wrapper, this one cds to the project root first: pyrefly discovers both its config (pyrefly.toml / [tool.pyrefly]) and a project-root venv by walking up from the cwd, and the LSP subprocess cwd isn't documented.
Which one? Match whatever runs as your type-check gate — the point of both plugins is that Claude's diagnostics don't disagree with the thing that blocks your commit. Pyrefly is much faster and still moving quickly; basedpyright has the deeper rule set and the pyright-compatible config. Don't run both: they declare the same .py/.pyi extensions, so the first registered wins, the other silently never starts, and /plugin shows a warning naming the winner.
Tuned for my setup. Same assumptions as
basedpyright-lsp: a.venv/and/or auv-managedpyproject.toml. Adjustbin/langserver.shfor Poetry, conda, or a differently-named venv.
Where side-quest findings live, so they neither derail the current task nor evaporate — a register for the items that are real but not today's job.
| Component | Trigger | Description |
|---|---|---|
| skill | /tracking:backlog [slug] |
Read, work, and append deferred-work items in docs/backlog/ — one slug-named file per item, worth: yes/later/no, no index, git rm in the fixing commit |
backlog — a defect, open decision, or follow-up surfaces mid-conversation; this writes it into docs/backlog/ instead of letting it derail the work or vanish, and reads it back later. One file per item, named by a slug that names the defect (reopen-fallback-ignores-frontmost.md) so it can be cited from a commit and dedupe is a filename check; no index file — the directory listing is the index. Three frontmatter fields: worth: yes | later | no (the triage call the list is ordered by — later must name the unknown that would settle it, no is kept deliberately so the next review that touches the file does not rediscover and re-argue it), where: path or path:symbol (never a line number — those rot), and added (never updated, so it reads as age). Items pass a three-part admission gate (real and re-derivable from code; not being done now; not owned by a dated review) and the body is written for a reader without the conversation: the concrete run with real values, the misreading to prevent, options with costs plus a recommendation for a later, and provenance. Reading the list verifies every where against the tree and reports stale anchors as stale rather than as work, then offers fix-a-named-item / drop / leave via AskUserQuestion; /tracking:backlog <slug> jumps to one item. Appending dedupes on where then slug, refuses to write onto a non-default branch without asking (a note on a feature branch gets swept into that PR or dies with it), checks the index for pre-existing staged work before offering to commit, and offers commit and push together. No checkbox, no resolved state: the item is git rm'd in the commit that lands its fix. Adapted from umputun/cc-thingz (MIT); see NOTICE for what was kept and what changed.
Tuned for my setup. Assumes the
docs/layout (docs/backlog/, dated reviews underdocs/reviews/<date>/). The item shape is project-agnostic otherwise.backlogis Git-only by design.
| Component | Trigger | Description |
|---|---|---|
| skill | /huddle:huddle, or any question that asks you to choose or approve |
Asks the question as a page in an agterm HTML overlay over the agent's own session and hands the answer back as JSON |
| command | huddle (on the Bash tool's PATH) |
The launcher the skill runs: huddle q … for one line, huddle - for a JSON spec, huddle wait, huddle render, huddle demo |
huddle — a text prompt is the wrong shape for many of the questions an agent asks a developer. "Which of these three architectures?" wants the three diagrams. "Is this the right fix?" wants the code. "How round should the cards be?" wants a slider and a preview, not a list of pixel values. huddle gives the agent a page for those: options that carry a picture (mermaid diagrams, wireframes, color, radius and type samples, charts), up to nine choices with a gray subtitle, a reasoned Recommended badge and pros and cons, alternatives side by side, sliders with a live preview and the starting look beside it, several related questions on one page with a review of every answer before anything is sent, and a free-text box on every question, so a note travels with the choice or replaces it. The keys are 1–9, arrows, Tab for the note, ⏎ to send, and ⌥⏎ for "let's talk in the terminal instead". The page takes the terminal theme's colors, and while it waits the session's sidebar row shows the same amber "asking" glyph a built-in question gets. The agent writes a small JSON spec, or one line: huddle q "Which store?" "*Redis|already runs|no new service" "Postgres|one table".
What I changed from the upstream skill, mostly to make it hold up as a daily tool:
- It is a command, not a path. The launcher lives in the plugin's
bin/, which Claude Code puts on the Bash tool'sPATH, so the agent can typehuddle wait <id>turns later without carrying a path around, and the skill'sallowed-tools: Bash(huddle *)pre-authorizes it in the turn that loads the skill. Upstream setH=…/huddle.pyonce and used$Hafterwards, which is empty in every later Bash call because shell state does not persist between them. - Real code, from disk.
{"code": {"file": "src/x.py", "lines": "40-62"}}reads the lines when the page is built and shows them numbered under their path;diff,mdandmermaidtake afilethe same way. Escaping source into JSON by hand is where a spec breaks or the snippet you decide on quietly stops matching the file. A whole file over 300 lines is refused: name the lines the question is about. - It refuses to ask nobody. A
claude -prun started from an agterm shell inheritsAGTERM_ENABLED=1, so upstream would open a page inside ralphex or a plan executor and stall it for 570 s. Claude Code setsCLAUDE_CODE_SESSION_ATTENDED=0there; huddle reads it and exits 3 without opening anything. The skill also tells subagents to hand their question to whoever started them. - Failures say what they are. An overlay slot already taken is exit 5
busyinstead of a bare error, and when the overlay in the way is a huddle page, the reply carries its id — usually the agent's own question, left pending by a timeout, whose id was lost with the call that opened it;huddle waiton an invalid page id or a stopped agterm fails at once instead of spinning out its 570 s and reportingpending; a malformed spec gets the JSON error, never a traceback. - The one remote script is verified. Diagrams need mermaid, which is fetched once from jsDelivr and inlined into a page that runs with agterm's bridge — and that bridge can type into terminals. The bundle is now checked against a pinned sha256 on every use; on a mismatch the diagrams show as source and stderr says why.
- The agent doesn't check for agterm; huddle does. Upstream's description names
AGTERM_ENABLED=1as the condition for using it. In eval runs of my first rewrite, which kept that condition, the agent spent a Bash call checking the variable, and where that call was not allowed it never asked with a page at all (0 of 6 runs). The description now says to runhuddlewithout checking; it tried in 6 of 6. For that to be safe, the browser fallback outside agterm is now opt-in: a plain terminal gets exit 3 and nothing opens. - The "asking" glyph tells the truth. Status hooks that repaint the sidebar after every tool call and at turn end (mine do) covered a question waiting in the background, so the sidebar said "working" while a page sat unanswered. The plugin installs a Stop hook (
hooks/hooks.json): when a turn ends with a huddle page still open, it re-posts the asking glyph, and because hooks run in parallel and in no fixed order, it keeps re-posting over any slower hook for 6 s (a hook slower than that wins), then exits. It runs async, so the turn's end never waits on it, and its shell guard skips Python entirely outside agterm or withoutpython3. It does nothing mid-turn, so a long test run keeps its working glyph, and the glyph it posts clears when you visit the session, so a question you close with nobody waiting does not strand an amber triangle. One case it misses: Stop does not run when you interrupt a turn with Escape, so the glyph stays as the last hook left it until the next turn ends — but then you are at that session, where the page is. - A page carries more context than a list, never less. A plan-approval page once showed three bare options, "Story 3", "Story 4", "Story 5", and none of the evidence. The agent had written each question's evidence under
context, which the upstream page shows only at the top level, so it dropped all of it silently. A question'scontextnow renders like itsbody; any key the page does not read is an error that names the key it probably meant; and an option labeled only by its position ("Story 3", "Option B") with nothing else on it is refused, so the agent has to put the story's text on the option. The skill's new "Carry the context" section says the same to the agent: what is being decided lives on the option, labeled by what it says, with its full text open on the page. qoptions take a third field for the recommendation's reason (*Label|subtitle|why),api.selecton a single-choice question replaces the choice instead of adding a second one, and the "when to ask with a page" rules defer to whatever your ownCLAUDE.mdsays about asking.
It asks every choice with a page, and your own rules decide whether it gets to. A list of short labels is where the difference between options gets lost, so huddle takes every question that asks you to choose or approve — a design fork, a sequencing call, a plan or its parts, even a choice between two options — and leaves only typed answers (a name, a path, a number) and a bare "go ahead?" on a step just described to the terminal. If your instructions say how questions are asked, they need to hand those questions over. Mine route 2–4-option choices to the question widget, and with only a narrow exception for "structural" choices, my sessions sent 89 questions to the widget and 3 to huddle in the first two days (counted from the session transcripts). This rule, as a Claude-only rules file (
~/.claude/rules/huddle.md, not a rules file Codex also reads), turned that around:Inside agterm, every question that asks me to choose or approve goes through the huddle skill: a design fork, a sequencing call, a plan or its parts, a choice between two options. It replaces the question widget there, overriding the shared rule on how questions are asked. Only a question I answer by typing (a name, a path, a number) or a bare "go ahead?" on a step you just described stays in the terminal.Measured in
claude -pruns with my real configuration and the real launcher, three runs each: an architecture choice, a code judgement and a two-option "full suite or unit tests?" all went to huddle 3 of 3; a rename confirmation and a "which Jira ticket?" question stayed in the terminal 3 of 3; the question widget was used 0 times in 15. The narrower exception it replaces got the architecture and code questions but left the two-option choice in the terminal, and a looser first wording of that one missed the architecture question too ("the user asked for one plain question"): naming what the agent is about to do is what makes these lines work.Permissions.
allowed-toolsonly covers the turn that loads the skill; the grant clears at your next message. If you don't run in auto mode, add"Bash(huddle *)"topermissions.allowso ahuddle waitin a later turn doesn't prompt. Pluginbin/directories come after your ownPATHentries, so ahuddleof your own would shadow this one.Needs agterm 0.34+ and Python 3 (standard library only). Outside agterm it opens nothing and exits 3, so the agent asks in the terminal;
"browser": truein~/.config/huddle/defaults.jsonserves the page on127.0.0.1in your browser instead. Personal defaults — style, panel size, the status glyph, a sound when a question arrives — live in~/.config/huddle/defaults.json.tests/test-huddle.shrenders every template and demo and loads each page in headless Chrome when one is installed. Five eval cases underplugins/huddle/evals/check that the agent reaches for a page on an architecture choice, a code judgement and a two-option choice, with a spec worth showing, and stays in the terminal for a go-ahead and a typed answer. Screenshots are in the upstream README. Adapted from skkap/claude-skills (MIT); seeNOTICEfor what was kept and what changed.
| Component | Trigger | Description |
|---|---|---|
| skill | /agrev:agrev [file], or "review this plan" |
Opens the document in plannotator in an agterm session right after the agent's, waits for your decision, and answers your annotations in the next round |
agrev — reading a plan as raw markdown in a terminal, or as a diff, is the wrong place to mark it up. agrev opens the document rendered in plannotator, in an agterm session of its own right after the agent's, so the chat stays one click away. You comment on phrases, mark text for deletion, attach images, and press Send Feedback or Approve. The agent gets every annotation at once, edits the document itself, and opens the next round with its replies pinned to the phrases they answer; plannotator shows what changed since the last round. scripts/review.py does everything that touches plannotator and agterm: it records plannotator's URL instead of opening a browser, shows the page in agterm, and puts a small proxy in front of plannotator that keeps its cookies between reviews, because an agterm overlay starts with empty storage and every review would otherwise open on the onboarding dialogs. It also strips the agent's own pinned comments from the feedback plannotator exports, so they are not read back as yours.
Needs agterm, plannotator and Python 3 (standard library only).
review.py opennames the plannotator install command when it is missing. Each round's log, result and comments stay in~/.cache/agrev/runs/.
| Component | Trigger | Description |
|---|---|---|
| skill | /peer-planning:make |
Writes a plan in docs/plans/ whose tasks state the outcome, the constraints and the proof of done, not the steps, for an executor that finds the details itself |
| skill | /peer-planning:exec <plan> |
Runs the plan as a two-agent loop in an agterm split: a subagent implements each task, Codex reviews the diff before the commit, then Codex is cleared for the next task |
peer-planning — one agent working alone accepts its own reasoning. Here a second one, Codex in the other pane of the split, reads every task's diff before it is committed, and for a task the plan marks for discussion it argues the approach before any code is written. This session orchestrates: it hands each task to an implementation subagent (Opus at medium by default), carries messages between Codex and the subagent, and clears Codex between tasks so each review starts fresh. Every step lands in an events.jsonl log, and a monitor page in an agterm overlay shows who holds the wait. After the last task it reviews the whole branch in revmux rounds, a full pass and then re-checks of the fixes, with a fresh subagent fixing each round's findings, then runs the project's /polish step, and stops before finalize, which you run. The plans make writes are coarse, because the executor is capable and the planner's job is to settle the decisions, not to script the edits. Both skills read the project's .claude/planning-rules.md.
Needs the rest of the setup. agterm with its two-agent-chat recipe installed (
peer-chat.pyonPATH, thepeer-chatskill for Claude and for Codex), Codex running in the right pane of the split, and revmux for the branch review. A project changes that review by overriding revmux'scomprehensiveandfinalprofiles in.revmux/prompts/profiles/, or replaces the playbook with its own.claude/peer-planning/review.md. A project without a/polishcommand skips that step. The monitor's test panel is fed by a separatepeer_planning_pytestmodule loaded throughPYTHONPATH, which this repo does not ship; without it the panel stays empty.
| Component | Trigger | Description |
|---|---|---|
| output style | /config → Output style → Direct |
Peer-to-peer tone, plain English, choice-first, diagrams-first |
Ships direct.md as a Claude Code output style — a system-prompt modification, not a skill, so there's nothing to invoke. Install the plugin, then pick Direct under /config → Output style (or set "outputStyle": "Direct" in a settings file). It takes effect on the next /clear or session, since the system prompt is read once at session start. keep-coding-instructions: true is set, so Claude's built-in software-engineering instructions stay in place and this layers on top.
force-for-plugin is deliberately not set: enabling the plugin offers the style, it doesn't impose it. If you want it applied automatically everywhere, add force-for-plugin: true to the frontmatter of your own copy — it overrides the user's outputStyle setting, which is why it isn't the shipped default.
Direct sets the working relationship first: Claude and I are both senior engineers, so it is told to hold its own opinion, disagree openly, challenge a wrong premise, and never soften a real problem — the point is to stop the model from treating me as an authority it can't argue with. On top of that: plain English and short replies, concrete A:/B: choices instead of guessing intent or pre-deciding, and a lead-with-a-diagram rule for anything structural (ASCII in chat, Mermaid in files and Artifacts, since chat clients don't render Mermaid).
An AI tells section bans the wording tics of model-generated prose — AI vocabulary ("delve", "pivotal", "leverage"), "not just X, but Y", forced groups of three, synonym cycling, hedge stacks, filler, inline-header bullets that restate their own line, abstract metaphor nouns, and feeling-words where the mechanism should be. Cherry-picked from Cursor's unslop skill; the "add soul" half and the blanket em-dash ban were deliberately left behind.
A Scope section bounds all of it: these rules shape text written for me to read, and nothing else. Subagent prompts, plans, ADRs, commit messages, and anything under docs/ keep full detail — exact errors, file:line, provenance, stated uncertainty. Brevity applied to text another agent consumes is information loss that never reaches a human to be noticed. Same axis as the diagram rule: the destination decides, not the topic.
Editing it. Unlike a
SKILL.md, an output style is part of the system prompt: edits need/reload-plugins(or a restart) and a/clearbefore they show up. To iterate on a fork of it without installing, runclaude --plugin-dir plugins/output-styles.
This repo is markdown apart from the two language-server launcher scripts and huddle's launcher and page runtime. GitHub Actions checks frontmatter, shellcheck, and the manifests on every push and PR (see .github/workflows/ci.yml); its shell-test step runs whatever matches tests/test-*.sh, so a test only needs a file dropped in tests/. The one there now, tests/test-huddle.sh, covers huddle.
Behavior that only shows up when a model reads a skill is covered by eval cases instead, in the native claude plugin eval format under a plugin's own evals/ directory (plugins/decide/evals/ and plugins/huddle/evals/ so far):
claude plugin eval decide@silver-cc-tools # + no-plugin baseline arm
claude plugin eval ./plugins/decide --ablation with-withoutThese are not in CI — they cost money and need a live agent. Targeting a plugin by name adds the baseline arm automatically; a path target needs --ablation with-without, and without a baseline a score says nothing about whether the skill changed anything.
MIT — see LICENSE.