Skip to content

About

The Clojure Agent Kit (aka KIT): an opinionated, reusable method for building Clojure software with a small team of AI agents — the method, fillable plan documents, and a runnable harness.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Clojure Agent Kit (aka "KIT")

An opinionated, reusable way to build Clojure software with a small team of independent AI agents — a contract-first blueprint, an isolated dispatch loop, a living decision log, and quality gates ordered cheap-to-expensive.

Distilled from a live multi-agent build that ran this loop across dozens of real dispatches, including several it got wrong. What's here is the discipline that survived contact with those runs, not a design done on paper.

KIT is the short form of the Clojure Agent Kit, and is how these documents refer to it. It is a name, not an acronym. The application template it brings with it is ontopro/clojure-stack-lite, always named with the tag KIT pins, as in ontopro/clojure-stack-lite at tag kit-v1.3: those tags version the template, not KIT.

Clone it and build beside it. KIT is what a project adopts: its clone sits in the project's workspace next to the application it generates from a pinned template, upgraded with bb upgrade from the workspace folder - the network checked, the clone clean, the tags fetched, each newer release's requirements read from its tag and checked against the machine, the clone moved to the release, then the workspace brought up by the new version's own code, step by step, with what it leaves for the Architect said by bb doctor and bb next until resolved - and nothing of the project is written into it. The first upgrade from 0.6.4 is by hand, since 0.6.4 has no bb upgrade: git -C KIT fetch --tags && git -C KIT checkout <tag>, then bb --config KIT/harness/bb.edn upgrade --after-pull from the workspace folder. KIT carries a version tag at each plan's boundary - 0.7.1 is the current one, and the DEVLOG's heading for it says in a line what the plan added and anything a workspace made before it needs; bb init records the version beside the commit. There is no library to require; there is one commit of one template that a dated health check certifies with it.

For adopters

What is in the clone - the method, the build docs, the harness, the tools, the skills - is listed under Five parts, in the section for KIT developers below.

Before anything: Babashka and git

Important

KIT is certified on an Apple silicon Mac (macOS, arm64) and on arm64 Linux - the health records below. Its toolchain is published for amd64 Linux too, and no record proves it there yet. An Intel Mac is not supported: cljfmt, which KIT runs, publishes no build for it.

KIT installs its own toolchain. You install the two things that run it:

Install Version Route
Babashka 1.12.212 or newer - it runs KIT; the true-up adds the matrix's own bb to the project's folder only when yours is older babashka.org → install; on macOS brew install borkdude/brew/babashka
git 2.41 or newer - every read of a diff takes --attr-source, which git has from 2.41; bb doctor says an older one git-scm.com/downloads; on macOS xcode-select --install

The rest comes from bb self-check (step 4 below): a JDK (Temurin 25), the Clojure CLI, bb, cljfmt, clj-kondo, bbin and clojure-mcp-light, each at the version the download matrix names (tools/toolchain/download-matrix.edn) and checked against its sha256, into the project's toolchain folder - <xyx>/.kit/toolchain, beside the clone, or the folder KIT_TOOLCHAIN_DIR names (another disk, or one folder several projects share). About 400 MB on disk, 294 MB of it the JDK - 470 when the true-up also installs bb, which it does only when yours is older than the matrix's (the matrix's :disk-mb, each measured after a full install). The doctor's offer lists what this machine gets, each with its size, and the disk's free space, and asks first.

bb doctor holds every tool on the PATH to the matrix - the same version is ok, a newer one is said, an older one or another commit fails with the command that fixes it - and shows KIT's dated known-good set beside it (the Mac's health record, harness/health/records/macos-arm64.edn: the versions that were actually run together). Only on a machine the matrix publishes no build for is your own JDK used: 21 or newer, 25 preferred (XTDB, an optional store, documents a minimum of 21, and 2.2.0 runs on 25 with -Dio.netty.noUnsafe=false).

How to use KIT

There are basically 2 steps to use KIT:

  1. setup - to set up the KIT adopter's workspace
  2. build - to build the adopter's application

