Imported from unclebob/AIR-J (
AGENTS.md). Install upstream withnpx skills add unclebob/AIR-J. Copyright stays with the author.
AIR-J Agent Instructions
Implementation language
- Implement AIR-J in Clojure.
- Keep the compiler and tooling JVM-native from the start.
Development process
- Use TDD.
- Write unit specs first.
- Implement only enough production code to satisfy the next failing spec.
- Refactor only after specs are green.
Test framework
- Use Speclj for unit tests.
- Put production code under
src. - Put specs under
spec. - Run specs with:
clj -M:spec
Spec structure check
- Before running Speclj specs, run speclj-structure-check.
- Use it to catch invalid Speclj nesting before test execution.
- Run it with:
clj -M:check-structure spec
- If structure check fails, fix the spec structure before running specs.
Mutation testing
- Use
clj-mutateto keep modules covered and overloaded with tests. clj-mutate --scanis an optional fast structural prepass.- The normal mutation run now reports total mutation count, covered/uncovered counts, changed mutation count, manifest presence, module-hash status, and differential surface area at the top of the run.
- Use
clj -M:mutate src/.../file.clj --scanonly when you want a quick structural read without running the full coverage/spec-backed mutation work. - Run mutation testing against the source file you changed.
clj-mutatenow defaults to differential mutation once a file already has an embedded footer manifest.- That means
clj -M:mutate src/.../file.clj --max-workers 3is usually a changed-top-level-forms run on previously mutated files. - Differential mutation is the preferred default workflow.
- Use
--since-last-runwhen you want to be explicit about that differential behavior. - Do not run full-file mutation with
--mutate-allunless the user explicitly requests it. - Run mutation testing with
--max-workers 3. - Run mutation module-by-module sequentially. Do not run mutation jobs for multiple modules concurrently.
- If an unchanged file with a manifest is split, do not copy the parent manifest into the daughters.
- Run tests first.
- If green, update daughter manifests.
- Then continue with CRAP and differential mutation, which should be a no-op for a semantics-preserving split.
- Run it with:
clj -M:mutate src/.../file.clj --max-workers 3
- If survivors remain, add or improve specs until the important survivors are killed.
CRAP control
- Use
crap4cljto measure change risk. - Keep CRAP below
8for changed functions/modules. - Run it with:
clj -M:crap
- If a changed function exceeds the threshold, reduce complexity or add tests until it is below
8.
Coverage
- Maintain a working coverage path through the
:covalias. crap4cljandclj-mutatedepend on current coverage information.- Run coverage with:
clj -M:cov
Dependency structure
- Use
dependency-checkerto keep dependencies organized. - As the system grows, break the code into components.
- Update
dependency-checker.ednwhen component boundaries change. - Check dependencies with:
clj -M:check-dependencies
- Treat dependency violations and cycles as design problems to fix, not warnings to ignore.
Completion criteria
Do not consider a change complete until all applicable checks pass:
clj -M:check-structure specclj -M:specclj -M:covclj -M:crapclj -M:mutate src/.../changed_file.cljclj -M:check-dependencies
Tooling pinned in deps.edn
Current pinned SHAs:
clj-mutate:a95a3352cd5fe104dac8e7a5c0b97547ba5718d5dependency-checker:e8f35792434adb35fb6b99f5c3f9ab2ab24a0279speclj-structure-check:7cc804c4e99b3482ca1d8a26b735ed41751a03abcrap4clj:9f12da1b09bc1177f8f058108cf22a73bc9a97a0
Repo name corrections:
- use
crap4clj, notcrap4j - use
speclj-structure-check, notspeclj-structure-checker