- Code quality is very important. Do not compromise on quality to deliver a result--if you don't know a good way to do something, ask. Also, whenever you need to make an architectural decision, come up with a few ideas and ask for feedback before implementing anything.
- This project is in Rust. Always write Rust code unless explicitly asked. Follow the conventions in [STYLE.md](STYLE.md).
- It is fine to finish only part of a task. It is far more important to accurately represent your progress than to succeed.
- Commit frequently and in general use git operations to your advantage (e.g. by reverting commits rather than manually undoing changes).
- When you create or resolve a TODO, adjust TODOS.md to reflect your changes. You should also update TODOS.md if you try to implement a TODO but hit a blocker or unexpected difficulty.
- Don't make changes to the code that aren't necessary for the current task. If you see something that you think should be changed but isn't in scope for the current task, just make a TODO about it.
- Reuse code and use external dependencies heavily. Before implementing something, make sure that it doesn't already exist in the codebase, and consider if there's a library that can be imported instead of implementing it yourself. We want to be able to maintain the minimum amount of code that gets the job done, even if that means introducing dependencies. If you don't know of a library but think one might be plausible, search the web. (I'm even open to using random GitHub projects, but run anything that's not a well-established library by me first so I can check if it's likely to be reliable.)
- Use the power of the type system to constrain your code and provide some assurance of correctness. If you need the result of an operation that has a precondition (e.g. unsigned subtraction requiring `a >= b`), encode the result in a type that proves the precondition was met, rather than e.g. `#[allow]`ing the operation or using `checked_sub` + `unreachable!`. For example, use `NonZeroUsize::new(a.checked_sub(b)?)` and match on `Some`/`None` — the `NonZeroUsize` then proves the difference is positive without any manual proof obligation. If some required property can't be guaranteed by the type system, it should be runtime checked (i.e. explode if it fails) and should have a corresponding unit test. For mathematically impossible cases that can't (yet) be prevented by the type system, use `unreachable!()` with a TODO about investigating type-system solutions. See `src/error.rs` for details.
- Numerical correctness: integer `+`, `-`, `*`, `/` panic in debug and silently wrap in release. For arithmetic on computation-size values (precision bits, term counts, bit lengths), use the `sane_arithmetic!` macro, which automatically uses checked arithmetic. For other integer arithmetic where you cannot prove overflow is impossible, use `checked_*` and handle the `None` case. See `src/sane.rs` for details. Do not use `wrapping_*`, `saturating_*`, or `overflowing_*` — silently wrapping or clamping a numerical result will almost certainly introduce correctness bugs.
- To reiterate: code correctness and quality is the most important concern here.
- Include a `Co-authored-by: <agent name>` trailer on commits you create (e.g., `Co-authored-by: Codex`).
- Always run `cargo test` before completing a task. Run `cargo clippy && cargo fmt` before creating a pull request.
- If the repo state starts out as dirty or you have any other reason to believe another agent might be working in parallel with you, do your work in a new git worktree. When you're done, clean up the worktree and either (a) if you're confident the task was completed correctly, merge it into main; or (b) report the branch you were working on and its status.