1. Set up workspace

One order, the same for a project and for developing KIT itself: Babashka and git; the project folder and the clone in it; bb self-check; the keys; the eval; then bb init.

  1. Install Babashka and git, as described in Before anything: Babashka and git above.

  2. Create project folder <xyx>. This will be the main working directory where all the work will be done.

    • recommend using a short name for the <xyx>.
    • the name must be lowercase letters, digits and single hyphens, starting with a letter - for example my-site - because bb init takes it as the project's name, and it becomes folder names and the application's namespace.
    • The only thing you put in it yourself is KIT's clone, in step 3; bb self-check and bb init make the rest.
  3. Open a terminal and cd into the newly created <xyx>. Clone this repo into it with:

    git clone https://github.com/ontopro/clojure-agent-kit.git KIT
    • KIT is a clone of the Clojure Agent Kit (aka KIT) and it will be guiding you through the product build, test and deployment process.
  4. cd into the clone and run bb self-check, the one setup command:

    cd KIT
    bb self-check
    • It points the clone's git hooks at .githooks/, and writes <xyx>/.env with the names of the keys the default profile needs, each empty - a .env already there is never touched.
    • Then bb doctor: what the project's toolchain folder lacks, with sizes, and Install? [y/N]. On y the true-up installs it; on a no, self-check stops, and bb self-check again picks up.
    • Then bb health: this KIT, this machine, the pinned template - minutes, starts JVMs.
    • It ends with the next three steps.
  5. Put this project's keys in <xyx>/.env. bb self-check wrote the names its profile needs, each empty, with what uses it and where it is sent. One key per project, with a spending limit set at the provider's console. The file is yours alone (mode 600); a .env a repository holds is refused at load; and the session's file tools are denied it (.claude/settings.json - a rail, not a lock: NOTES.md row 236). It may hold what else the application needs too - a DATABASE_URL, a PORT.

  6. Put the project's toolchain first on this terminal's PATH and load the keys:

    eval "$(bb toolchain-env)"
    • toolchain-env prints no value: it checks the .env, then prints the line that has your shell read it. A line the shell would run ($(...), a bare word) or a name a program reads its hooks from (PATH, GIT_*, BABASHKA_*...) is flagged by its line number and nothing is loaded: read it, change it, or accept the file as it is with bb env-accept. So is a name left empty (NAME=) that your shell already has set - loading it would empty the shell's: fill the line or remove it.
    • Each change it sees is noted in .env-record.edn beside it - the names added and removed, never a value - so a .env that changed when you did not change it shows.
    • With mise activated in your shell, its shims come back in front of the folder's bin/ after the eval, so a .mise.local.toml naming another JDK would win over the folder's. The application's .mise.toml names temurin-25, the matrix's major, so by default the two agree.
  7. Make the workspace, move to it, and check the profile sees the keys:

    bb init
    cd ..
    bb profile
    • By default init names the project after <xyx> (bb init <name> names it otherwise) and makes <xyx>-app and <xyx>-build plus a few other directories and files in <xyx> - always the folder the clone is in. It writes no .env: it says which names the profile needs that the file lacks, if any.
    • <xyx> is where you will be doing all the work from.

Important

The keys reach a session only through the shell that starts it. Run the eval in the terminal you start claude from, and again - with claude restarted - after you change the .env.

At this point you are all set to build your application.

2. Build the application

  • Make sure you are in the <xyx> directory, in the terminal step 6 loaded.
  • Start a Claude Code session there (claude) and type /kit-start.
  • Claude walks you through:
    • the workspace directory structure
    • the approach: the opening of KIT's method.md, then the steps in order from workflow.md
    • the roles and the models they run on - harness/roster.md has the when and why - and the model and effort it recommends for this session, the Architect's
    • the first step: scoping, stage 0's first step, in phase B, PROVE
  • At any time after, /kit-where-am-i says where the project stands - the phase, the stage, what is done and open - and reads into whichever part you pick.

Where it was last shown to work

