|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to coding agents collaborating on this repository. |
| 4 | + |
| 5 | +## Mission |
| 6 | + |
| 7 | +Element 0 is a small, embeddable Lisp dialect inspired by Scheme, implemented in Zig. |
| 8 | +The interpreter (Elz) is designed to integrate into Zig applications as a scripting engine. |
| 9 | +Priorities, in order: |
| 10 | + |
| 11 | +1. Correctness and R5RS compliance where applicable. |
| 12 | +2. Clean, minimal public API for embedding into Zig projects. |
| 13 | +3. Maintainable and well-tested code. |
| 14 | +4. Cross-platform support (Linux, macOS, and Windows). |
| 15 | + |
| 16 | +## Core Rules |
| 17 | + |
| 18 | +- Use English for code, comments, docs, and tests. |
| 19 | +- Prefer small, focused changes over large refactoring. |
| 20 | +- Add comments only when they clarify non-obvious behavior. |
| 21 | +- Do not add features, error handling, or abstractions beyond what is needed for the current task. |
| 22 | + |
| 23 | +## Repository Layout |
| 24 | + |
| 25 | +- `src/lib.zig`: Main public API export module for embedding Elz as a library. |
| 26 | +- `src/main.zig`: REPL entry point (`elz-repl` binary). |
| 27 | +- `src/elz/core.zig`: Core value types, Environment, and Module definitions. |
| 28 | +- `src/elz/interpreter.zig`: Main `Interpreter` struct. |
| 29 | +- `src/elz/eval.zig`: Evaluation engine. |
| 30 | +- `src/elz/parser.zig`: S-expression parser. |
| 31 | +- `src/elz/env_setup.zig`: Environment initialization and FFI setup. |
| 32 | +- `src/elz/ffi.zig`: Foreign function interface for calling Zig functions from Element 0. |
| 33 | +- `src/elz/gc.zig`: Garbage collection wrapper (uses Boehm-Demers-Weiser GC). |
| 34 | +- `src/elz/errors.zig`: Error types. |
| 35 | +- `src/elz/writer.zig`: Value serialization and display. |
| 36 | +- `src/elz/api_helpers.zig`: Public API helper functions. |
| 37 | +- `src/elz/primitives/`: Built-in functions grouped by category (math, lists, strings, control, predicates, vectors, hashmaps, io, ports, datetime, os, modules, and process). |
| 38 | +- `src/stdlib/std.elz`: Standard library written in Element 0 itself. |
| 39 | +- `examples/zig/`: FFI examples showing how to call Zig functions from Element 0. |
| 40 | +- `examples/elz/`: Element 0 script examples. |
| 41 | +- `tests/`: Element 0 language-level tests (`test_stdlib.elz`, `test_advanced.elz`, `test_edge_cases.elz`, `test_regression.elz`, `test_module_lib.elz`). |
| 42 | +- `.github/workflows/`: CI workflows (tests, lints, docs, and releases). |
| 43 | +- `build.zig` / `build.zig.zon`: Zig build configuration and dependencies. |
| 44 | +- `Makefile`: GNU Make wrapper around `zig build`. |
| 45 | + |
| 46 | +## Architecture |
| 47 | + |
| 48 | +### Interpreter Pipeline |
| 49 | + |
| 50 | +Source code flows through: Parser (`parser.zig`) -> Evaluator (`eval.zig`) -> Writer (`writer.zig`). |
| 51 | +The `Interpreter` struct in `interpreter.zig` ties these together and manages the root environment. |
| 52 | + |
| 53 | +### Core / Primitives Split |
| 54 | + |
| 55 | +- `src/elz/core.zig` defines the value types and environment model. |
| 56 | +- `src/elz/primitives/` contains all built-in functions, each in a category-specific module. |
| 57 | +- New built-in functions should be added to the appropriate primitives' module. |
| 58 | + |
| 59 | +### FFI |
| 60 | + |
| 61 | +Zig functions can be registered with the interpreter via `env_setup.define_foreign_func()`. |
| 62 | +This is the primary extension mechanism for embedding use cases. |
| 63 | + |
| 64 | +### Garbage Collection |
| 65 | + |
| 66 | +Memory is managed by the Boehm-Demers-Weiser GC (`bdwgc`), wrapped in `gc.zig`. The GC is linked as a C library dependency. |
| 67 | + |
| 68 | +### Dependencies |
| 69 | + |
| 70 | +Managed via Zig's package manager (`build.zig.zon`): |
| 71 | + |
| 72 | +- Chilli: CLI framework for the REPL. |
| 73 | +- BDWGC (v8.2.12): Garbage collector. |
| 74 | +- Linenoise (v2.0): Line editing for the REPL (POSIX only). |
| 75 | +- Minish: Property-based testing framework. |
| 76 | + |
| 77 | +## Zig Conventions |
| 78 | + |
| 79 | +- Zig version: 0.15.2. |
| 80 | +- Formatting is enforced by `zig fmt`. Run `make format` before committing. |
| 81 | +- Naming: `snake_case` for functions and variables, `PascalCase` for types and structs. |
| 82 | +- Element 0 symbols use `kebab-case` (e.g., `zig-mul`, `string-length`). |
| 83 | + |
| 84 | +## Required Validation |
| 85 | + |
| 86 | +Run all test suites for any change: |
| 87 | + |
| 88 | +| Target | Command | What It Runs | |
| 89 | +|---------------------|--------------------|--------------------------------------------------------------| |
| 90 | +| Zig unit tests | `make test` | Inline `test` blocks in `src/**/*.zig` | |
| 91 | +| Property tests | `make test-prop` | Property-based tests in `tests/*_prop_test.zig` (Minish) | |
| 92 | +| Integration tests | `make test-integ` | Integration tests in `tests/*_integ_test.zig` | |
| 93 | +| Language tests | `make test-elz` | Element 0 test files in `tests/test_*.elz` | |
| 94 | +| All tests | `make test-all` | Runs all of the above | |
| 95 | +| Lint | `make lint` | Checks Zig formatting with `zig fmt --check` | |
| 96 | + |
| 97 | +For interactive exploration: `make repl`. |
| 98 | + |
| 99 | +## First Contribution Flow |
| 100 | + |
| 101 | +1. Read the relevant source module under `src/elz/`. |
| 102 | +2. Implement the smallest possible change. |
| 103 | +3. Add or update inline `test` blocks in the changed Zig module. Add Element 0 tests in `tests/` if language behavior changed. |
| 104 | +4. Run `make test-all`. |
| 105 | +5. Verify interactively with `make repl` if needed. |
| 106 | + |
| 107 | +Good first tasks: |
| 108 | + |
| 109 | +- Add a new built-in function in the appropriate `src/elz/primitives/` module. |
| 110 | +- Add a new standard library function in `src/stdlib/std.elz`. |
| 111 | +- Fix an edge case identified in `tests/test_edge_cases.elz`. |
| 112 | +- Add a new FFI example in `examples/zig/`. |
| 113 | + |
| 114 | +## Testing Expectations |
| 115 | + |
| 116 | +- Unit and regression tests live as inline `test` blocks in the module they cover (`src/elz/*.zig` and `src/elz/primitives/*.zig`). |
| 117 | +- Property-based tests live in `tests/*_prop_test.zig` and use the Minish framework. They test invariants like commutativity, roundtrip properties, and crash resistance. |
| 118 | +- Integration tests live in `tests/*_integ_test.zig` and test the public embedding API (init, evalString, FFI, error propagation, sandboxing). |
| 119 | +- Language-level tests live in `tests/test_*.elz` and are run by the interpreter itself via `make test-elz`. |
| 120 | +- No language-facing change is complete without an Element 0 test. |
| 121 | + |
| 122 | +## Change Design Checklist |
| 123 | + |
| 124 | +Before coding: |
| 125 | + |
| 126 | +1. Identify which module(s) the change touches (core, primitives, parser, eval, etc.). |
| 127 | +2. Consider whether the change requires updates to the standard library (`std.elz`). |
| 128 | +3. Check cross-platform implications if the change touches OS or I/O primitives. |
| 129 | + |
| 130 | +Before submitting: |
| 131 | + |
| 132 | +1. `make test && make test-elz` passes. |
| 133 | +2. `make lint` passes. |
| 134 | +3. Docs updated if the public API surface changed. |
| 135 | + |
| 136 | +## Commit and PR Hygiene |
| 137 | + |
| 138 | +- Keep commits scoped to one logical change. |
| 139 | +- PR descriptions should include: |
| 140 | + 1. Behavioral change summary. |
| 141 | + 2. Tests added or updated. |
| 142 | + 3. Interactive verification done (yes/no). |
0 commit comments