jolt/CLAUDE.md
Yogthos 67e642bdfb core.match: regex + array patterns (full support); library-conformance directive
Finishes core.match — its full test suite (115/115) now passes, including the
two patterns the earlier work left out:

- Regex-literal patterns. A #"…" now reads as a regex VALUE (Clojure parity: the
  reader constructs the Pattern, so a macro receives a regex, not jolt's tagged
  form), and the analyzer compiles a regex value to the same :regex IR leaf via
  its source. emit-quoted handles a quoted regex; a regex value carries the
  java.util.regex.Pattern host tag so extend-protocol/instance? dispatch on it.
- Primitive-array patterns. A ^Type hint's :tag is now the SYMBOL (e.g. `ints`),
  matching the JVM, so core.match's array-tag lookup engages the array
  specialization (alength/aget). jolt's :tag consumers already tolerate a symbol
  (hc-cell-num-ret normalizes; tag->nkind/def-meta handle both).

Also: a library-conformance directive in CLAUDE.md, and the supported-libraries
list (docs + site) simplified to one-line entries — a listed library is assumed
to work fully, so no tallies or feature enumerations. core.match + transit-jolt
added to the list.

Seed change (reader/backend/30-macros) -> re-minted; the rest runtime. JVM-
certified corpus rows; the stale `symbol hint -> :tag` divergence is dropped from
the allowlist (jolt now matches the JVM). make test + shakesmoke green.
2026-06-25 00:46:10 -04:00

8.4 KiB

Project Instructions for AI Agents

This file provides instructions and context for AI coding agents working on this project.

Beads Issue Tracker

This project uses bd (beads) for issue tracking. Run bd prime to see full workflow context and commands.

Quick Reference

bd ready              # Find available work
bd show <id>          # View issue details
bd update <id> --claim  # Claim work
bd close <id>         # Complete work

Rules

  • Use bd for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
  • Run bd prime for detailed command reference and session close protocol
  • Use bd remember for persistent knowledge — do NOT use MEMORY.md files

Architecture in one line: issues live in a local Dolt DB; sync uses refs/dolt/data on your git remote; .beads/issues.jsonl is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.

Session Completion

When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.

MANDATORY WORKFLOW:

  1. File issues for remaining work - Create issues for anything that needs follow-up
  2. Run quality gates (if code changed) - Tests, linters, builds
  3. Update issue status - Close finished work, update in-progress items
  4. PUSH TO REMOTE - This is MANDATORY:
    git pull --rebase
    git push
    git status  # MUST show "up to date with origin"
    
  5. Clean up - Clear stashes, prune remote branches
  6. Verify - All changes committed AND pushed
  7. Hand off - Provide context for next session

CRITICAL RULES:

  • Work is NOT complete until git push succeeds
  • NEVER stop before pushing - that leaves work stranded locally
  • NEVER say "ready to push when you are" - YOU must push
  • If push fails, resolve and retry until it succeeds

Build & Test

No build step — bin/joltc runs off the checked-in seed (host/chez/seed/). The gate is pure Chez (+ Clojure for the JVM oracle).

bin/joltc -e EXPR                          # run a Clojure expression on Chez
make test                                  # FULL gate (self-host + corpus + unit + smoke + certify)
make corpus                                # conformance corpus vs the JVM-sourced spec (floor 2678)
make unit                                  # host-specific unit cases (test/chez/unit.edn)
make selfhost                              # bootstrap fixpoint (rebuild == checked-in seed)
make certify                               # JVM oracle (skips if clojure absent)
chez --script host/chez/run-corpus.ss      # the corpus gate directly; JOLT_CORPUS_LIMIT=N for a fast stride
make remint                                # re-mint the seed after a seed-source change

Re-mint after changing a seed source. The reader (host/chez/reader.ss), the analyzer/IR/backend (jolt-core/jolt/*.clj), or the clojure.core overlay (jolt-core/clojure/core/*.clj) are baked into the seed — change one and run make remint (iterates host/chez/bootstrap.ss to a byte-fixpoint) or make selfhost fails. Runtime-only host/chez/*.ss shims do NOT need a re-mint.

Run the gate with a REAL exit code. make test > /tmp/gate.out 2>&1; echo "EXIT: $?" — the final OK: all gates passed line must be present. CI (.github/workflows/tests.yml) runs make test on every push/PR.

Architecture Overview

Clojure on Chez Scheme — the sole substrate. A small Chez runtime (host/chez/*.ss: value model, persistent collections, seqs, vars/ns, host interop) hosts a portable Clojure overlay (jolt-core/): the reader/analyzer/IR/backend (jolt-core/jolt/) and clojure.core in dependency-ordered tiers (jolt-core/clojure/core/NN-*.clj, loaded in order: 00-syntax, 00-kernel, 10-seq, 20-coll, 25-sorted, 30-macros, 40-lazy, 50-io). The stdlib namespaces (clojure.string/set/walk/edn/pprint/…) are portable Clojure under stdlib/clojure/.

bin/joltc (host/chez/cli.ss) loads the checked-in seed (host/chez/seed/{prelude,image}.ss) + the spine and compiles+evals on Chez (read → analyze → IR → emit → eval). host/chez/bootstrap.ss rebuilds that seed from source on pure Chez; the build is a self-hosting fixpoint (a rebuild reproduces the checked-in seed byte-for-byte — make selfhost). The correctness oracle is the JVM-sourced conformance corpus (test/chez/corpus.edn, test/conformance/).

Issue tracking and design notes live in beads (bd prime, bd memories).

Library conformance

When a real Clojure library's tests pass on Jolt, treat the docs/specs/tests update as PART OF THE SAME WORK — not a follow-up. In the change that lands the fixes:

  • Add JVM-certified corpus rows (test/chez/corpus.edn) for every general gap the library shook out — the corpus is the executable contract. Verify each via make test's certify step.
  • List the library in BOTH the in-repo docs/libraries.md AND the website (jolt-lang.github.io, resources/md/libraries.md) — one line (name + a short description + any load note like JOLT_FEATURES clj). Do NOT enumerate what works or paste test tallies; a listed library is assumed to work fully, so only list it once it does.
  • Update the affected prose docs and RFCsdocs/host-interop.md for new interop surface, docs/spec/*.md / docs/rfc/* for semantics, docs/MODULES.md if files moved.
  • File a bead for each remaining gap so it's tracked.

The supported-libraries list (docs + site) and the corpus are the public record of what Jolt runs — keep them current as libraries land.

Conventions & Patterns

  • A tier may only use macros from tiers that load before it. Compile mode expands macros at tier LOAD, so an if-let (30-macros) inside a 20-coll fn breaks compiled init even though it passes when expanded lazily. Same ordering for expander-called fns (empty?/keys/vals live in 00-syntax).
  • Never read your own wrapper's fields with get in attached-ops values (sorted colls): get on the wrapper IS the dispatched lookup and recurses forever. Use jolt.host/ref-get.
  • Map literals with :jolt/type as a key parse as tagged reader forms — don't tag overlay value maps in source.
  • The compiler is reached from the runtime by var-deref string lookup. The .ss runtime calls into the cross-compiled compiler with (var-deref "jolt.analyzer" "analyze") etc., and the compiler resolves its own unqualified jolt.host/… refs the same way against host-contract.ss. So a public defn with no in-Clojure callers may still be a live entry point — don't treat it as dead. Only a private defn- with no callers is safe to remove.
  • A native clojure.core fn is a (def-var! "clojure.core" "name" …) in a host/chez/*.ss; the rest of core is the overlay (jolt-core/clojure/core/*.clj). A few natives are re-asserted in post-prelude.ss so they win over the overlay. See docs/MODULES.md for where a given fn lives, and docs/seed-overlay-registry.md for the shadowing rule. Start at docs/MODULES.md to find a feature's files.
  • Fix latent bugs to match Clojure rather than preserving them, with a regression case. Match the JVM (or provide a superset); the JVM-sourced corpus is the contract.
  • Gate every change: make test with a real exit code (self-host fixpoint, corpus floor, unit, cli smoke, certify). Re-mint if a seed source changed.

Writing style (comments, docstrings, docs)

Write like a human maintainer of a serious open-source project. Plain, terse, factual. Document how the code works now — what it does and why it matters.

  • No LLM tells: drop "Note that", "It's worth noting", "Importantly", "simply", "essentially", "in order to", "under the hood", and marketing words ("comprehensive", "robust", "seamless", "leverage", "powerful").
  • No historical exposition (how the code used to work, porting notes, "the prior X"), no internal issue IDs (jolt-xxxx) or milestone tags ("Phase N") in comments or docstrings. The git history and beads hold that.
  • Keep genuine semantic contrasts with JVM Clojure — those document real, user-visible behavior.
  • Don't restate the code; explain the non-obvious. Match the surrounding file's comment density and tone.