|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to coding agents collaborating on this repository. |
| 4 | + |
| 5 | +## Mission |
| 6 | + |
| 7 | +Zodd is a small, embeddable [Datalog](https://en.wikipedia.org/wiki/Datalog) engine written in pure Zig. |
| 8 | +It evaluates recursive rules over sets of tuples using semi-naive iteration, merge joins, and indexed extension primitives. |
| 9 | +Zodd is designed to be embedded in Zig projects as a library. |
| 10 | +Priorities, in order: |
| 11 | + |
| 12 | +1. Correctness of relations, variables, joins, extensions, and fixed-point iteration. |
| 13 | +2. Minimal public API for use as a library from other Zig projects. |
| 14 | +3. Small dependency footprint and maintainable, well-tested code. |
| 15 | +4. Cross-platform support (Linux, macOS, and Windows). |
| 16 | + |
| 17 | +## Core Rules |
| 18 | + |
| 19 | +- Use English for code, comments, docs, and tests. |
| 20 | +- Prefer small, focused changes over large refactoring. |
| 21 | +- Add comments only when they clarify non-obvious behavior. |
| 22 | +- Do not add features, error handling, or abstractions beyond what is needed for the current task. |
| 23 | +- Keep the dependency set small: do not add new Zig packages or C libraries without prior discussion. |
| 24 | + |
| 25 | +## Writing Style |
| 26 | + |
| 27 | +- Use Oxford commas in inline lists: "a, b, and c" not "a, b, c". |
| 28 | +- Do not use em dashes. Restructure the sentence, or use a colon or semicolon instead. |
| 29 | +- Avoid colorful adjectives and adverbs. Write "Datalog engine" not "blazing-fast Datalog engine", "merge join" not "efficient merge join". |
| 30 | +- Use noun phrases for checklist items, not imperative verbs. Write "redundant index detection" not "detect redundant indexes". |
| 31 | +- Headings in Markdown files must be in the title case: "Build from Source" not "Build from source". Minor words (a, an, the, and, but, or, for, in, |
| 32 | + on, at, to, by, of, is, are, was, were, be) stay lowercase unless they are the first word. |
| 33 | + |
| 34 | +## Repository Layout |
| 35 | + |
| 36 | +- `src/lib.zig`: Public API entry point. Re-exports `Relation`, `Variable`, `Iteration`, `ExecutionContext`, join helpers, and extend primitives. |
| 37 | +- `src/zodd/relation.zig`: Immutable `Relation` type (sorted, deduplicated tuples). |
| 38 | +- `src/zodd/variable.zig`: Mutable `Variable` type for fixed-point iteration, plus the `gallop` search helper. |
| 39 | +- `src/zodd/iteration.zig`: `Iteration` driver for semi-naive evaluation. |
| 40 | +- `src/zodd/join.zig`: Merge-join algorithms (`joinHelper`, `joinInto`, `joinAnti`). |
| 41 | +- `src/zodd/extend.zig`: Leaper-based extension primitives (`ExtendWith`, `FilterAnti`, `ExtendAnti`, `extendInto`). |
| 42 | +- `src/zodd/index.zig`: Indexes for keyed lookups. |
| 43 | +- `src/zodd/aggregate.zig`: Group-by and aggregation operations. |
| 44 | +- `tests/`: Non-unit tests (`integration_tests.zig`, `regression_tests.zig`, `property_tests.zig`, `incremental_tests.zig`). |
| 45 | +- `examples/`: Self-contained example programs (`e1_network_reachability.zig` through `e6_dependency_resolution.zig`) built as executables via |
| 46 | + `build.zig`. |
| 47 | +- `.github/workflows/`: CI workflows (`tests.yml` for unit and integration tests, `docs.yml` for API doc deployment). |
| 48 | +- `build.zig` / `build.zig.zon`: Zig build configuration and package metadata. |
| 49 | +- `Makefile`: GNU Make wrapper around `zig build` targets. |
| 50 | +- `docs/`: Generated API docs land in `docs/api/` (produced by `make docs`). |
| 51 | + |
| 52 | +## Architecture |
| 53 | + |
| 54 | +### Evaluation Pipeline |
| 55 | + |
| 56 | +A Datalog program flows through: base data is loaded into a `Relation` (`relation.zig`). Derived predicates use a `Variable` (`variable.zig`) driven |
| 57 | +by an `Iteration` (`iteration.zig`) loop that calls `changed()` until a fixed point. Each iteration extends tuples via `join` (`join.zig`) or `extend` |
| 58 | +(`extend.zig`), optionally using indexes (`index.zig`) or aggregates (`aggregate.zig`). Every primitive takes a `std.mem.Allocator` directly; there is |
| 59 | +no wrapper context type. |
| 60 | + |
| 61 | +### Relations and Variables Split |
| 62 | + |
| 63 | +- `relation.zig` is the immutable, sorted, deduplicated tuple container used for base facts and finalized results. |
| 64 | +- `variable.zig` is the mutable counterpart used inside fixed-point loops; it tracks stable, recent, and to-add tuple sets for semi-naive evaluation. |
| 65 | +- New join shapes go in `join.zig`. New leaper-style extensions go in `extend.zig`. |
| 66 | + |
| 67 | +### Indexing and Aggregation |
| 68 | + |
| 69 | +`index.zig` provides keyed lookups used by the extend primitives. `aggregate.zig` provides group-by reductions. |
| 70 | +When adding a new join or extension shape, consider whether it needs an index variant and add it alongside the existing ones. |
| 71 | + |
| 72 | +### Public API Surface |
| 73 | + |
| 74 | +Everything re-exported from `src/lib.zig` is part of the public API. |
| 75 | +Changes to names or signatures there are breaking. |
| 76 | +The rest of `src/zodd/` is internal and may be refactored freely as long as the public surface and its behavior are preserved. |
| 77 | + |
| 78 | +### Dependencies |
| 79 | + |
| 80 | +Zodd depends on two sibling Zig packages declared in `build.zig.zon`: |
| 81 | + |
| 82 | +- `ordered`: sorted container primitives, linked into the `zodd` module for all builds. |
| 83 | +- `minish`: property-testing framework, used only by `tests/property_tests.zig` and lazy-loaded in `build.zig`. |
| 84 | + |
| 85 | +Please do not add further dependencies without prior discussion. |
| 86 | + |
| 87 | +## Zig Conventions |
| 88 | + |
| 89 | +- Zig version: 0.16.0 (as declared in `build.zig.zon` and the Makefile's `ZIG_LOCAL` path). CI pins the version declared in `build.zig.zon`. |
| 90 | +- Formatting is enforced by `zig fmt`. Run `make format` before committing. |
| 91 | +- Naming follows Zig standard-library conventions: `camelCase` for functions (e.g. `joinInto`, `extendInto`, `fromSlice`), `snake_case` for local |
| 92 | + variables and struct fields, `PascalCase` for types and structs (e.g. `Relation`, `Variable`, `ExecutionContext`), and `SCREAMING_SNAKE_CASE` for |
| 93 | + top-level compile-time constants. |
| 94 | + |
| 95 | +## Required Validation |
| 96 | + |
| 97 | +Run the relevant targets for any change: |
| 98 | + |
| 99 | +| Target | Command | What It Runs | |
| 100 | +|----------------|------------------------------------------------|-----------------------------------------------------------------------| |
| 101 | +| Unit tests | `make test` | Inline `test` blocks in `src/` plus every file under `tests/` | |
| 102 | +| Lint | `make lint` | Checks Zig formatting with `zig fmt --check` over `src/` and `tests/` | |
| 103 | +| Examples | `make example` | Builds and runs every example under `examples/` | |
| 104 | +| Single example | `make example EXAMPLE=e1_network_reachability` | Runs one example program | |
| 105 | +| Docs | `make docs` | Generates API docs into `docs/api` | |
| 106 | +| Everything | `make all` | Runs `build`, `test`, `lint`, and `docs` | |
| 107 | + |
| 108 | +## First Contribution Flow |
| 109 | + |
| 110 | +1. Read the relevant module under `src/zodd/` (often `relation.zig`, `variable.zig`, `join.zig`, or `extend.zig`). |
| 111 | +2. Implement the smallest change that covers the requirement. |
| 112 | +3. Add or update inline `test` blocks in the changed Zig module, or extend a test file under `tests/`, to cover the new behavior. |
| 113 | +4. Run `make test` and `make lint`. |
| 114 | +5. If public behavior changed, also run `make example` to ensure no example regresses. |
| 115 | + |
| 116 | +Good first tasks: |
| 117 | + |
| 118 | +- Add a new join or extension shape in `src/zodd/join.zig` or `src/zodd/extend.zig` (with an inline `test` block and, if appropriate, an integration |
| 119 | + test under `tests/`). |
| 120 | +- Improve an existing index strategy in `src/zodd/index.zig`. |
| 121 | +- Add a new aggregate operation in `src/zodd/aggregate.zig`. |
| 122 | +- Add a new example under `examples/` demonstrating a Datalog pattern, and list it in `examples/README.md`. |
| 123 | + |
| 124 | +## Testing Expectations |
| 125 | + |
| 126 | +- Unit tests live as inline `test` blocks in the module they cover (`src/lib.zig` and `src/zodd/*.zig`). They are discovered automatically via |
| 127 | + `std.testing.refAllDecls(@This())` in `src/lib.zig`. |
| 128 | +- Non-unit tests live under `tests/` (`integration_tests.zig`, `regression_tests.zig`, `property_tests.zig`, `incremental_tests.zig`) and are |
| 129 | + auto-discovered by `build.zig`. |
| 130 | +- Property tests use the `minish` dependency and should use fixed seeds so failures are reproducible in CI. |
| 131 | +- Every new relation, variable operation, join, extension, index, or aggregate must ship with at least one `test` block that exercises it. |
| 132 | +- No public API change is complete without a test covering the new or changed behavior. |
| 133 | + |
| 134 | +## Change Design Checklist |
| 135 | + |
| 136 | +Before coding: |
| 137 | + |
| 138 | +1. Identify which module(s) the change touches (`relation`, `variable`, `iteration`, `join`, `extend`, `index`, `aggregate`, or `context`). |
| 139 | +2. Consider whether a new join or extension needs a matching index or anti-variant. |
| 140 | +3. Check whether the change is public-API-visible (i.e. re-exported from `src/lib.zig`); if so, treat it as a breaking or additive API change |
| 141 | + deliberately. |
| 142 | +4. Check cross-platform implications, especially for anything that touches the filesystem, timing, or OS-specific types. |
| 143 | + |
| 144 | +Before submitting: |
| 145 | + |
| 146 | +1. `make test` passes. |
| 147 | +2. `make lint` passes. |
| 148 | +3. `make example` still succeeds when touching relations, variables, joins, extensions, or iteration. |
| 149 | +4. Docs updated (`make docs`) if the public API surface changed, and `ROADMAP.md` ticked/updated if a listed item was implemented. |
| 150 | + |
| 151 | +## Commit and PR Hygiene |
| 152 | + |
| 153 | +- Keep commits scoped to one logical change. |
| 154 | +- PR descriptions should include: |
| 155 | + 1. Behavioral change summary. |
| 156 | + 2. Tests added or updated. |
| 157 | + 3. Whether examples were run locally (yes/no), and on which OS. |
0 commit comments