Rendered by bb health-sync from harness/health/records/, one record per platform - its latest run, every run kept beside it under records/<platform>/ - each written by bb health --record after a run in which every check passed: the selfcheck project and an application generated from the pinned template, gates green, every gate failed on purpose, one task through the loop, the application served, a headless Firefox opening it through KIT's browser pack (tools/browser/) where geckodriver and Firefox are installed (skipped, and the row says so, where they are not), and KIT's security pack (tools/security/) trying from outside what the build docs' architecture document says the template gives, and asking about every library it ships and every line of its history. bb gates fails if this block and the records disagree. The date is the claim; nothing here says it still holds today.

Platform Run on KIT commit Template Checks Time
Linux Ubuntu 24.04.5 LTS arm64 2026-11-09 5d5fc90 kit-v1.3 (f12268d) 10 of 12 ok, 2 skipped: selfcheck gates, selfcheck red, selfcheck loop, app gates, app red, app loop, app serve, app browser, app security, app image SKIPPED, xtdb embedded, xtdb pgwire SKIPPED 99s
macOS 27.0.1 arm64 2026-11-09 5d5fc90 kit-v1.3 (f12268d) 12 of 12 ok: selfcheck gates, selfcheck red, selfcheck loop, app gates, app red, app loop, app serve, app browser, app security, app image, xtdb embedded, xtdb pgwire 179s

One record per platform actually run, the latest run on it; a platform not in the table has none. bb health --record on such a machine writes one - commit it, and bb health-sync.

Is it worth it?

It pays for itself when a project has enough scope to amortise setting the process up once, and a correctness bar worth a dedicated, independent verification step. For a weekend build or a single-session prototype, skip to a plain coder loop plus gates plus one human review — the full role model and the decision log are overhead you don't need yet.

It scaffolds on stock Clojure Stack Lite (HTMX, AlpineJS, TailwindCSS, SQLite/PostgreSQL), with XTDB v2 as a SQL-compatible alternative datastore.

Known limitations

NOTES.md is the honest state of KIT — what is deliberately deferred, and where the weak points are.

For KIT developers

Five parts

What it is
method.md The method. Five phases — Setup, Prove, Build, Pre-release, Release — each a group of stages by kind, run as one lean-agile discipline: lean decides what to build, agile decides how, and the flow is Kanban (pulled, WIP-limited, no timeboxes). Roles, the task-packet contract, the rule source, the decision log, the gate order, and a field guide of twelve lessons each bought with a real run.
build-docs/ The build docs, half-written on purpose — the source a plan derives from, an overview with a ranked risk register, requirements with MVP/post-MVP scoping, architecture and method-and-tooling each in three parts (GIVEN by adopting KIT, CHOSEN once in stage 0's plan, THEIRS the domain), the decision log, and just-in-time stage docs. bb init copies it into the project's plan repository, beside the rules overlay, the profile and the run records that repository also holds, and bb plan-check reads the filled plan before the first dispatch.
harness/ The code that runs, and its health check's first subject (health/selfcheck/, a deliberately trivial project with gates that execute and fixtures that make each fail): the doctor, bb init and the health check; the two readings of a filled plan (bb plan-check, the gate; bb plan-review, the model's pass); the packet assembler, the gate runner, gate 0 and the boundary gate, three-worktree provisioning, an API-backed runner, a per-run cost report that names the three commits it ran against, the rule source with a drift gate, a bake-off that compares candidates for a role with a judge reading blind, and the loop that drives them — stopping for a person at every branch it cannot decide. Its own README is the inventory.
tools/ Tool packs a project runs from KIT's clone, each with its own bb.edn and dependencies, against the project's own server whatever its framework — the way a project already runs the boundary gate. The first is tools/browser/: the stage-end checks in a real browser (screenshots as tall as the page with the overflow measure, an axe-core scan, the serve-check-stop skeleton), Etaoin under Babashka driving a headless Firefox through geckodriver. Beside it, tools/svg/ checks the SVG files a project draws, and tools/security/ tries from outside what a request can - the headers, the cookies, a POST without its token, the routes that need a login, the error pages, the static folders, TLS - at every stage's end and in bb health. Its README is the list.
skills/ One skill per step of the workflow that is a conversation with a person and has a defined output - kit-scoping, kit-plan, kit-stage-plan, kit-stage-end, and beside them kit-start, the orientation a project's first session begins with, and kit-where-am-i, at any time where the project stands and a guided reading into it - in one anatomy (when it runs, reads, refuses when, asks, writes, done when), each a thin layer over the method section it cites. Claude Code's mechanism, loaded from .claude/skills/: bb init renders them into a workspace's, where kit-start is the first conversation; bb skills-sync, run from the workspace folder, renders them again after an upgrade (bb upgrade runs it), and its --check in KIT's gates holds every cited heading to the method. The other seats follow the same sections by hand. Its README says the rules.

