Customize and automate

Publish an add-on

Lay out a collection, write an add-on's chains and skills, validate it, and publish it for other instances to install.

Added in 2.1

This guide builds a collection acme with one add-on, release, and installs it from the directory to try it. To install someone else's add-on, see Share chains with add-ons.

Before you start

  • A running Kraft server, and git.
  • A git repository to publish the collection from, if other machines will install it.
  • The instance defines every harness and agent profile the add-on requires. The example needs the shipped claude harness and strong profile.

Publish a collection

1. Lay out the collection

A collection is a directory with .kraft/collection.json at its root and one directory per add-on:

acme-kraft/
  .kraft/collection.json
  addons/
    release/
      .kraft/addon.json
      library.yaml
      chains/ship.yaml
      skills/release-notes/SKILL.md

collection.json names the collection and lists its add-ons:

acme-kraft/.kraft/collection.json
{
  "$schema": "https://kraft-sdlc.dev/schemas/collection.schema.json",
  "name": "acme",
  "description": "ACME's Kraft chains and review methods",
  "owner": { "name": "ACME Platform", "email": "platform@acme.dev" },
  "addons": [
    { "name": "release", "source": "./addons/release", "description": "Release chains" }
  ]
}

addon.json names the add-on, its version, and what it needs from an instance. "kraft": "2" means any Kraft 2.x:

acme-kraft/addons/release/.kraft/addon.json
{
  "$schema": "https://kraft-sdlc.dev/schemas/addon.schema.json",
  "name": "release",
  "version": "1.0.0",
  "description": "Release chains",
  "requires": { "kraft": "2", "harnesses": ["claude"], "profiles": ["strong"] }
}

2. Write the add-on's files

The files have the same shape as the ones in your own config/. Inside an add-on, a bare extends:, steering: or skill: names the add-on's own declaration. A bare harness: or profile: names the instance's.

An add-on holds only the files it uses. One chain, or one skill, is a valid add-on. An add-on with none of library.yaml, chains/, skills/ and profiles.yaml is refused.

A chain is named by its id, or by its file name when it has none, so the chain below is release:ship once installed. A file name is a lowercase letter, then lowercase letters, digits, _ or -. Kraft ignores chains/Ship.yaml, and validate warns about it.

acme-kraft/addons/release/library.yaml
tasks:
  implementer:
    kind: agent
    harness: claude
    profile: strong
    prompt: Implement the approved plan, then write the release notes.
    skill: release-notes
    policy:
      time_cap_minutes: 90

  test_changed_scopes:
    kind: builtin
    ref: kraft.verify_changed_test_scopes
    scope: each_repository
acme-kraft/addons/release/chains/ship.yaml
id: ship
description: Implement, write release notes, run the tests for what changed.

nodes:
  - id: implementation
    kind: exec
    tasks:
      - id: implement
        extends: implementer

  - id: verify
    kind: exec
    tasks:
      - id: test_changed_scopes
        extends: test_changed_scopes
acme-kraft/addons/release/skills/release-notes/SKILL.md
---
name: release-notes
description: Write release notes for the change in this worktree.
---

Add one line to `RELEASES.md` for each user-visible change, newest first.

An add-on cannot use a component of your local library or of another add-on: it carries everything its chains extend. It also cannot carry a subprocess task or a permission. What an add-on may set has the list.

3. Validate it

kraft admin addon validate ./acme-kraft
release 1.0.0  sha256:f915f6266d319e9c0bc2bb2483683d74f307839138258901919e7d071fd37da4

validate runs the checks an install runs and installs nothing. It prints one line per add-on, then:

  • each problem as error: <file>: <message>. Any problem makes it exit 1.
  • each file or manifest key Kraft ignores as warning: <message>. A warning does not change the exit code.
  • when the config directory has no library.yaml, as in CI, a skipped: line that names the checks it left out.

When the config directory has a library.yaml, validate also checks the add-on against that instance: its requires, its namespace, and your own chains.

Add-on problems lists each message and its fix.

4. Try it from the directory

Add the directory itself as a collection, and install from it:

kraft admin addon collection add ./acme-kraft
kraft admin addon install release@acme

An add-on from a directory collection has an update whenever its files change, whatever its version. Edit a file, then run kraft admin addon update and accept the review. Before you add the published collection (Install an add-on), remove this one: kraft admin addon uninstall release@acme, then kraft admin addon collection remove acme.

A directory collection exists on one machine only, and never auto-updates.

5. Publish it

Commit the collection and push it to a git host. To release a change later, raise version in addon.json and push. An installed instance sees an update only when the version changes, so a push without a new version changes nothing for the people who installed it.

Tell people the collection's address and the add-on's id. They add and install it with the commands under Install an add-on.

A private repository works when git on the machine that runs the Kraft server can clone it without a prompt: an SSH key, or a credential helper, that a server run as a service can reach. Put no credentials in the URL; Kraft refuses one that has them.

Run validate in CI

Run validate on every push to the collection. validate needs no server and no config directory, so CI only installs Kraft and runs it. The job fails when validate exits 1. For GitHub Actions:

.github/workflows/validate.yml
name: validate
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pipx run --spec kraft-sdlc kraft admin addon validate .

Or share from the repository itself

A collection suits chains many repositories share. For one repository's own chains, commit them in the repository and skip the collection: a repo library is read from the repository's .kraft/ folder on its default branch, with no manifest and no install.

  1. Put library.yaml, profiles.yaml, chains/<name>.yaml or skills/<name>/SKILL.md directly in .kraft/, commit them, and merge to the default branch.
  2. A teammate runs kraft repo connect in a terminal. Connect prints a review of the library and asks whether to take it.
  3. Items filed in that repo run .kraft/chains/default.yaml with no further setup, and --chain my-repo:hotfix selects another. A later change waits until someone runs kraft repo library and takes it. The first accept asks whether later text changes may be taken automatically; see Automatic updates.

The repository's id in repos.yaml is the namespace, and an instance checks every change against the same rules as an add-on. Unlike an add-on, the library is visible only to that repository's items: another repository, your own chains and harnesses.yaml cannot name it. Repo libraries has the facts.

Serve Claude Code from the same directory

An add-on directory can also be a Claude Code plugin. Kraft reads .kraft/, library.yaml, profiles.yaml, chains/ and skills/, and nothing else in the directory:

addons/release/
  .kraft/addon.json
  .claude-plugin/plugin.json
  library.yaml
  chains/ship.yaml
  skills/release-notes/SKILL.md
  hooks/hooks.json
  .mcp.json
  • skills/ has the layout Claude Code uses, so both tools read the same SKILL.md. The skill is release:release-notes in both.
  • .claude-plugin/, hooks/ and .mcp.json never reach Kraft. It does not install the Claude Code half: do that in Claude Code.
  • An alias changes the name on Kraft's side only. An add-on installed with --as acme-release has acme-release:release-notes in Kraft and release:release-notes in Claude Code.
  • A chain of yours that already says skill: release:<name> hands that skill to the agent. Once an add-on holds the namespace release, Kraft reads the skill from the add-on, and the install review lists each such reference.

Next steps

Copyright © 2026