Building a Clojure Agent Environment
Table of Contents
- 1. Executive recommendation
- 2. How the pieces fit together
- 3. What is actually deployed
- 4. Comparison of existing tools
- 5. Ranked stack
- 6. The failure modes, and what actually addresses each
- 7. A
.claude/layout - 8. A verification ladder that has been calibrated
- 9. Skills are not scarce — they are invisible to the way I looked
- 10. The gap nobody is filling
- 11. Across the Lisp family
- 12. Adoption plan
- 13. Related
1. Executive recommendation
Build the environment in two layers and do not confuse them.
The lower layer is deterministic and has nothing to do with language models:
a parser that can repair delimiters, a formatter, a linter, and a running
nREPL. It is cheap, it is boring, and it is the layer that actually prevents
the failure this whole subject is about. The upper layer is agent-facing
context — CLAUDE.md, skills, hooks, an MCP server — and it is worth
nothing on top of a missing lower layer.
The evidence for putting it that way is in §3: across 93 Clojure
projects on this machine, clj-kondo configuration appears in 20 and
delimiter repair in 2. The upper layer is better provisioned than the lower
one, which is exactly backwards.
Minimum viable stack, in the order it should be adopted:
- A hook that repairs delimiters on every write. One line of configuration.
clj-kondoand a formatter, which most projects here already have.- One long-lived nREPL the agent can evaluate against.
CLAUDE.mdnaming the above, so an agent knows the REPL exists.- Only then: an MCP server, if the extra tools earn their tokens.
2. How the pieces fit together
Distinguishing official capability from community tooling matters here, because the community tools are configured through the official mechanisms and inherit their constraints.
2.1. Supplied by the agent (official)
| mechanism | what it is | lifetime |
|---|---|---|
CLAUDE.md |
project instructions, loaded into context every session | always resident |
| skills | a directory with SKILL.md, loaded on demand by description match |
loaded when relevant |
| slash commands | user-invoked entry points | on invocation |
| hooks | shell commands the harness runs at lifecycle points | every matching event |
| MCP servers | external processes exposing tools over a protocol | while connected |
| subagents | separate context windows with their own tool sets | per delegation |
The distinction that governs design: CLAUDE.md costs context on every turn,
skills cost context only when their description matches, and hooks cost no
context at all. A hook is the only one of these that is deterministic — it
runs whether or not the model decided to invoke it.
That asymmetry is the whole argument for putting delimiter repair in a hook
rather than in a skill. A skill that says "always balance your parentheses" is
a request. A PreToolUse hook is a guarantee.
2.2. Supplied by the community
Four integration models, and they are not interchangeable:
- Hook-shaped. A binary the harness invokes on write. Deterministic, no
context cost, no model involvement.
clj-paren-repair-claude-hook,brepl. - CLI-shaped. A command the model calls through
bash. Costs a tool call, works with any agent that has a shell.clj-nrepl-eval,clj-paren-repair. - MCP-shaped. A server exposing typed tools. Richest, most expensive in
tokens and setup, and overlaps whatever the harness already does natively.
clojure-mcp,nrepl-mcp-server. - Prompt-shaped. Text, nothing more.
clojure-system-prompt.
3. What is actually deployed
Surveys of this subject list what exists. The more useful question is what a
working Clojure shop has actually adopted, so the audit below walked every
project under two GitHub orgs carrying a deps.edn, project.clj,
shadow-cljs.edn or bb.edn.
| layer | check | present |
|---|---|---|
| agent context | CLAUDE.md |
20 / 93 |
| agent context | .claude/skills/ |
10 / 93 |
| deterministic | clj-kondo configuration |
20 / 93 |
| deterministic | clojure-lsp configuration |
1 / 93 |
| deterministic | formatter configuration | 14 / 93 |
| runtime | nREPL or CIDER in deps | 22 / 93 |
| deterministic | delimiter-repair hook | 2 / 93 |
| tools | MCP server configured | 0 / 93 |
Three readings.
The cheapest control is the least adopted. Delimiter repair is one line of configuration and it is the direct answer to the failure mode every survey names. Two projects have it.
Linting is not the same as indexing. clj-kondo at 20 and clojure-lsp at
1 means the corpus checks its code but gives an agent no symbol index to
navigate with. An agent without clojure-lsp does what a reader without an
index does: greps.
Twelve projects have a REPL an agent could use and no CLAUDE.md to mention
it. That is the widest gap between capability and reachability in the corpus,
and it costs nothing to close. It is also a clean instance of Norman's gulf of
evaluation: the capability is present and documented, and the presentation
makes it unreachable.
3.1. A note on how this table was produced
The first two runs of the audit were wrong, and both errors were caught by one assertion — this repository must report an nREPL, because it ran cider-nrepl twenty minutes ago.
- BSD
grep -qs pat f1 f2 f3exits non-zero when any named file is missing, even when another matched. The first run reported delimiter repair and nREPL presence at zero across the whole corpus. - Passing a flag where a pattern was expected left
grepwith a pattern and no file, so it read the enclosing loop's standard input and silently truncated the run at 32 of 93 rows. The totals looked plausible.
A count is not evidence until something in the corpus is known in advance and the count agrees with it.
4. Comparison of existing tools
| project | model | maturity | licence | capability | limitation |
|---|---|---|---|---|---|
clojure-mcp TESTED |
MCP | 778★, v0.5.1 | EPL-2.0 | eval, form-aware edit, paren repair, deps inspection | self-described alpha; overlaps native edit tools |
clojure-mcp-light TESTED |
hook + CLI | 189★, v0.2.2 | EPL-2.0 | delimiter repair on write; CLI nREPL eval | no structural editing |
brepl |
hook + CLI | 70★, v2.7.1 | see repo | bracket fix via parmezan, eval, live file sync | overlaps the above; pick one |
clojure-system-prompt |
prompt | 44★ | MIT | REPL-first conventions as text | no enforcement |
nrepl-mcp-server |
MCP | 37★ | none stated | eval, namespace inspection | last pushed 2025-06; no licence |
awesome-clojure-llm |
index | 24★ | none stated | curated list | a list, not a tool |
clojure-skills |
skills | 12★ | see repo | paren repair, eval, LSP integration as skills | skills are advisory, not enforced |
lisplens |
CLI + MCP | 3★ | MPL-2.0 | token-efficient polyglot Lisp editing | small, young |
forj |
MCP + hooks | 2★ | none stated | agent teams, checkpoints, gates | no licence; very young |
The no licence column matters more than the star count. Three of these projects ship without one, which means no grant of rights — fine for reading, a problem for anything a business depends on.
The star counts above are the weak signal, and a better one exists.
The sibling survey github-skills-search crawled the Clojure AI ecosystem on the same day
this note was written: two hops from four seed repositories to 743 users and
180,255 star edges, yielding 118 candidates with a structured card each. Its
ranking uses independent co-stars — cohort users who starred a repository,
excluding those recruited through an engagement with that same repository.
Without the correction a seed's own contributors inflate its count by
construction; one project in that survey drops from 62 raw co-stars to 3
independent ones.
That survey also had to solve a problem this note did not notice: since 2026-06-30 GitHub restricts stargazer and watcher lists to repository admins, so a cohort cannot be built from who starred a thing. It is built from public engagement instead — contributors, fork owners, issue and pull-request authors.
Two things it found that the table above misses entirely.
ECA (editor-code-assistant/eca, 1,011 stars) is the flagship product written in Clojure in this space — an editor-agnostic coding assistant, second by independent co-stars across the whole cohort. It is a peer of the harness, not a plugin for one, which is why a survey organised around "what can I add to Claude Code" does not surface it.
There are eight or more Clojure MCP SDKs, a category this note omits by
framing MCP as something to consume rather than something to build. Co-stars
favour the early entrants — modex, mcp-clojure-sdk — while the newer
plumcp (client and server, Clojure and ClojureScript, OAuth 2.1, all
transports, used by ECA and Nubank) and mcp-server (RokLenarcic) are the more
complete. Worth knowing before writing an MCP server by hand.
4.1. Where this note disagrees with its sources
Two LLM-generated surveys of this question were available. Both are useful and both contain errors that would have cost time.
The hook schema is wrong in one of them. It gives
"matchers": [{"tool": "Edit|Write"}]. Claude Code takes a singular matcher
string. Copying the survey produces a hook that sits in settings.json
looking configured and never fires — the worst failure mode available, since
it is invisible. The tool's own README has the correct shape.
The alpha claim checks out. The same survey flags clojure-mcp as alpha;
its README says so directly at line 475. Recorded because a claim that
survives checking deserves the same note as one that does not.
5. Ranked stack
5.1. Tier 0 — before anything else
CLAUDE.md naming how to start the REPL, and a running nREPL. Without these
the remainder is decoration. Twelve projects in the audit have the second and not
the first.
5.2. Tier 1 — deterministic, cheap, adopt immediately
A delimiter-repair hook on PreToolUse and PostToolUse for Write|Edit;
clj-kondo; a formatter. This tier costs no context and no tokens, and it is
where the actual guarantee lives.
5.3. Tier 2 — runtime feedback
A CLI nREPL client the model can call through bash. This is the cheapest way
to make claims executable, and it works under any agent with a shell rather
than only under one harness.
5.4. Tier 3 — MCP, on the author's own terms
The most useful guidance here is upstream's, and it is more specific than
either survey that recommended the tool. clojure-mcp's README says to start
with clojure-mcp-light, because a CLI assistant already has good
inline-diff editing and shell tools, and that this "works well for most
Clojure development". It then gives two reasons to add the full server on
:cli-assist:
- Structural editing as a fallback. The light sibling repairs delimiters after an edit succeeds, but cannot help when a find-and-replace match string does not match the code — quantified upstream at under 5% of edits. Structural editing targets a form by type and name, so the problem does not arise.
- A first-class REPL tool. Models "tend to use MCP tools more readily than CLI commands", which may raise how often the REPL is consulted at all.
That second reason is the interesting one, because it is a claim about model
behaviour rather than capability. clj-nrepl-eval and clojure_eval do the
same thing; the argument is that one gets reached for and the other does not.
It is exactly the sort of claim the ecosystem has no way to check — see the
evaluation gap below.
So the two tools are complementary rather than alternatives, which settles the disagreement between the two surveys: the one recommending the light sibling first was reading upstream correctly, and the one calling the full server the foundation was not wrong to want it, only wrong about the order.
5.5. Tier 4 — multi-agent orchestration
Defer. The projects here are young and unlicensed.
6. The failure modes, and what actually addresses each
| failure | why it happens | what fixes it | kind |
|---|---|---|---|
| unbalanced delimiters | the model edits text, not forms | repair hook on write | deterministic |
| edit lands in the wrong form | line-based patching has no notion of a form | structural edit tool | tool-assisted |
| invented API | training data, not this codebase | evaluate it in the REPL | runtime |
| stale assumption about state | the file is not the running system | evaluate it in the REPL | runtime |
| silent breakage of a caller | no symbol index | clojure-lsp |
deterministic |
| green gate, broken behaviour | the gate was never run against a known-bad input | calibrate the gate | discipline |
The last row is the one no tool supplies. See §8.
7. A .claude/ layout
.claude/
settings.json hooks: paren repair on Write|Edit, both Pre and Post
skills/
clojure-repl/ how to reach the REPL here, and what to evaluate first
clojure-test/ run the focused test, then the namespace, then the suite
clojure-review/ what to check that a linter cannot
CLAUDE.md the REPL address, the aliases, the tier boundaries
.clj-kondo/config.edn
.lsp/config.edn
The split: CLAUDE.md carries what is true every turn and nothing more;
skills carry procedures with a trigger; settings.json carries what must
happen whether or not the model agrees.
8. A verification ladder that has been calibrated
| step | gate | on failure |
|---|---|---|
| 1 | parses | hook repairs the write before it lands |
| 2 | formatted | formatter rewrites |
| 3 | lints | clj-kondo reports |
| 4 | loads | (require 'ns :reload) in the REPL |
| 5 | tests | run the focused test first |
Step 1, run rather than asserted:
known-bad (defn f [x] (inc x) -> updatedInput: (defn f [x] (inc x)) known-good (defn f [x] (inc x)) -> no output at all tool absent from PATH -> exit 1, naming the install step
The middle line is what makes the first line mean something. If balanced input also produced output, a check that greps for the repair would pass against a hook that does nothing.
The runtime half, against a live nREPL:
$ clj-nrepl-eval -p 42527 "(+ 1 2 3" => 6
The input is missing a delimiter. The client repaired it and evaluated it. That single line exercises both halves of the lower layer at once.
9. Skills are not scarce — they are invisible to the way I looked
The audit in §3 counted .claude/skills/ directories in two GitHub
orgs and found 10 of 93. A skill-specific crawl of GitHub, run the same day,
found 1,251 repositories holding 4,414 skill directories. Both numbers are
correct. They measure different things, and the gap between them is the
finding.
Dedicated skill repositories barely exist — topic:claude-skills clojure
returns 1, topic:agent-skills clojure returns 3. Skills live inside other
repositories, where a repository-level search cannot see them, and where my
directory-existence check only sees them if I happen to be standing in the
right tree.
Three consequences.
Large Clojure products already ship skills. Penpot (60k stars) carries
nrepl-eval. Metabase (49k) carries clojure-eval, clojure-review,
clojure-write and add-malli-schemas. Defold ships clojure-code-style for
its editor; XTDB ships xtdb-testing and xtdb-object-boundaries. Shipping a
skill is now part of how a large Clojure codebase onboards an agent, and the
practice is further along than a survey of one person's repositories suggests.
Skills propagate, and nobody is tracking provenance. Metabase's three skills
appear in 19 to 31 other repositories — forks, dotfiles, and marketplaces
including aiskillstore and awesome-omni-skill. Nearly half of all matched
skill directories, 47.8%, sit in eight or more registry repositories that
mirror them in bulk. A skill is a Markdown file that tells an agent what to
do, it copies as easily as a dotfile, and one of the places Metabase's skills
turn up is a malicious-skill benchmark. That is a supply chain with no
provenance layer, and this note has nothing to offer about it.
The center of gravity is narrower than the volume suggests. Among classified skill names, REPL and evaluation is the largest single group at 55 of 768. Everything else is specific — a library, a frontend framework, a house style. The generic "Clojure skill" is rarer than the count implies.
9.1. Why this correction is worth keeping
The crawl committed six predictions before running and falsified two of its own, including the one about how many repositories it would find. A survey that can be wrong about its own subject in a way it records is worth more than one that cannot, and it is the practice this note's verification ladder is trying to import.
10. The gap nobody is filling
The landscape survey's strongest negative finding: evaluation is the largest gap in this ecosystem. There is no benchmark for Clojure code generation, the one effort at a fine-tuning dataset was abandoned in 2023, and apart from one project requiring a Rama cluster there is no maintained evaluation tooling.
That matters for everything above. Every recommendation in every survey of this subject — including this note — rests on plausibility and on small local checks. Nobody can currently answer whether adding an MCP server changes outcomes, whether a delimiter hook reduces failed edits by a measurable amount, or whether a skill fires when it should. The tools are good and the evidence that they help is anecdote.
There are early signs of a measurement culture — skill A/B tests, benchmark receipts, an encrypted challenge suite — but they are per-project, not shared. Until that changes, the honest framing of a recommended stack is this is what the people building the tools believe, not this is what works.
11. Across the Lisp family
| dialect | delimiter repair | live runtime | index | what differs |
|---|---|---|---|---|
| Clojure | mature | nREPL | clojure-lsp |
best provisioned by a wide margin |
| ClojureScript | shared | shadow-cljs / piggieback | shared | the REPL is the hard part, not the editing |
| Common Lisp | ad-hoc | SLIME/SWANK | none agent-facing | the runtime is excellent and unreachable |
| Scheme, Racket | ad-hoc | varies | Racket has one | fragmented across implementations |
| Emacs Lisp | native to the editor | the editor is the runtime | none | the agent is outside the thing that has the REPL |
| Fennel, Janet | none found | none found | none | the tooling does not exist yet |
The generalisable part: delimiter repair is a parsing problem and ports across the family almost unchanged; live runtime access is a protocol problem and does not port at all. Clojure's advantage is nREPL, not its parentheses.
12. Adoption plan
- Today. Add the repair hook. One line, no context cost.
- This week. Calibrate it — feed it an unbalanced form and watch it fire. An uncalibrated hook is indistinguishable from no hook.
- This week. Add
CLAUDE.mdto the twelve projects that have a REPL and no note saying so. - Next.
clj-kondowhere missing;clojure-lspanywhere an agent navigates rather than reads. - Then. A CLI nREPL client, so claims become executable under any harness.
- Only then. MCP, on a minimal profile, and measure whether the extra tools change outcomes.
- Not yet. Multi-agent orchestration.
13. Related
- Shared REPL as Gossip Protocol — the multi-machine case for one long-lived REPL.
- Claude Code Features: 2026 Q2 — what the harness supplies natively.
- CLI Coding Agents: 2026 Q2 — the comparison this assumes.
github-skills-search(aygp-dr) — the crawl this note leans on for ecosystem shape: 118 candidates, independent co-stars, a card per project.- Advanced Clojure — one nREPL server that CIDER and Calva can both connect to.