Each of the repository's own documents has one job, and none of them repeats another:

NOTES.md what is missing, weak or open now
DEVLOG.md what changed, when, and why — newest first
portability.md running KIT from a seat other than Claude Code, and the dispatch design that follows
harness/README.md the harness: what is in it, how a project adopts it, what is deliberately left out
workflow.md the method as it runs on KIT, in order — setup, then stage 0 (scope, plan, implement, deploy locally), the stages with their four steps and their reviews, the loop, pre-release and release — as one diagram and a table of steps
harness/roster.md who acts in a build — every review, gate and dispatch — from which role, on which model
CLAUDE.md working rules for an agent changing this repository

That separation is not tidiness. Two of these carried the same forward-looking list for a while and both went stale; the rule now is that a fact lives in one of them and the others link to it.

Setting up to develop KIT

The same order as a project's, with the two seats in place of bb init:

  1. Babashka and git (Before anything).
  2. A folder KIT/, and this repository cloned into it: KIT/clojure-agent-kit/. The folder above the clone holds the toolchain (KIT/.kit/toolchain) and the keys (KIT/.env), as <xyx>/ does for a project.
  3. bb self-check in the clone - the hooks, KIT/.env, the doctor with its offer, the health check.
  4. The keys in KIT/.env; eval "$(bb toolchain-env)" in the terminal that starts the sessions.
  5. .local/wording/names.txt - the project names no committed line may carry, one a line; an empty file to start. The commit check refuses every commit while it is missing, and says how.
  6. The two seats: the KIT session, claude in the clone, which writes; and the reading session, claude --agent kit-reader -n kit-reader --model fable in a tab of its own. The kit-session skill (.claude/skills/kit-session/, never shipped) is the routine they follow, and kit-security-review the KIT's own security review, run when the person asks.

Before a tag

Important

The order is the point: the containers clone HEAD and see only what is committed, so the health records are committed before the gates run on the commit the tag will name.

  1. The plan's work committed, bb kit-status read, and the tree clean.
  2. The health records on that commit: bb health --record in harness/, then bb docker-health at the root, then bb health-sync; the records and the README block committed. A record names the commit it ran on, and a tag on code its records never ran is a tag on an untried claim. They make known-good the pins: bb tag-check's versions line holds the download matrix, the pack's pins and the Dockerfile's to what the runs recorded, the JDK apart - the KIT an adopter gets has its pins equal to known-good.
  3. The tag's documents: its heading in DEVLOG.md (## <tag> — <what the plan was>), with its line - what the plan added, and anything a workspace made before it needs ("How it is versioned" there) - and this README's sentence naming the current tag.
  4. On the commit the tag will name: bb repair && bb gates green, then bb docker-gates green - the gates on a clone of that commit in the KIT's toolchain image, a fresh Linux machine in Docker with only the KIT's toolchain: the check on a fresh machine until a workflow runs it on push.
  5. The person's, by hand: bear-claw's secrets scan, a second rule set the KIT's scan does not carry; Docker Scout's scan of the KIT's toolchain image (a Docker login), docker scout cves local://clojure-agent-kit-toolchain:<as-of>-<digest> --only-severity critical,high as bb tag-check prints it, a HIGH or CRITICAL against a pinned tool moving that pin before the tag; and the KIT's pins (bb kit-pins), a go or no-go per row, a row that goes moving before the tag with its health runs.
  6. The merge, the tag and the push, by the person.

