Contributing¶
Thanks for your interest in contributing to claude-toolbox!
Full documentation lives in
docs/contributing/— architecture overview, plugin development guide, testing conventions, and documentation workflow. This file covers the essentials for quick orientation.
Getting Started¶
- Fork and clone the repo
- Run the test suite to make sure everything works:
for test in test/test-*.sh; do $test; done - Create a feature branch from
master
Development¶
See Architecture for how the components fit together and Testing for test conventions. The authoritative reference for all conventions is CLAUDE.md — this guide summarizes the most important rules for quick orientation.
Key workflows¶
- Editing skills: Edit in
klaude-plugin/skills/, then runmake generate-kodexto regenerate the Codex variant. - Editing profiles: Edit in
klaude-plugin/profiles/, then runmake generate-kodex. Vendored profiles (e.g., Go) usemake vendor-goinstead. - Adding a profile: Follow the "Adding a new profile" checklist in
CLAUDE.md. - Editing codex config: Hand-authored files live in
.codex/(config.toml, hooks.json, rules, scripts). Generated files (agents, kodex-plugin) should not be edited directly.
Commit conventions¶
- Use imperative mood in commit messages ("Add feature" not "Added feature")
- Keep the first line under 72 characters
- Include a blank line + body for non-trivial changes explaining the "why"
Plugin Development¶
The kk plugin lives at klaude-plugin/. This section covers the practical rules for authoring each component. For the full specification, see CLAUDE.md.
Skills¶
Each skill is a directory under klaude-plugin/skills/<name>/ containing at minimum a SKILL.md entry point.
SKILL.md structure:
---
name: skill-name
description: |
Trigger-first description. Front-load the key use case.
---
# Skill Title
## Conventions
## Workflow
Naming rules:
- Imperative verbs over noun phrases:
designnotanalysis-process. - Family prefixes for grouped skills:
review-code,review-design,review-spec. - Reference other skills without the
kk:prefix in prose: writereview-codenotkk:review-code.
Description budget: Claude Code truncates skill descriptions at 1,536 characters per entry. OpenCode's limit is 1,024. Lead with trigger keywords — truncation happens at the tail. Detailed rules, cascades, and examples belong in the SKILL.md body, not the description.
Workflow ordering (ADR 0004): Every skill MUST fully load its instructions before taking any action on its subject matter. This is the single most critical rule for skill authoring.
- "Instructions" = SKILL.md + referenced process files + shared protocols + resolved profile content.
- "Action on subject matter" = reading diff content, editing code, engaging with idea prose, running tests, producing findings.
- A narrow early scope is permitted (e.g.,
git diff --statfor filenames) to drive profile detection. - Content-level read instructions appear exactly once in the workflow, after instruction loading.
Every skill's Workflow section must carry a mandatory-order directive at the top naming this rule by intent. The failure mode: once an LLM has diff content loaded, it has enough to pattern-match findings without methodology, and its efficiency bias favors the shortcut. The methodology becomes ceremony the agent optimizes away.
Shared Instructions¶
Instructions consumed by multiple skills live at klaude-plugin/skills/_shared/<name>.md. Each consuming skill gets a symlink:
Reference in skill prose as [shared-<name>.md](shared-<name>.md). The shared- prefix makes it obvious which files are shared vs. skill-specific. Only symlink into skills that actually reference the file.
Symlinks must stay inside the skills/ tree — cross-boundary symlinks break under some plugin installers (see ADR 0003).
Commands¶
Commands live under klaude-plugin/commands/<name>/. For skills with standard + isolated modes:
default.md— standard variant, invoked as/kk:<name>:defaultisolated.md— isolated sub-agent variant, invoked as/kk:<name>:isolated
Agents¶
Agent definitions live at klaude-plugin/agents/<name>.md with frontmatter specifying name, description, and tools (an allowlist of tools the agent can use):
---
name: code-reviewer
description: |
Independent code reviewer with no authorship attachment.
tools:
- Read
- Grep
- Glob
- mcp__capy__capy_search
---
Agent names describe the role (code-reviewer, design-reviewer), not the skill that invokes them. Don't rename agent files when renaming skills.
Agents inherit the instruction-before-action rule — they must read provided checklists before analyzing subject matter, regardless of payload delivery order from the spawning skill.
Hooks¶
Hook definitions in klaude-plugin/hooks/hooks.json:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-bash.sh"
}]
}]
}
}
Hook scripts read JSON from stdin (the tool_input object), return structured JSON for deny decisions. Always exit 0 — use permissionDecision: "deny" in the JSON output to block a tool call. See klaude-plugin/scripts/validate-bash.sh for the pattern.
Profiles¶
Profiles at klaude-plugin/profiles/<name>/ provide domain-specific content to every workflow phase. See the Profile Conventions section of CLAUDE.md for the full specification.
Required files:
DETECTION.md— three mandatory section headings:## Path signals,## Filename signals,## Content signals. All three must be present even if the body is empty. Optional:## Design signalsfor pre-code detection.overview.md— human-readable summary and dependency-lookup targets.
Phase subdirectories: review-code/, design/, implement/, test/, document/, review-spec/. Not every profile populates every phase. Each populated phase must have an index.md with always-load and conditional entries. Conditional entries need explicit Load if: clauses naming concrete diff properties — two agents evaluating the same diff must reach the same conclusion.
Bidirectional index invariant (enforced by test/test-plugin-structure.sh):
- Forward: every markdown link in
index.mdresolves to a file on disk. - Reverse: every
.mdin the phase directory (exceptindex.md) is referenced by the index.
An unreferenced .md inside a phase subdirectory is always a bug. Authoring notes belong in overview.md at the profile root, not inside phase subdirectories.
Adding a new profile checklist:
- Create the profile directory by copying an existing one as a template.
- Write
DETECTION.mdandoverview.md. - Populate the phase subdirectories the profile needs (each with
index.md). - Append the profile name to
EXPECTED_PROFILESintest/test-plugin-structure.sh. - Append the profile name to the Known Profiles list in
klaude-plugin/skills/_shared/profile-detection.md. - Run
bash test/test-plugin-structure.shand confirm green.
Evaluations¶
Skills with non-trivial decision logic should ship evaluation scenarios under klaude-plugin/skills/<skill>/evals/. One directory per eval:
eval.json schema:
{
"id": 1,
"name": "eval-name-kebab-case",
"description": "What this eval tests.",
"skills": ["skill-name"],
"prompt": "The user prompt that triggers the skill.",
"trap": "The failure hypothesis — what a model is likely to get wrong.",
"files": ["test-files/foo.yaml"],
"assertions": [
{ "id": "1.1", "text": "Specific, gradable behavior." }
]
}
Use real filesystem fixtures in test-files/, not inline JSON strings. Include at least one regression eval proving the skill does NOT activate when it shouldn't.
${CLAUDE_PLUGIN_ROOT} — Substitution Rules¶
The harness provides ${CLAUDE_PLUGIN_ROOT} resolving to the installed plugin's root. Understanding its substitution boundary is critical (ADR 0003):
Substituted at plugin-load time (safe to use ${CLAUDE_PLUGIN_ROOT}/... freely):
SKILL.mdfilesagents/*.mdfileshooks/*.jsoncommand strings- MCP config files
NOT substituted by the Read tool (the literal token reaches the agent):
- Everything in
skills/_shared/ - Everything in
profiles/ - Any file an agent reads at runtime
For runtime-read files, prefer explicit content (e.g., hard-coded profile name lists) over the token. If the file must describe a plugin-root path, instruct the agent to construct it using the resolved prefix it already knows from SKILL.md.
Other rules:
- Brace form required:
${CLAUDE_PLUGIN_ROOT}works, bare$CLAUDE_PLUGIN_ROOTdoes NOT get substituted. Globwon't work against these paths — it's cwd-scoped and returns 0 matches for outside-cwd absolute paths. UseReadwith the resolved path instead.- To reference the variable name literally in prose, use bare
$CLAUDE_PLUGIN_ROOTor${CLAUDE_PLUGIN_ROOT}.
Capy Knowledge Protocol¶
Skills that interact with capy MCP tools use kk: namespaced source labels:
| Label | Contents |
|---|---|
kk:arch-decisions | Architecture decisions, design rationale |
kk:review-findings | Code review patterns, recurring issues |
kk:lang-idioms | Language best practices from external sources |
kk:project-conventions | Discovered project patterns |
kk:test-patterns | Testing approaches, edge cases |
kk:debug-context | Root causes, tricky bugs |
Only index non-obvious learnings not derivable from reading the code or git history. Empty results are normal for new projects — proceed with standard guidelines.
Common Pitfalls¶
-
Workflow ordering is the #1 failure mode. If the agent sees subject matter before methodology, it shortcuts the methodology. Structure every workflow so instructions load first. See ADR 0004.
-
Forgetting
make generate-kodex. After editing anything inklaude-plugin/, the Codex variant drifts. CI checks this withmake generate-kodex && git diff --exit-code kodex-plugin/ .codex/agents/. -
Orphan files in profile phase directories. Every
.mdfile (exceptindex.md) must be referenced by the phase'sindex.md. The bidirectional invariant test catches this. -
Symlinks outside
skills/. Per-skill symlinks must point within theskills/tree (../_shared/<name>.md). Cross-boundary symlinks break under some installers. Profile content uses${CLAUDE_PLUGIN_ROOT}references instead. -
Skill description truncation. Descriptions are truncated from the tail. If your trigger keywords are at the end, the skill won't be matched. Lead with the use case.
-
Stale Known Profiles list. When adding a profile, you must update both
EXPECTED_PROFILESin the test file and the Known Profiles list inklaude-plugin/skills/_shared/profile-detection.md. The list is the runtime enumeration — consumers iterate it rather than walking the filesystem. -
Renaming skills. Update
EXPECTED_SKILLS/EXPECTED_COMMANDSin tests. Don't rename agent files. Don't touchrun_plugin_migration'sdirs_to_removein.claude/toolbox/scripts/template-sync.sh(historical cleanup paths). Don't touchdocs/done/(frozen history). Watch for substring collisions in sed operations. -
Vague
Load if:clauses. Conditional entries in profileindex.mdmust name concrete diff properties (field values, filenames, directory names) — not vague category labels. Two agents evaluating the same diff must reach the same conclusion.
Pull Requests¶
- One logical change per PR
- All test suites must pass:
for test in test/test-*.sh; do $test; done - If you edited
klaude-plugin/, verifymake generate-kodex && git diff --exit-code kodex-plugin/ .codex/agents/shows no drift - Update documentation if your change affects user-facing behavior
Architecture Decisions¶
Non-trivial design decisions are recorded as ADRs in docs/adr/ using Michael Nygard's template (Context, Decision, Consequences). Per-feature design docs live at docs/wip/<feature>/ while work is active and move to docs/done/<feature>/ on completion.
| ADR | Decision |
|---|---|
| 0001 | Single additive detection axis for all profile types |
| 0002 | Profile-first layout with index-driven content loading |
| 0003 | Plugin-root references instead of cross-boundary symlinks |
| 0004 | Instructions before action in every skill workflow |
| 0005 | Two-layer hook + advisory enforcement for Codex |
License¶
By contributing, you agree that your contributions will be licensed under the ELv2 License.
Documentation Site¶
The docs site uses MkDocs Material with mike for versioned publishing.
Local preview:
Build without serving:
How publishing works:
- Push to
master→ deploys asdevvia mike (unreleased docs) - Push tag
v0.14.0→ deploys as0.14(major.minor) and updates thelatestalias to point to it - The bare URL always redirects to
latest(most recent release) - GitHub Actions workflow at
.github/workflows/docs.ymlhandles both - Mike pushes to the
gh-pagesbranch; GitHub Pages serves from there - First deploy requires enabling GitHub Pages on the
gh-pagesbranch in repo Settings
Content structure: Pages live in docs/ alongside internal design docs (wip/, done/, adr/). Internal dirs are excluded from search via exclude_docs in mkdocs.yml but remain accessible by direct URL. The landing page is a custom template at docs/overrides/home.html.
Python deps: Install via pip install -r requirements.txt (mkdocs-material, mike, minify, panzoom).
Repository Structure¶
klaude-plugin/ # kk plugin — Claude (canonical source of truth)
├── .claude-plugin/plugin.json # Plugin manifest
├── skills/ # 10 development workflow skills
├── commands/ # 4 slash commands
├── agents/ # Sub-agents (code-reviewer, spec-reviewer, design-reviewer, ...)
├── profiles/ # Per-domain content (languages, IaC DSLs)
├── hooks/hooks.json # Bash validation hook config
└── scripts/validate-bash.sh # Hook script
kodex-plugin/ # kk plugin — Codex (GENERATED from klaude-plugin/)
├── .codex-plugin/plugin.json # Generated plugin manifest
├── skills/ # Generated skills (transformed SKILL.md files)
└── profiles/ # Per-domain content (languages, IaC DSLs)
.claude-plugin/marketplace.json # Claude marketplace catalog
.agents/plugins/marketplace.json # Codex marketplace catalog
CLAUDE.md # Claude project instructions (this repo)
AGENTS.md # Codex project instructions (this repo)
.claude/
├── CLAUDE.extra.md # Behavioral instructions (synced downstream)
├── settings.json # Upstream-managed: permissions baseline, env, model, plugins
├── settings.local.json # Per-repo: hooks, MCP enables, additional permissions
└── scripts/ # statusline.sh, statusline_enhanced.sh
.codex/
├── config.toml # Codex settings: model, approval policy, features, MCP
├── hooks.json # SessionStart + PreToolUse hook definitions
├── rules/default.rules # Starlark command policies (ported from Claude deny list)
├── agents/ # 5 sub-agent TOML files (generated from klaude-plugin/agents/)
└── scripts/ # session-start.sh, pretooluse-bash.sh
.github/
├── scripts/ # template-cleanup.sh, template-sync.sh, bootstrap.sh
├── workflows/ # template-cleanup, template-sync, docs
└── template-state.json # Sync manifest and variables
docs/ # MkDocs site + internal design docs
├── overrides/ # Template overrides (home.html, main.html)
├── assets/ # CSS (tokyonight.css, extra.css), JS
├── getting-started/ # Setup guides
├── user-guide/ # Skills, profiles, MCP, config, sync
├── providers/ # Claude Code and Codex specifics
├── contributing/ # ARCHITECTURE.md, TESTING.md, plugin dev
├── about/ # License, changelog
├── adr/ # Architecture decision records
├── wip/ # In-progress feature design docs (excluded from search)
└── done/ # Completed feature docs (excluded from search)
mkdocs.yml # MkDocs Material config
requirements.txt # Python deps for docs site
cmd/
├── vendor-profiles/ # Profile vendoring tool
└── generate-kodex/ # Codex plugin generation tool
test/
├── helpers.sh # Shared test utilities and assertions
├── test-*.sh # 8 test suites
└── fixtures/ # Test manifests and templates