/clojure-write
Guide Clojure and ClojureScript development using REPL-driven workflow, coding conventions, and best practices. Use when writing, developing, or refactoring Clojure/ClojureScript code.
$ npx -y skills add metabase/metabase --skill clojure-write --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/clojure-write
Context preview
The summary Claude sees to decide when to auto-load this skill.
Guide Clojure and ClojureScript development using REPL-driven workflow, coding conventions, and best practices. Use when writing, developing, or refactoring Clojure/ClojureScript code.
SKILL.md
clojure-write.SKILL.mdname: clojure-write
description: Guide Clojure and ClojureScript development using REPL-driven workflow, coding conventions, and best practices. Use when writing, developing, or refactoring Clojure/ClojureScript code.
Clojure Development Skill
Tool Preference
When `clojure-mcp` tools are available (e.g., `clojure_eval`, `clojure_edit`), **always use them** instead of shell commands like `./bin/mage -repl`. The MCP tools provide:
- Direct REPL integration without shell escaping issues
- Better error messages and feedback
- Structural Clojure editing that prevents syntax errors
Only fall back to `./bin/mage` commands when clojure-mcp is not available.
@./../_shared/development-workflow.md @./../_shared/clojure-style-guide.md @./../_shared/clojure-commands.md
REPL-Driven Development Workflow
- Start with small, fundamental functions:
- Identify the core features or functionalities required for your task.
- Break each feature down into the smallest, most basic functions that can be developed and tested independently.
- Write and test in the REPL:
- Write the code for each small function directly in the REPL (Read-Eval-Print Loop).
- Test it thoroughly with a variety of inputs, including typical use cases and relevant edge cases, to ensure it
behaves as expected.
- Integrate into source code:
- Once a function works correctly in the REPL, move it from the REPL environment into your source code files (e.g.,
within appropriate namespaces).
- Gradually increase complexity:
- Build upon tested, basic functions to create more complex functions or components.
- Compose smaller functions together, testing each new composition in the REPL to verify correctness step by step.
- Ensure dependency testing:
- Make sure every function is fully tested in the REPL before it is depended upon by other functions.
- This ensures that each layer of your application is reliable before you build on it.
- Use the REPL fully:
- Use the REPL as your primary tool to experiment with different approaches, iterate quickly, and get immediate
feedback on your code.
- Follow functional programming principles:
- Keep functions small, focused, and composable.
- Use Clojure's functional programming features—like immutability, higher-order functions, and the standard
library—to write concise, effective code.
How to Evaluate Code
Bottom-up Dev Loop
1. Write code into a file. 2. Evaluate the file's namespace and make sure it loads correctly with:
./bin/mage -repl --namespace metabase.app-db.connection
3. Call functions in the namespace with test inputs, and observe that the outputs are correct Feel free to copy these REPL session trials into actual test cases using `deftest` and `is`. 4. Once you know these functions are good, return to 1, and compose them into the task that you need to build.
Writing Docstrings
A docstring is a contract for the *caller*, not a diary for the implementer. It states what the function does, what it takes, returns, throws, and the preconditions/invariants the caller must respect. Those guarantees and requirements *belong* there — they are exactly what the caller needs surfaced in the IDE.
When you find implementation context in a docstring, the default is to **relocate it, not delete it** — move it to an inline comment at the point in the body where it is actually relevant. That context is often genuinely valuable; it is just in the wrong place (the caller should not have to read it; the implementer standing at that line should). Delete outright only when it is blather: self-congratulation, restating the obvious, or documenting a property that is the expected default.
On that last case — narrating properties like "portable across all supported appdbs" earns no sentence. If it were not portable, that is either a bug, or it means callers must handle each case themselves — and in *that* case it is the *absence* of the property that must be documented. Document deviations from expectation, not conformance to it.
Heuristic — a sentence earns its place in the docstring only if it passes both tests:
1. Rewrite test (necessary, not sufficient): if rewriting the body to a different implementation with an identical contract could make the sentence false, it describes the implementation, not the contract. Relocate it to an inline comment at the point in the body where it applies.
2. Ownership test: if the sentence states a fact about code this function does not own — a callee's behavior, a library's guarantee — it survives any rewrite trivially, which is exactly why the rewrite test alone is not enough. If this body *relies* on that fact, it is implementation context: relocate it to the call site. If nothing here relies on it, it is blather about someone else's code: delete it, and let the callee's own docstring answer for it.
Say each fact once. Duplicated prose is a stale comment in advance: when the fact changes, one copy gets updated and the rest quietly rot. This holds even within code you own — a namespace docstring that re-summarizes its own multimethods, three sibling functions carrying the same paragraph about retry behavior. Give the fact one home, and have the other places name it rather than restate it.
Multi-line docstrings are not banned — a genuinely non-obvious constraint the code had to deal with can be worth explaining. But be prudent; the failure mode is far too much detail. When tempted to write a multi-paragraph explanatory docstring, check with the user first. And prefer a *test* to prose: if a future reader thinks "that's a silly way to do it" and changes it, a test should fail and tell them why. If that breakage keeps happening, *that* is the signal a comment was warranted.
Critical Rules for Editing
- Be careful with parentheses counts when editing Clojure code
- After EVERY change to Clojure code, verify readability with `-check-readable`
- End all files with
Read more
name: clojure-write description: Guide Clojure and ClojureScript development using REPL-driven workflow, coding conventions, and best practices. Use when writing, developing, or refactoring Clojure/ClojureScript code.
Clojure Development Skill
Tool Preference
When `clojure-mcp` tools are available (e.g., `clojure_eval`, `clojure_edit`), **always use them** instead of shell commands like `./bin/mage -repl`. The MCP tools provide:
- Direct REPL integration without shell escaping issues
- Better error messages and feedback
- Structural Clojure editing that prevents syntax errors
Only fall back to `./bin/mage` commands when clojure-mcp is not available.
@./../_shared/development-workflow.md @./../_shared/clojure-style-guide.md @./../_shared/clojure-commands.md
REPL-Driven Development Workflow
- Start with small, fundamental functions:
- Identify the core features or functionalities required for your task.
- Break each feature down into the smallest, most basic functions that can be developed and tested independently.
- Write and test in the REPL:
- Write the code for each small function directly in the REPL (Read-Eval-Print Loop).
- Test it thoroughly with a variety of inputs, including typical use cases and relevant edge cases, to ensure it
behaves as expected.
- Integrate into source code:
- Once a function works correctly in the REPL, move it from the REPL environment into your source code files (e.g.,
within appropriate namespaces).
- Gradually increase complexity:
- Build upon tested, basic functions to create more complex functions or components.
- Compose smaller functions together, testing each new composition in the REPL to verify correctness step by step.
- Ensure dependency testing:
- Make sure every function is fully tested in the REPL before it is depended upon by other functions.
- This ensures that each layer of your application is reliable before you build on it.
- Use the REPL fully:
- Use the REPL as your primary tool to experiment with different approaches, iterate quickly, and get immediate
feedback on your code.
- Follow functional programming principles:
- Keep functions small, focused, and composable.
- Use Clojure's functional programming features—like immutability, higher-order functions, and the standard
library—to write concise, effective code.
How to Evaluate Code
Bottom-up Dev Loop
1. Write code into a file. 2. Evaluate the file's namespace and make sure it loads correctly with:
./bin/mage -repl --namespace metabase.app-db.connection
3. Call functions in the namespace with test inputs, and observe that the outputs are correct Feel free to copy these REPL session trials into actual test cases using `deftest` and `is`. 4. Once you know these functions are good, return to 1, and compose them into the task that you need to build.
Writing Docstrings
A docstring is a contract for the *caller*, not a diary for the implementer. It states what the function does, what it takes, returns, throws, and the preconditions/invariants the caller must respect. Those guarantees and requirements *belong* there — they are exactly what the caller needs surfaced in the IDE.
When you find implementation context in a docstring, the default is to **relocate it, not delete it** — move it to an inline comment at the point in the body where it is actually relevant. That context is often genuinely valuable; it is just in the wrong place (the caller should not have to read it; the implementer standing at that line should). Delete outright only when it is blather: self-congratulation, restating the obvious, or documenting a property that is the expected default.
On that last case — narrating properties like "portable across all supported appdbs" earns no sentence. If it were not portable, that is either a bug, or it means callers must handle each case themselves — and in *that* case it is the *absence* of the property that must be documented. Document deviations from expectation, not conformance to it.
Heuristic — a sentence earns its place in the docstring only if it passes both tests:
1. Rewrite test (necessary, not sufficient): if rewriting the body to a different implementation with an identical contract could make the sentence false, it describes the implementation, not the contract. Relocate it to an inline comment at the point in the body where it applies.
2. Ownership test: if the sentence states a fact about code this function does not own — a callee's behavior, a library's guarantee — it survives any rewrite trivially, which is exactly why the rewrite test alone is not enough. If this body *relies* on that fact, it is implementation context: relocate it to the call site. If nothing here relies on it, it is blather about someone else's code: delete it, and let the callee's own docstring answer for it.
Say each fact once. Duplicated prose is a stale comment in advance: when the fact changes, one copy gets updated and the rest quietly rot. This holds even within code you own — a namespace docstring that re-summarizes its own multimethods, three sibling functions carrying the same paragraph about retry behavior. Give the fact one home, and have the other places name it rather than restate it.
Multi-line docstrings are not banned — a genuinely non-obvious constraint the code had to deal with can be worth explaining. But be prudent; the failure mode is far too much detail. When tempted to write a multi-paragraph explanatory docstring, check with the user first. And prefer a *test* to prose: if a future reader thinks "that's a silly way to do it" and changes it, a test should fail and tell them why. If that breakage keeps happening, *that* is the signal a comment was warranted.
Critical Rules for Editing
- Be careful with parentheses counts when editing Clojure code
- After EVERY change to Clojure code, verify readability with `-check-readable`
- End all files with
Metabase is the easy, open-source way for everyone in your company to ask questions and learn from data.
Repo: metabase/metabase
Other skills on metabase.
- /add-malli-schemas
Efficiently add Malli schemas to API endpoints in the Metabase codebase with proper patterns, validation timing, and error handling
Open skill - /add-tracing
Add OpenTelemetry tracing spans to Clojure code following Metabase tracing conventions. Use when instrumenting backend code with trace coverage.
Open skill - /analytics-events
Add product analytics events to track user interactions in the Metabase frontend
Open skill - /clojure-eval
Evaluate Clojure code via nREPL using clj-nrepl-eval. Use this when you need to test code, check if edited files compile, verify function behavior, or interact with a running REPL session.
Open skill - /clojure-review
Review Clojure and ClojureScript code changes for compliance with Metabase coding standards, style violations, and code quality issues. Use when reviewing pull requests or diffs containing Clojure/ClojureScript code.
Open skill - /docs-review
Review documentation changes for compliance with the Metabase writing style guide. Use when reviewing pull requests, files, or diffs containing documentation markdown files.
Open skill