bb tag-check <tag> at the root is this list's mechanism: a line per check and no tag unless every one holds. --run does steps 2 and 4 where they are stale, stopping for the commit between them; --landed checks origin after step 6. It names step 5's scans and runs none of them.

The commands

bb self-check # from the root of the clone, the one setup command: the hooks, the .env template, bb doctor
              # with its offer to install, then - when it says yes - bb health
bb doctor     # from the root of the clone: every tool, its version, and for anything unusable
              # the command or page that fixes it. Run it, follow it, run it again - until both
              # verdicts say yes: "The KIT's gates can run here" and "A loop can run here"
bb health     # then, once: is this KIT healthy here, with the template it pins? Minutes, starts JVMs:
              # the selfcheck project and a freshly generated application, gates green, gates failed on purpose,
              # one task through the loop, the application served, a Firefox opening it (skipped, and said, with no geckodriver)
bb init       # then: the workspace, named after the folder the clone is in - see harness/README.md
bb gates      # KIT's own gates: doctor -> format -> lint -> boundary -> containment -> shell lines -> rules -> skills -> the register -> inventory -> health block -> the records (reports, stage reports, bake-offs) -> test
bb hooks-install   # the pre-commit hook, which runs `bb commit-check` - bb self-check sets it too
bb commit-check    # what the hook runs: refuse unless the last `bb gates` was green on exactly this tree, or on one
                   # differing only in DEVLOG.md/NOTES.md (the register checked), and while .local/wording/names.txt is missing
bb kit-status      # at an item's end or before a restart: the working tree, the Next line, flaky tests, stale health records, open register rows, the plan's log
bb tag-check <tag> # before a tag: the checklist above for <tag> on HEAD (--run does what is stale, --landed after the push)
bb docker-gates    # the gates on a clone of HEAD in a fresh Linux container; bb docker-health the health check there

cd harness
bb example    # the whole loop shape in one run — no model calls, no network

The root bb.edn is KIT's own task list - setup (self-check, init), the gates and the KIT's development checks - most of them handed to harness/, where the harness and the rest of its tasks live. A project runs its KIT commands from its workspace folder, through the front door bb init writes there (<xyx>/bb.edn); bb gates there runs the workspace's own checks, and bb front-door-sync writes it again; bb upgrade runs it among its steps.

bb example is the 60-second tour: it assembles a task packet, shows the Tester's context being stripped of the implementation, dispatches to a scripted runner, repairs the output, runs the gates until one fails, and checks the runner against the contract.

Where things live

  • The clone. A workspace's clone of KIT is KIT/ by the README's steps, but the name is not fixed: workspace.edn records the folder, so it may be renamed. It stays in the workspace: bb init takes no folder, the workspace is always the one above the clone.
  • The template. ontopro/clojure-stack-lite is KIT's fork of the upstream template: its kit branch is KIT's line of it, tagged kit-v1, kit-v1.1, kit-v1.2, …, and its master is an untouched mirror of the upstream.

Provenance

harness/PROVENANCE.md records what was extracted from the private harness it came from and every place this copy deliberately diverges — each with its reason. It is a fork, not a mirror; "sync with upstream" is not a supported operation, and the divergences are fixes rather than drift.

Licence

MIT. Six rules in the harness's rule source are adapted from github/awesome-copilot (MIT), and the application template KIT pins is a fork of abogoyavlensky/clojure-stack-lite (MIT); see NOTICE for the attributions and the upstream licence texts. An application generated from it carries no licence file: choosing one is its owner's first decision.

About

The Clojure Agent Kit (aka KIT): an opinionated, reusable method for building Clojure software with a small team of AI agents — the method, fillable plan documents, and a runnable harness.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages