A personal Claude Code plugin marketplace — a single Git repo holding skills shared across Claude Code, OpenAI Codex, and Grok Build. See Using with Codex and Using with Grok.
Claude Code — add the marketplace, then install a plugin:
/plugin marketplace add kurrik/dotclaude
/plugin install ark@dotclaude
Or share it across all your instances declaratively (recommended) — see Share across every instance below.
Codex CLI — same two steps, from a shell:
codex plugin marketplace add kurrik/dotclaude
codex plugin add ark@dotclaude
Grok Build — add the same marketplace and install the plugin:
grok plugin marketplace add kurrik/dotclaude
grok plugin install ark --trust
| Plugin | Provides | Invoke as |
|---|---|---|
ark |
Git & GitHub workflow skills | Claude Code and Grok: /ark:pr, /ark:review, /ark:reset-worktree, /ark:polish, /ark:improve-polish · Codex: the same names via $ mention (e.g. $ark:pr) or /skills |
/ark:polish— frontload the PR review cycle before pushing: run up to three reviewers in parallel subagents (the current host's native reviewer, a preferred cross-agent CLI review if installed, and a check against a layered review-principles corpus), triage and fix findings without expanding scope, commit each round with the audit trail in the message, and loop until findings are exhausted, nitty, or need a human. Claude Code pairs its native review with Codex CLI; Codex pairs its native review with Claude CLI; Grok pairs its native review with Codex CLI, falling back to Claude CLI only when Codex is unavailable or fails before reviewing. This avoids redundant nested same-agent sessions. Designed to run before/ark:pr. The corpus has three layers: general principles bundled with the skill (plugins/ark/skills/polish/principles/), machine-specific rules in~/.claude/review-principles/, and repo-specific rules in the repo's.claude/review-principles/— same-named files are the same principle, with the more specific layer winning on conflict./ark:improve-polish— upstream review-cycle lessons from the current session back into the bundled corpus: diagnose this session's polish rounds, PR review feedback, and human corrections for generalizable lessons (errors and feedback to anticipate, better fix patterns), draft principle updates with real positive and negative examples, and — after you approve the draft — open a PR against this repo entirely throughgh api, so it works from any machine that installed the marketplace with no local checkout ofkurrik/dotclaude./ark:pr— stage, commit, push the current branch, and open a GitHub PR with an auto-generated description that follows the repo's PR template. Runs/ark:polishon the branch before pushing unless you explicitly say to skip it./ark:review— fetch PR review comments, address them, push fixes, and reply to each thread through a single pending review. Runs/ark:polishon the fix commits before pushing unless you explicitly say to skip it./ark:reset-worktree— reset the current git worktree's branch back to the base branch, or the primary clone back to a cleanmaincheckout. Asks before discarding uncommitted work.
Requirements:
/ark:prand/ark:reviewuse the GitHub CLI (gh) signed in to your account. Noghextensions needed —/ark:reviewtalks to GitHub's GraphQL API directly viagh api./ark:reset-worktreeneeds onlygit./ark:polishneeds onlygitfor its always-on native and principles legs; its optional cross-agent leg usescodexfrom Claude Code,claudefrom Codex, and preferscodexwith aclaudefallback from Grok. General principles ship with the skill, augmented by~/.claude/review-principles/and the repo's.claude/review-principles/when those exist./ark:improve-polishneedsghsigned in to an account that can push to (or fork)kurrik/dotclaude.
For a throwaway-worktree workflow: each worktree directory owns the branch worktree/<directory-name>, and resetting means "throw away everything and start again from main".
~/workspace/a17k # primary clone, sits on main
~/workspace/a17k-01 # worktree on branch worktree/a17k-01
~/workspace/a17k-02 # worktree on branch worktree/a17k-02
Run from ~/workspace/a17k-01, it fetches main from origin, checks out worktree/a17k-01 (creating it if needed), hard-resets it to main, and unsets its upstream so a later bare git push can't update a remote copy.
Run from the primary clone, there is no scratch branch to throw away, so the equivalent end state is main itself: it fetches main, checks it out, and hard-resets it to the fetched tip. The upstream is kept (main is supposed to track origin/main), --prefix is ignored, and the branch you were on is left in place — you're just no longer on it.
The logic lives in plugins/ark/skills/reset-worktree/scripts/reset-worktree.sh and is runnable on its own:
bash reset-worktree.sh [--force] [--base <branch>] [--prefix <ns>] [--dry-run]
The skill wrapper exists so the script is distributed with the plugin and so the agent can handle the one case the script won't decide alone: it exits 3 on a dirty worktree, and the skill then asks you before re-running with --force.
--basesets the base branch (defaultmain).--prefixchanges the namespace (defaultworktree);--prefix ''gives a barea17k-01. A prefix cannot be an existing branch name — git stores refs as filesystem paths, so with amainbranch present the refmain/a17k-01is impossible (cannot lock ref 'refs/heads/main/a17k-01': 'refs/heads/main' exists). That's why the namespace isworktree/rather thanmain/; the script rejects a colliding prefix up front.- If
mainis already checked out — in another worktree, or in the primary clone you're running from —git fetch origin main:maincan't fast-forward it; the script falls back to fetching and resetting toorigin/main. reset --hardleaves untracked files alone. The script lists any that survive rather than deleting them.
reset-worktree.test.sh covers these paths against a throwaway repo and runs in CI.
This trips people up, so to be explicit:
- The marketplace name (
dotclaude) only appears when configuring or installing —/plugin install <plugin>@dotclaude(Claude Code),codex plugin add <plugin>@dotclaude(Codex), orgrok plugin marketplace add ...followed bygrok plugin install <plugin>(Grok) — and as the key in settings. It does not prefix anything. - The plugin name is the prefix. A skill
fooin thearkplugin isark:fooin all three tools —/ark:fooin Claude Code and Grok,$ark:fooas a Codex mention.
So when you add a skill, the directory name determines the suffix and the plugin name determines the prefix:
plugins/ark/skills/pr/SKILL.md -> ark:pr
plugins/ark/skills/triage/SKILL.md -> ark:triage
dotclaude/
├── .claude-plugin/
│ └── marketplace.json # Catalog: lists every plugin + its source path
├── plugins/
│ └── ark/
│ ├── .claude-plugin/
│ │ └── plugin.json # Plugin manifest (name, version, metadata)
│ └── skills/ # Skills (one directory per skill)
│ ├── improve-polish/
│ │ └── SKILL.md # Upstreams session review lessons into polish's corpus
│ ├── polish/
│ │ ├── SKILL.md
│ │ └── principles/ # Bundled general layer of the review-principles corpus
│ ├── pr/
│ │ └── SKILL.md
│ ├── reset-worktree/
│ │ ├── SKILL.md
│ │ └── scripts/ # Helper scripts, referenced relative to the skill dir
│ │ ├── reset-worktree.sh
│ │ └── reset-worktree.test.sh
│ └── review/
│ └── SKILL.md
├── README.md
└── LICENSE
Component directories (skills/, commands/, agents/, hooks/, .mcp.json) live at the plugin root — only plugin.json goes inside .claude-plugin/.
To make a plugin load automatically on every machine without running /plugin install each time, add two keys to your user settings at ~/.claude/settings.json:
{
"extraKnownMarketplaces": {
"dotclaude": {
"source": { "source": "github", "repo": "kurrik/dotclaude" }
}
},
"enabledPlugins": {
"ark@dotclaude": true
}
}extraKnownMarketplacesregisters the marketplace automatically.enabledPluginsenables specific plugins by default ("<plugin>@<marketplace>": true).
Replicate those two blocks in any machine's ~/.claude/settings.json (or a project's .claude/settings.json to scope it to one repo) and the plugin is there on next launch.
The Codex CLI reads this repo directly as a plugin marketplace — it accepts the .claude-plugin/marketplace.json catalog and the .claude-plugin/plugin.json manifest as legacy-compatible locations, and discovers the same skills/ directories. No Codex-specific files are needed.
codex plugin marketplace add kurrik/dotclaude
codex plugin add ark@dotclaude
Then start a new Codex session (plugins load at session start). The skills surface under the same names as in Claude Code — ark:pr, ark:review, ark:reset-worktree, ark:polish, ark:improve-polish — invoked by typing $ to mention one, via /skills, or implicitly by description.
To pick up a new version later:
codex plugin marketplace upgrade dotclaude
codex plugin add ark@dotclaude
Grok accepts this repo's .claude-plugin/marketplace.json and plugin manifest as compatibility locations and discovers the same skills/ directories. No Grok-specific copy of the plugin is needed.
grok plugin marketplace add kurrik/dotclaude
grok plugin install ark --trust
The skills surface under their plugin-qualified slash names, including /ark:polish. To pick up a new version later:
grok plugin marketplace update dotclaude
grok plugin update ark
Cross-agent caveats:
ark:polishuses the active host's native subagents and never shells out to that same host: Claude Code runs native Claude +codex review; Codex runs native Codex +claude -p; Grok runs native Grok +codex review, usingclaude -ponly when Codex is unavailable or fails before reviewing. If no selected external CLI is installed, polish proceeds with its native and principles legs and reports the skip.- Claude frontmatter such as
allowed-toolsandargument-hintis ignored by Codex but supported by Grok. Codex invocations still work; they simply lack the pre-approved tool list and argument autocomplete.
Claude's cloud environments — Claude Code on the web and scheduled Routines — preinstall git but not the gh CLI, and gh's API calls need an explicit token. To use the ark commands there:
- In the environment's Setup script, install
gh(setup-script installs are snapshotted and reused across sessions, so this runs once — not every session):#!/bin/bash apt-get update && apt-get install -y gh
- Add a least-privilege token as an environment variable so
gh apiis authenticated withoutgh auth login:GH_TOKEN=<your token> - No network change needed —
github.comis in the default "Trusted" egress allowlist.
Because /ark:review uses gh api directly (no gh extensions), that's the whole list — there's nothing else to provision.
- Create
plugins/<name>/.claude-plugin/plugin.jsonwith at least{ "name": "<name>" }. - Add skills under
plugins/<name>/skills/<skill>/SKILL.md. - Register it in
.claude-plugin/marketplace.jsonby appending to thepluginsarray:{ "name": "<name>", "description": "…", "source": "./plugins/<name>" } - Validate, commit, push:
claude plugin validate . - On each instance,
/plugin marketplace update dotclaude(or restart) picks up the change.
CI (
.github/workflows/validate.yml) re-runsclaude plugin validateon the marketplace and every plugin for each push and PR, so a broken manifest can't land onmain. It also runs everyplugins/*/scripts/*.test.shandplugins/*/skills/*/scripts/*.test.sh, so name a script's test suite that way and CI picks it up.
Everything in this repo ships as a skills/<name>/SKILL.md directory because Claude Code, Codex, and Grok all discover skills natively. In Claude Code and Grok a skill is user-invocable as /<plugin>:<name> (with argument-hint, allowed-tools, and disable-model-invocation frontmatter all supported) and model-invocable from its description — so a skill loses nothing compared to a commands/*.md slash command.
Claude-only commands/*.md files, by contrast, only reach Codex through its automatic command→skill migration, which is unreliable: it silently skips any command file over ~4 KB or containing $ARGUMENTS, and the migrated names come out as <plugin>:source-command-<name>.
To keep a skill portable across all three tools:
- Reference bundled files relative to the skill directory ("
scripts/foo.shinside this skill's directory") —${CLAUDE_PLUGIN_ROOT}and${CLAUDE_SKILL_DIR}only expand in Claude Code. - Don't rely on
$ARGUMENTSsubstitution (Claude-only); phrase argument handling in prose. Claude Code appends unmatched arguments asARGUMENTS: <value>, Codex arguments follow the$mention, and Grok arguments follow the slash command. - Claude frontmatter (
allowed-tools,argument-hint,disable-model-invocation) is supported by Grok and ignored by Codex, so it's safe to keep.
Each plugin's plugin.json carries an explicit version. Bump it when you change a plugin so instances see an update is available. (Omit version entirely and Claude Code falls back to the git commit SHA — every commit becomes a new version.)