Contributing
ai-core-kit is a forkable standard, not a project. Contributing means improving the standard — the kit’s own tooling, its documentation, and the CHILD payload it renders into forks. This page covers the rules every contribution must respect, the conventions the linter enforces, and the workflow for adding a skill.
Before contributing files derived from another repository, read the License Ledger. Patterns are free to learn from; files are not free to copy.
The kit is dependency-free by design: the frontmatter linter and the render engine are stdlib-only Python, so the only hard requirement for most contributions is Python 3 and git. There is no build step to run before editing a primitive — a skill, agent, or command is just markdown with YAML frontmatter. The one local check you should always run before opening a PR is the frontmatter linter (§3), which CI also enforces.
1. The two-layer boundary (read this first)
The single most important rule: never conflate the META layer with the CHILD layer. See The META vs CHILD boundary for the full treatment.
| Layer | What it is | Where it lives |
|---|---|---|
| META | building the kit itself | root docs, .claude/, scripts/, telemetry/, bootstrap/ |
| CHILD | what /ack-init renders into a fork | everything under templates/ |
The conventions apply to both layers — a skill is shaped the same whether it ships in the META .claude/ or in a child template. What differs is policy:
- Design-contract-first and the contract gate are CHILD rules. They are authored here as templates plus hooks that ship into the child, never wired into the META repo. A META gate would only ever pass vacuously.
- Forkability (invariant I7): the META
.claude/tree is never copied into a child. Child hook paths use the literal${CLAUDE_PROJECT_DIR}; child template variables are${dotted.path}(snake_case, read from the manifest’smanaged:subtree). Never embedtemplates/or absolute kit paths in child-payload deliverables.
Boundary checklist for any change under templates/:
- No absolute paths and no
templates/prefix in rendered output. - Hook commands use
${CLAUDE_PROJECT_DIR}. - Template variables use
${dotted.path}resolving to the manifestmanaged:subtree. - No META-only tooling (the discovery engine,
/ack-build) leaks into the child payload.
2. Frontmatter conventions
Every Claude Code primitive is markdown with YAML frontmatter. The rules below are the canonical standard (CONVENTIONS.md) and are mechanically enforced (see §3).
Skills (SKILL.md)
---
name: my-skill # REQUIRED. lowercase-hyphenated (^[a-z0-9]+(-[a-z0-9]+)*$)
description: > # REQUIRED. third-person — WHAT it does + WHEN to use it
Do X for Y. Use when … . Trigger when … . Do NOT use when … .
license: Apache-2.0 # OPTIONAL (or "Complete terms in LICENSE.txt")
allowed-tools: Read, Bash # OPTIONAL (restrict the skill's tool surface)
---- Allowed keys, total:
name,description,license,allowed-tools. Nothing else. - Forbidden keys (the linter errors):
version,author,category,triggers,updated. They are noise the harness ignores and they drift — versioning lives in git, triggers live indescription. - The
descriptionis the trigger surface. Write it in the third person; state what it does and when to use it; include explicit trigger phrases and a when-NOT-to-use clause. - The body (after the closing
---) should stay at or under 500 lines — advisory, so the linter emits a warning, not an error. Push detail toreferences/*.md(linked one level deep),assets/, andscripts/.
Agents (.claude/agents/*.md and templates/agents/*.md)
---
name: code-reviewer # REQUIRED. lowercase-hyphenated, matches the file stem
description: > # REQUIRED. third-person, with a "use proactively when …" clause
… . Use this agent proactively when … . Trigger when …
model: sonnet # OPTIONAL. one of: haiku | sonnet | opus | inherit
tools: Read, Grep, Bash # OPTIONAL. least-privilege allowlist (omit ⟹ inherit)
---modeldefaults toinherit. Assign by cognitive load:haikufor mechanical scans,sonnetfor authoring/extraction,opusfor adversarial QA / load-bearing judgement.- One agent per focused task. Agents orchestrate skills; they do not re-implement them.
Commands (.claude/commands/*.md and templates/commands/*.md)
---
description: One-line, third-person summary of what the command does. # REQUIRED
argument-hint: "[--flag] [<arg>]" # OPTIONAL
allowed-tools: Read, Write, Bash(git status:*) # OPTIONAL
disable-model-invocation: true # OPTIONAL (human-only)
---Only description is required. Commands are thin entrypoints — orchestration logic delegates to agents and skills, it is not inlined.
3. The frontmatter linter
scripts/lint-frontmatter.py mechanically checks the rules above across .claude/agents/*.md, .claude/commands/*.md, .claude/skills/**/SKILL.md, and templates/**/SKILL.md. CI runs it; a violation exits non-zero.
# Scan the whole repo (default target is the repo root containing the script):
python3 scripts/lint-frontmatter.py
# Or scan a specific path before committing:
python3 scripts/lint-frontmatter.py templates/skills/my-skill/SKILL.mdWhat it checks:
- SKILL.md — requires
name(lowercase-hyphenated) +description; rejects the forbidden keys; rejects any key outside the allowed set; warns if the body exceeds 500 lines. - Agents — require
name+description; validatemodelis one ofhaiku|sonnet|opus|inherit; warn on unrecognized keys. - Commands — require
description; warn on unrecognized keys.
It is stdlib-only (no PyYAML) — it parses only flat top-level key: value lines, which keeps the kit dependency-free and mirrors the no-runtime-deps render engine. Errors exit non-zero; warnings do not.
Prefer running the
skill-validatorskill, which runs this linter for you and interprets every finding.
4. Adding a skill
The two META build-tooling skills exist to make authoring a kit skill reliable. Use them in order:
Step 1 — author with skill-creator
skill-creator drafts a new SKILL.md, runs with-skill vs baseline evals, grades them, and optimizes the description for reliable triggering. Use it to build a skill from scratch, refactor an existing one, or tune a description that under- or over-triggers.
Lay the skill out folder-per-skill:
templates/skills/<skill-id>/ # CHILD payload (or .claude/skills/<skill-id>/ for META)
├── SKILL.md # frontmatter + body (≤ 500 lines)
├── references/*.md # deep detail, linked ONE level deep only
├── assets/ # templates, fixtures
├── scripts/ # automation the skill calls
└── LICENSE.txt # ONLY if a file was vendored (Apache-2.0 example skills, WITH a NOTICE)Decide the layer first: a skill that helps build the kit goes in META .claude/skills/; a skill that ships into a fork goes in templates/skills/. If it ships into a fork, ensure it is wired by a manifest condition or archetype (see the Skills Catalog for wiring triggers).
Step 2 — validate with skill-validator
skill-validator runs scripts/lint-frontmatter.py and interprets every finding. Use it to check a SKILL.md (or agent, or command) before committing, to audit a freshly ported or authored primitive, and to learn the required vs forbidden keys. It judges conformance — it does not write the primitive.
Step 3 — record licensing if you vendored
If any file was copied in from an external repo, follow the vendoring checklist: keep the upstream LICENSE.txt in the skill folder and add an attribution entry to THIRD_PARTY_NOTICES.md. Never vendor the proprietary doc skills (docx/pdf/pptx/xlsx).
5. Pull request expectations
- Keep
CLAUDE.mda minimal pointer — it is loaded every turn, so bloat is a permanent token tax. Put detail in on-demand docs, not inCLAUDE.md. - Run the linter (
python3 scripts/lint-frontmatter.py) and ensure it exits zero before opening a PR. - Respect the layer boundary and the forkability invariants in §1.
- For anything derived from an external repo, confirm its license posture against the License Ledger and update
THIRD_PARTY_NOTICES.mdif a file was copied.
See also
- The META vs CHILD boundary — the full treatment of the §1 rule every contribution must respect.
- Skills Catalog — where
skill-creatorandskill-validatorlive, plus how a CHILD-payload skill gets wired into a fork. - Commands Reference and Agents Reference — the conventions for the other two primitive types.
- License Ledger — the vendoring checklist and the four reference repos’ license posture.