Guidance for AI assistants (Claude Code, Gemini, Codex, etc.) collaborating on this repository.
Read this file first, then load the relevant skills for your current task. project-structure.md, development-commands.md, code-style.md, tests.md, and defensive-programming.md are the default set for most Core work. Load error-handling.md when touching error surfaces or JSON access, architecture.md when changing provider/repository/UniFFI patterns, common-issues.md when debugging tricky failures, and swapper-checklist.md only for swapper integrations.
- Project Structure — Repo layout, crates, and tech stack
- Development Commands — Build, test, lint, format, mobile
- Code Style — Formatting, naming, imports, code organization
- Error Handling — Error types, propagation, JSON access
- Architecture — Provider/mapper, repository, RPC, UniFFI patterns
- Tests — Test conventions, mocks, integration tests
- Defensive Programming — Safety rules and exhaustive patterns
- Common Issues — Known anti-patterns and their fixes
- Swapper Checklist — Integration checklist for swapper providers
Before finishing a task:
- Review for simplification — reduce duplication, extract helpers, consolidate modules, remove dead code
- Keep changes minimal — code must be concise and focused; reviewers cannot realistically review thousands of lines per PR, so only include what is necessary for the task
- Run tests:
just testorjust test <CRATE> - Run clippy:
cargo clippy -p <crate> -- -D warnings - Format:
just format
- Do not write tolerance-based assertions against live network values or values recomputed from separate RPC/API calls in integration tests. These tests are flaky and low-signal.
- For integration tests, assert stable invariants only. For exact numeric behavior, cover the pure calculation in unit tests with deterministic inputs.
- Write one test function with many assertions instead of many separate single-assertion test functions. Group related cases into a single
test_<function_name>test.
- Put reusable mocks in a crate
testkitfile and attach them to the type withimpl Type { pub fn mock() -> Self }. - Use
mock()for the default case; usemock_with_*or a clearly named variant only when needed. - Keep mocks small, valid, and fixed. If a fixture is only used once, an inline literal is fine.
Mock example:
impl Asset {
pub fn mock() -> Self {
Asset::from_chain(Chain::Ethereum)
}
}Examples: