This repo is a personal Claude Code plugin marketplace by @seankoji
(.claude-plugin/marketplace.json:2 — marketplace name is seankoji). It packages and distributes
reusable Claude Code slash-command plugins so they can be installed across
machines with one command and kept in sync, instead of being copy-pasted into each machine's
~/.claude/ by hand.
Who it's for: two distinct audiences.
- Plugin users — anyone who runs
claude plugin marketplace add seankoji/claude-pluginsand installs one or more plugins. They only ever see each plugin's slash commands and itsREADME.md. - Marketplace maintainers — whoever adds/edits plugins. They are governed by
AGENTS.md(loaded by Claude Code for sessions inside this repo) and the CI in.github/workflows/validate.yml. Users never seeAGENTS.md(AGENTS.md:3-4).
What it solves: Claude Code reads plugins from a marketplace — a git repo with a top-level
marketplace.json index pointing at self-contained plugin packages. This repo IS that marketplace. It
currently ships 6 plugins: elephant-goldfish, claude-tuneup, prompt-builder, imps, ape,
offload-sidecar (.claude-plugin/marketplace.json:7-45).
.claude-plugin/marketplace.json # the index: name "seankoji", owner, list of 6 plugins
schemas/marketplace.schema.json # contract for the index
schemas/plugin.schema.json # contract for each plugin manifest
plugins/<name>/
.claude-plugin/plugin.json # this plugin's manifest (NO "commands" field — see below)
commands/<cmd>.md # slash commands, AUTO-DISCOVERED from this dir
scripts/* # bundled helpers (chmod +x for *.sh)
personas/*.md # bundled briefs (imps only)
README.md # user-facing docs for this plugin
README.md # marketplace overview + install table (one row per plugin)
AGENTS.md # maintainer guide (in-repo agents only)
.github/workflows/validate.yml # CI gate
- Commands are auto-discovered from
commands/*.md. Aplugin.jsonhas nocommandsfield — CI rejects any manifest that has one (.github/workflows/validate.yml:23-24). Every plugin manifest here omits it (e.g.plugins/imps/.claude-plugin/plugin.json). - Invocation is always
/<plugin>:<command>— the plugin name namespaces every command. A fileplugins/imps/commands/status.mdis invoked/imps:status;plugins/elephant-goldfish/commands/elephant.mdis/elephant-goldfish:elephant. The command file stem is the command name; a nested file (e.g.plugins/imps/commands/issue-mode.md) becomes/imps:issue-mode. - Marketplace
namevs gitsourceare different identifiers. You ADD the marketplace by its git source (claude plugin marketplace add seankoji/claude-plugins), but you INSTALL a plugin by<plugin>@<marketplace-name>(claude plugin install imps@seankoji). The@seankojisuffix is thenamefield inmarketplace.json:2, not the GitHub path (README.md:18-30).
This is the single most important architectural rule for the bundled-asset plugins:
- Bundled assets (scripts, persona briefs) ship inside the plugin and self-locate via the
${CLAUDE_PLUGIN_ROOT}env var that Claude Code sets to the installed plugin's directory. Commands reference assets as${CLAUDE_PLUGIN_ROOT}/scripts/...— never a hardcoded~/.claude/path. This is an enforced invariant (AGENTS.md:38-39) and CI fails the build if acommands/*.mdfile hardcodes a bundled-asset~/.claude/path (.github/workflows/validate.yml:48-58). - Runtime state (logs, run state, learnings) is written outside the plugin, under the user's
~/.claude/. It is created on first run, is not bundled, and is per-user/per-project. Example: imps writes~/.claude/imps/runs/<slug>.json(plugins/imps/README.md:106-114); claude-tuneup writes~/.claude/claude-tuneup.notes.md; prompt-builder reads~/.claude/prompt-builder/learnings.md.
Mnemonic: read from ${CLAUDE_PLUGIN_ROOT}, write to ~/.claude/.
| Component | Role | Owned by |
|---|---|---|
| Marketplace index | Lists the 6 plugins; defines the seankoji name |
.claude-plugin/marketplace.json |
| Marketplace schema | Draft-07 contract for the index (requires name/owner/plugins) | schemas/marketplace.schema.json |
| Plugin schema | Draft-07 contract for each manifest (8 required fields) | schemas/plugin.schema.json |
| Maintainer guide | Layout, add-a-plugin checklist, invariants | AGENTS.md |
| Marketplace README | User-facing overview + install instructions | README.md |
| CI validator | 5-check gate on every push/PR | .github/workflows/validate.yml |
| elephant-goldfish | Self-validating design-doc generator + Gemini judge | plugins/elephant-goldfish/ |
| claude-tuneup | Permission audit + settings tuneup | plugins/claude-tuneup/ |
| prompt-builder | Iterative prompt-engineering assistant | plugins/prompt-builder/ |
| imps | Swarm orchestrator (parallel model-routed agents) | plugins/imps/ |
| ape | OSS-repo foraging for transferable techniques, run as a Workflow script | plugins/ape/ |
| offload-sidecar | MCP file-transform/vision offload to local Ollama tiers or budget-gated Gemini via agy | plugins/offload-sidecar/ |
- One plugin per tool vs one bundled mega-plugin. Chosen: one plugin per tool (4 separate packages
under
plugins/). This lets users install only what they want (claude plugin install prompt-builder@seankojiwithout dragging inimps), and keeps each plugin's manifest, README, and CI surface independent. A single bundled plugin would force all-or-nothing installs and couple unrelated release cadences. (Inferred rationale — the per-plugin layout and per-plugin install rows inREADME.md:7-12are the evidence; the trade-off reasoning is inferred.) /<plugin>:<command>namespacing vs bare commands. Accepted the namespaced form because it is what Claude Code's marketplace plugin system imposes — commands are auto-discovered and prefixed by plugin name. There is no bare-command option for marketplace plugins; the cost (longer invocation) is paid to get collision-free naming across plugins. (Inferred — namespacing is observable in every README's usage block; that it is mandatory rather than chosen is inferred from the auto-discovery model.)- Marketplace name
seankoji(notclaude-plugins). The marketplacenameisseankoji(marketplace.json:2) even though the repo isclaude-plugins. The Claude Code CLI rejects marketplace names containing the substring "claude", so the repo name could not be reused as the marketplace name; the owner handle was used instead. This is whyinstall <plugin>@seankojiworks but@claude-pluginswould not. (The "claude"-substring rejection is the stated reason in the task brief and is consistent with the divergent name; treat the exact CLI rule as inferred — it is not asserted in a repo file.) plugin.jsoncarries nocommandsfield vs an explicit command list. Chosen: rely on auto-discovery fromcommands/*.mdand actively forbid acommandsfield (CI rejects it,validate.yml:23-24). An explicit list would drift from the files on disk; auto-discovery makes the filesystem the single source of truth. (Rationale inferred; the CI rejection is fact.)- Fail-closed judge vs fail-open. elephant-goldfish's judge exits non-zero (code 2) on empty/unreachable
output rather than treating "no gaps found" as a pass — an empty judge response must never certify a doc
(
plugins/elephant-goldfish/scripts/goldfish-judge.sh:64-72,164-167). Stated invariant: "Fail-closed beats fail-open everywhere" (AGENTS.md:42).
elephant-goldfish — plugins/elephant-goldfish/
- Command:
/elephant-goldfish:elephant(commands/elephant.md). A self-validating design-doc generator: writes/updateselephant.mdgrounded in the repo, then a Goldfish Gate runs a closed judge→patch→re-judge loop (up to 5 rounds) using a different-lineagegeminiCLI reader (commands/elephant.md:11-33). - Modes via argument (
commands/elephant.md:2-6,35-36,51-58): bare = write (or just gate an existing doc) then run the judge loop;check= read-only factual-drift pass — amodel: haikuagent verifies everypath/path:linecitation and flags undocumented additions, no writes, no judge; any other text = a goldfish failure report pasted back from a prior run, folded in directly. - Bundled asset:
scripts/goldfish-judge.sh— ONE cold comprehension pass whose primary judge is thegeminiCLI, with an optional second-opinion judge viaollama(setOLLAMA_MODEL). Exit codes:0=READY (every judge that ran agrees),10=NOT READY (any judge disagrees),2=judge error/empty/no VERDICT line (fail-closed),1=usage (scripts/goldfish-judge.sh:19-27,64-72,164-167). Both judges get the doc inlined into the prompt — never file access — so no sandbox flags are needed (scripts/goldfish-judge.sh:5-17). - Config env vars:
GEMINI_MODEL(defaultgemini-2.5-pro),OLLAMA_MODEL(unset — optional second judge),OLLAMA_NO_THINK(true),OLLAMA_HOST,JUDGE_TIMEOUT(180s) (scripts/goldfish-judge.sh:36-45,README.md:76-84). - Prerequisite:
geminiCLI on PATH, pointed at a Gemini model — not a Claude model, or the judge shares the author's priors (README.md:37-53).
claude-tuneup — plugins/claude-tuneup/
- Command:
/claude-tuneup:claude-tuneup(commands/claude-tuneup.md). Three phases: Scan (read last 50 transcripts, surface allowlist candidates with count ≥ 3, classify global vs project), Audit (compare~/.claude/settings.jsonvs project.claude/settings.json, strip dupes / move misplaced entries), Self-reflect (append findings to~/.claude/claude-tuneup.notes.md) (README.md:11-29). - Flags:
--scan-only,--audit-only,--dry-run,--no-reflect(README.md:58-64). - Bundled asset:
scripts/scan_perms.py, invoked aspython3 ${CLAUDE_PLUGIN_ROOT}/scripts/scan_perms.py; if absent, Phase 1 is skipped and the run falls back to--audit-only(README.md:72). - Prerequisite: Claude Code only — no external tools (
README.md:33-35).
prompt-builder — plugins/prompt-builder/
- Command:
/prompt-builder:prompt-builder [initial brief](commands/prompt-builder.md). Iterative prompt-engineering assistant: diagnose → structure → draft → critique → deliver → refine (README.md:8-15). PR #56 dropped the 8 acronym frameworks in favor of Anthropic's own evidence-based prompting techniques — none of the acronyms are evidence-based and picking between near-identical ones wasted time without changing output (README.md:11,commands/prompt-builder.md:98-103): XML-tag structuring, context/motivation, long-context layout, Chain-of-Thought, prompt chaining, few-shot examples, and do-vs-don't phrasing (README.md:19-30). Prefilling is deliberately not used — deprecated on current models (README.md:31). - Bundled asset:
scripts/audit-log.sh(byte-identical copy also inimpsandclaude-tuneup) — appends one structured line to~/.claude/audit.jsonlat session end; needsjqon PATH and skips itself with a warning (not a failure) if missing (README.md:35). - Optional runtime state:
~/.claude/prompt-builder/learnings.mdread at session start, grown over time with a ~150-line soft cap (README.md:37,62-68).
imps — plugins/imps/
- Four commands, all auto-discovered from
commands/:/imps:imps(commands/imps.md) — swarm orchestrator. Three entry modes auto-detected from the argument: free-text task, issue-driven (/imps 42 43 51), checklist-file (README.md:23-49)./imps:issue-mode(commands/issue-mode.md) — issue-driven mode (scout issues → rolling dispatch in isolated worktrees → holding branch → gates → persona panel → operator handoff)./imps:status(commands/status.md) — self-rescheduling heartbeat for active runs; stops when the state dir is empty./imps:prs(commands/prs.md) — proactive PR monitor; addresses review comments, CI failures, merge conflicts; stops when the PR is merged/closed/48h old (README.md:51-56).
- Bundled assets (
README.md:96-104): 5 persona briefs at${CLAUDE_PLUGIN_ROOT}/personas/<slug>.md(solution-architect,grumpy-engineer,sre,business-analyst,ux-designer— see the panel table atREADME.md:79-85) and a cosmetic banner${CLAUDE_PLUGIN_ROOT}/scripts/imps-intro.py. - Runtime state under
~/.claude/imps/(README.md:106-118):runs/<slug>.json(dispatch state + heartbeat source),runs/<slug>.prs.json(PR-monitor state),learnings.md(self-tuning## Active rules, ≤10 bullets, read at startup every run). - Prerequisites (
README.md:58-72): Workflow tool (degrades to sequentialAgentcalls),ghCLI for issue-driven mode, GitHub MCP (mcp__github__*) for PR/issue reads, theimpagent type (falls back togeneral-purpose). Optional:CLAUDE_CDP_URLand Claude-in-Chrome MCP for the browser review half.
ape — plugins/ape/
- Two commands:
/ape:forage [focus](commands/forage.md) — Phase 0 (fingerprint) runs as a plain command, then syncs the bundledscripts/ape-forage.workflow.jsinto~/.claude/workflows/ape-forage.js(a plugin can't ship a runnable Workflow directly —.jsworkflows only load from a user's own~/.claude/workflows/) and invokes it;/ape:clean [--all](commands/clean.md) — sanctioned deletion of clones, keeping reports unless--all(README.md:48-59). - The synced Workflow script runs: parallel 3-axis discovery (same domain, adjacent stack, curated
sources) → dedupe (plain code) + one judgment-call ranking agent → clone with one automatic retry →
parallel per-repo analysis → one synthesis agent producing
RECOMMENDATIONS.mdplus the top 2-3 picks returned to the caller (README.md:5-46). - Bundled scripts:
scripts/init-workspace.sh,scripts/clone-candidates.sh,scripts/search-repos.sh,scripts/triage-repos.sh,scripts/readme-peek.sh— each batches what would otherwise be a multi-command/for-loop bash block into one matchable command, since Claude Code's permission analyzer can't statically verify a compound block against anallowed-toolsprefix (README.md:54-59,97-99). - All artifacts land in
~/tmp/repo-research/<project-dir-name>/:fingerprint.md(cached ≤30 days),repos/,reports/*.md,RECOMMENDATIONS.md(README.md:78-79). - Prerequisite:
ghCLI (discovery + cloning), the Workflow tool;/ape:foragedispatches a background run, so the command's turn ends before the expedition finishes (README.md:81-85).
offload-sidecar — plugins/offload-sidecar/ (formerly ollama-sidecar)
- No
commands/— this plugin ships only an MCP server (scripts/offload_sidecar.py, run viapython3 ${CLAUDE_PLUGIN_ROOT}/scripts/offload_sidecar.pythrough the plugin's.mcp.json) exposing one tool,process_local_file, for file transforms/digests too irregular for a fixedjq/Python rule. - Reads
input_pathfrom disk and writesoutput_pathback to disk directly — Claude exchanges only a path and an operation name, never file contents. - Two operation kinds: deterministic (pure local Python, no model call — line/format ops plus
json_digest,xlsx_extract) and LLM, routed across four tiers on two engines:deep/fastare local/LAN Ollama endpoints (private);flash/proare Gemini via the Google Antigravity CLI (agy) on the operator's subscription — the only tiers with vision (describe_image,verify_screenshot,pdf_to_structured) and ~1M-token context. - Cloud calls are budget-gated up front: sliding-window per-model call budgets plus lockout deadlines
parsed from agy's own output live in
~/.local/state/offload-sidecar/quota.json; an exhausted budget REJECTS the call before agy is spawned, with a structured error naming the local fallback. - Every output is validated before it's written (format checks, size-ratio bounds, record-count heuristics,
required-JSON-key checks for the digest family, known-secret-shape scans depending on operation); a
failed validation writes to
<output_path>.rejectedand leaves the requested file untouched — never a false"success". userConfig(prompted at install, reconfigurable later): Ollama host/model/num_ctx per local tier, TLS CA bundle, agy binary + flash/pro model names, and the four cloud call-budget caps (plugin.jsonuserConfig).- Prerequisite:
python3on PATH (stdlib only). A reachable Ollama instance is needed only for local-tier LLM operations; theagyCLI (authenticated) only for the flash/pro tiers — each engine degrades independently with a structured error.
Five things must change together — missing one breaks the marketplace:
plugins/<name>/.claude-plugin/plugin.json— fill every required field (the 8 inplugin.schema.json:7)..claude-plugin/marketplace.json— add an entry under"plugins"(name/source/description required).- Root
README.md"Available plugins" table — add one row. plugins/<name>/README.md— user-facing prerequisites, modes, env vars, license.chmod +x plugins/<name>/scripts/*.sh— every shipped shell helper must be executable.
Runs on every push and PR (validate.yml:3). Five steps:
- Marketplace manifest —
marketplace.jsonis valid JSON (:11-14). - All plugin manifests — each
plugins/*/.claude-plugin/plugin.jsonis valid JSON, has a non-emptyname, and has nocommandsfield (:16-26). - Name↔source consistency — for each marketplace entry, the
sourcedir exists and its manifest'snamematches the marketplacename(:28-36). - Shell scripts executable — every git-tracked
plugins/**/*.shhas mode100755(:38-46). - Bundled-asset path hygiene — no hardcoded bundled
~/.claude/paths (~/.claude/scripts/scan_perms,~/.claude/imps/imps-intro,~/.claude/imps/personas/) in anyplugins/*/commands/*.md— useCLAUDE_PLUGIN_ROOTinstead (:48-58).
Local pre-commit check (AGENTS.md:48-52):
jq . .claude-plugin/marketplace.json && for f in plugins/*/.claude-plugin/plugin.json; do jq -e '.name' "$f"; done
grep -rn --include="*.md" 'CLAUDE_PLUGIN_ROOT' plugins/*/commands/ | headschemas/marketplace.schema.json— draft-07; requiresname,owner({name, url}), andplugins[](each requiresname,source,description).schemas/plugin.schema.json— draft-07; requiresname,version,description,author({name, url}),homepage,repository,license,keywords(≥1) (plugin.schema.json:7). All four manifests satisfy this.
claude plugin marketplace add seankoji/claude-plugins # add the marketplace (one-time, by git source)
claude plugin install elephant-goldfish@seankoji # install a plugin (by marketplace name)
claude plugin install elephant-goldfish@seankoji --scope project # project-scoped (shared via .claude/)
claude plugin marketplace update # keep up to dateThen invoke any command as /<plugin>:<command>, e.g. /imps:status or /prompt-builder:prompt-builder.
- The exact Claude Code CLI rule that a marketplace
namemay not contain the substring "claude" is taken from the design brief, not asserted in any repo file. The divergence between repo nameclaude-pluginsand marketplace nameseankoji(marketplace.json:2) is consistent with it, but the rule itself is unverified from the tree. - Default branch is documented as
masterinAGENTS.md:6. This worktree's HEAD is detached ata805f23; branch naming was not independently re-verified.
Refresh: /elephant-goldfish:elephant (gate an existing doc) · reconcile (drift) · regenerate (rebuild)