Install pre-commit:
# preferred
pipx install pre-commit
# or on Homebrew-based systems
brew install pre-commit
Note: macOS can ship a broken Python 2
pre-commitstub at/usr/local/bin/pre-commit. A pipx- or Homebrew-installed version on your PATH should take precedence.
After cloning, install the pre-commit hooks once:
pre-commit install
cljfmt-fixRuns cljfmt fix on every staged Clojure file (.clj, .cljs, .cljc)
before each commit.
git commit to proceed.cljfmt must be on your PATH (e.g. installed via
bbin: bbin install io.github.weavejester/cljfmt).# Run against all files in the repo
pre-commit run --all-files
# Run only the cljfmt hook
pre-commit run cljfmt-fix
# Run against specific files
pre-commit run cljfmt-fix --files src/foo/bar.clj
clj-kondo-lintRuns clj-kondo --lint on every staged Clojure file before each commit.
The commit is blocked if there are any warnings or errors.
--cache false to avoid JVM file-lock contention when pre-commit
parallelises the hook across multiple files..clj-kondo/config.edn so individual-file linting
works without a full classpath scan.clj-kondo must be on your PATH (e.g. installed via
bbin: bbin install clj-kondo/clj-kondo).# Run only the clj-kondo hook
pre-commit run clj-kondo-lint
# Run against specific files
pre-commit run clj-kondo-lint --files src/foo/bar.clj
Check formatting without modifying files:
bb fmt:check
Fix formatting across the whole repo:
cljfmt fix bb.edn deps.edn .lsp/config.edn .psi/startup-prompts.edn \
components extensions spec test tests.edn extensions/tests.edn
bb lint
Project-local commit checks can be wired through .psi/commit-checks.edn and
run bb tasks that fail with a non-zero exit when a check should block follow-up.
This repo defines:
bb commit-check:rama-cc
bb commit-check:file-lengths
bb commit-check:dispatch-architecture
commit-check:rama-ccRuns:
rama-cc --threshold 21 --fail-above 20 components/ bases/
This task exits with the same exit code returned by the shell command, even
when rama-cc reports zero matched files.
commit-check:file-lengthsScans components/ and bases/ for files under src/ or test/ and fails if
any exceed 800 lines.
When it fails it prints the matching files to stderr and exits non-zero.
commit-check:dispatch-architectureRuns a psi-specific dispatch architecture check for agent-session.
Current behavior:
:effect/type missing from dispatch_schema.clj:effect/type missing from dispatch_effects.cljdispatch_handlers/(:state* ctx) writes outside a small allowlist of
infrastructure namespacesThis task is intentionally narrow and project-specific so we can prove its usefulness before broadening scope or upstreaming ideas.
https://github.com/hugoduncan/psi (push to master + tags).CLOJARS_USERNAME and CLOJARS_PASSWORD (deploy token) set as GitHub Actions
secrets on the repo (Settings → Secrets → Actions).master, up to date with origin.CHANGELOG.md has a non-empty ## [Unreleased] section
(bb changelog:check to verify).bb release
This single command:
master.PATCH = (git rev-list HEAD --count) + 1.CHANGELOG.md: [Unreleased] → [MAJOR.MINOR.PATCH] - YYYY-MM-DD,
prepends a fresh [Unreleased], and updates the comparison link footer.{:version "MAJOR.MINOR.PATCH"} to bases/main/resources/psi/version.edn."release: vMAJOR.MINOR.PATCH" and tags vMAJOR.MINOR.PATCH.version.edn to {:version "unreleased"} and commits
"release: post-vMAJOR.MINOR.PATCH reset version to unreleased".master + tags to origin.Pushing the tag triggers .github/workflows/release.yml, which:
org.hugoduncan/psi).:jar launcher policy against the deployed Clojars artifact
(retries up to 8×30s for propagation).bb release and bb release:tag are re-entrant:
| Failure point | Recovery |
|---|---|
Died after stamp-changelog!, before git commit | Re-run detects stamped changelog, resumes from commit |
| Died after tag, before version reset commit | Re-run detects tag + un-reset version resource, completes reset |
| Died after version reset, before push | bb release detects local tag not on origin, goes straight to push |
| Push failed (network) | Re-run bb release — detects local tag not on origin, retries push |
If the GH Actions release job fails after Clojars deploy but before GH Release creation, re-pushing the tag is not safe (tag already exists). Instead:
workflow_dispatch on the tag, orbb build:jar + create the GH Release via gh release create.After the workflow completes:
# Verify Clojars artifact
clojure -Sdeps '{:deps {org.hugoduncan/psi {:mvn/version "X.Y.Z"}}}' \
-M -m psi.main --version
# Verify bbin install
bbin install org.hugoduncan/psi --as psi --mvn/version X.Y.Z
psi --version
bb build:lib and bb deploy can be run standalone against an already-stamped
version resource for debugging:
# 1. Temporarily stamp the version resource (do NOT commit)
echo '{:version "0.1.9999"}' > bases/main/resources/psi/version.edn
# 2. Build the library jar
bb build:lib # → target/psi-0.1.9999.jar
# 3. Deploy to Clojars (requires CLOJARS_USERNAME + CLOJARS_PASSWORD in env)
CLOJARS_USERNAME=you CLOJARS_PASSWORD=token bb deploy
# 4. Restore the version resource
echo '{:version "unreleased"}' > bases/main/resources/psi/version.edn
bb deploy auto-invokes bb build:lib if the jar is absent, so steps 2 and 3
can be combined as just bb deploy.
The GitHub Actions workflow (.github/workflows/ci.yml) runs on:
workflow_dispatch)mastermastercheck (fmt + lint)
├── clojure-test
└── emacs-test
check runs first. clojure-test and emacs-test run in parallel only
if check passes.
| Job | Tasks |
|---|---|
check | bb fmt:check, bb lint |
clojure-test | bb clojure:test (unit + extensions) |
emacs-test | bb emacs:check (byte-compile + ERT) |
Maven and Clojure deps (~/.m2, ~/.gitlibs, ~/.clojure) are cached
and keyed on deps.edn + bb.edn to speed up subsequent runs.
# All tests
bb test
# Clojure unit tests only
bb clojure:test:unit
# Clojure extension tests only
bb clojure:test:extensions
# Emacs frontend tests
bb emacs:check
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |