This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file takes precedence over session summaries. When a session is restored from a compressed summary, the summary may contain incorrect interpretations of processes defined here. Always re-read and follow this file as written — do not rely on the summary's framing of what a process means or what the user intended.
This project uses Nix flakes for development. All commands must be run
inside nix develop or prefixed with nix develop -c. The .envrc auto-loads
the nix shell via direnv.
nix develop -c rainix-sol-prelude
nix develop -c rainix-rs-prelude
nix develop -c rainlang-preluderainlang-prelude generates metadata files needed by the Solidity build (runs
BuildAuthoringMeta.sol, then rain meta build to produce CBOR-encoded
deflated meta).
# Solidity
nix develop -c rainix-sol-test # forge test (all tests)
nix develop -c rainix-sol-static # slither + forge fmt check
nix develop -c rainix-sol-artifacts # build artifacts
# Run a single Solidity test
nix develop -c forge test --match-test "testFunctionName"
nix develop -c forge test --match-contract "ContractName"
# Rust
nix develop -c rainix-rs-test # cargo test
nix develop -c rainix-rs-static # cargo fmt --check + cargo clippy
nix develop -c test-wasm-build # WASM compilation check
# Docs
nix develop -c forge doc -b # Solidity docs
nix develop -c cargo doc # Rust docsBuildAuthoringMeta.solexports raw ABI-encoded authoring meta tometa/rainlang-preluderunsrain meta buildto CBOR-encode and deflate the metanix develop -c forge script --silent ./script/BuildPointers.soldeploys contracts in local EVM, extracts function pointer tables, and writessrc/generated/*.pointers.solnix develop -c forge buildcompiles everything using the generated pointers
After forge build, check for warnings. Address all warnings before proceeding
to pointer rebuild, tests, or the next task.
The src/generated/ directory contains build-time generated constants (bytecode
hashes, function pointer tables, parse meta). These are regenerated by
BuildPointers.sol.
After any source change affecting bytecode: run
nix develop -c rainlang-prelude →
nix develop -c forge script --silent ./script/BuildPointers.sol →
nix develop -c forge fmt, then run LibInterpreterDeployTest to get new
deploy addresses/codehashes. Update LibInterpreterDeploy.sol and repeat until
stable (constants cascade through the deploy chain).
-
RainlangParser (
src/concrete/RainlangParser.sol) — Converts Rainlang text to bytecode. Uses bloom filter + fingerprint table for word lookup. -
RainlangStore (
src/concrete/RainlangStore.sol) — Sandboxed key-value storage. Namespaced bymsg.sender+StateNamespace. -
RainlangInterpreter (
src/concrete/RainlangInterpreter.sol) — Stack-based evaluation runtime. Entry point:eval4(). Dispatches opcodes via function pointer tables. -
RainlangExpressionDeployer (
src/concrete/RainlangExpressionDeployer.sol) — Coordinates parse → integrity check → serialize. ImplementsIParserV2. -
Rainlang (
src/concrete/Rainlang.sol) — On-chain registry and single discovery point for the deployer, interpreter, store, and parser. External tooling discovers all component addresses by querying a single known Rainlang address.
All five are deployed to deterministic addresses via Zoltu deployer. Addresses
and code hashes are in src/lib/deploy/LibInterpreterDeploy.sol. Deploy
constants cascade: parser → expression deployer → Rainlang. Interpreter changes
also cascade to Rainlang.
Each opcode is a library in src/lib/op/<category>/ with three functions:
run(Operand, Pointer stackTop) → Pointer— Runtime executionintegrity(IntegrityCheckState, Operand) → (inputs, outputs)— Pre-execution validation- Operand handler — Parses operand bytes during parsing
All opcodes are registered in src/lib/op/LibAllStandardOps.sol which maintains
four parallel arrays (authoring meta, operand handlers, integrity pointers,
opcode pointers). The ordering must be consistent across all four arrays.
External contracts can extend the interpreter with additional opcodes.
src/concrete/extern/RainlangReferenceExtern.sol is the reference
implementation. Externs implement IInterpreterExternV4 and have their own
function pointer tables.
- cli — CLI tool (
rainlang-cli) - eval — Evaluation runtime using REVM/foundry-evm
- parser — Rust parser implementation
- dispair — Dispatch pair utilities
- bindings — Alloy Solidity contract bindings
- test_fixtures — Shared test fixtures (deploys all contracts on local Anvil)
script/Deploy.sol uses the DEPLOYMENT_SUITE env var to select which
component to deploy: "parser", "store", "interpreter",
"expression-deployer", or "rainlang".
- Solidity version: exactly
0.8.25, EVM targetcancun - Optimizer: enabled, 1000000 runs
- Fuzz runs: 2048
- Source of truth for these settings is
foundry.toml - License:
LicenseRef-DCL-1.0with copyrightRain Open Source Software Ltd - Custom bytecode serialization is used instead of ABI encoding for gas efficiency
- Function pointer dispatch (no switch/if chains) for opcode routing
- Assembly blocks are used extensively and marked
memory-safewhere applicable - NatSpec: when a doc block contains any explicit tag (e.g.
@title), all entries must be explicitly tagged — untagged lines continue the previous tag, not implicit@notice
Testing patterns and conventions are in TESTING.md. Read that file before
writing tests.
- Test files are in
test/mirroringsrc/structure, suffixed.t.sol - Rust test fixtures (
crates/test_fixtures/) deploy all five contracts on a local Anvil instance - Always run test commands with
run_in_background: trueso work continues in parallel - While background builds or tests run, continue with other work that doesn't depend on the build result — e.g. triage presentation, code review, documentation edits
Jidoka is a priority: process correctness (correct future) over ad hoc progress (present state). Quality at the source enables throughput; skipping quality steps creates rework and slows overall flow. Process introspection takes precedence over following the process.
Each fix is a complete cycle: understand → write test → run test (confirm fail)
→ write fix → run test (confirm pass) → run full suite → verify. Do not move to
the next item with incomplete work. New code must meet the same audit
requirements defined in the /audit skill — a fix that introduces untested
error paths, missing NatSpec, or other audit findings is not complete.
When fixing bugs, follow TDD: write a test that reproduces the bug, run it to confirm it fails, then write the fix and run the test again to confirm it passes. Do not write the fix before running the test and confirming it reproduces the bug.
When the user says "jidoka," they are signaling a process defect. The response is:
- Identify the process defect.
- Propose a durable fix (document edit, rule change).
- Stop and wait for agreement. Do not resume task work, run commands, or do anything else. The process fix is the deliverable of that moment.
When the user asks "why" about a defect, they are asking for root cause analysis of the process failure — not requesting that you go do the thing. Answer the "why" first, agree on the process fix, then resume.
Do not claim motivations or internal states. Describe what you actually did, not a story about why. Say "I skipped the test suite run" not "I was optimizing for throughput." Say "the rule is in CLAUDE.md" not "I've internalized it." You have no metrics, no persistence, and no self-observation — narratives about your own reasoning are fabrications.
Audit instructions are available as skills: /audit (full overview),
/audit-pass0 through /audit-pass5 (individual passes), and /audit-triage
(finding triage).