opencode is a terminal coding agent you start with opencode inside your Rust project folder. It reads project instructions from AGENTS.md, so you can give it the exact cargo commands, module layout, and Rust-specific rules your codebase expects. This guide shows how to configure it and run a tight Rust workflow: plan, edit, test, lint, review.
Why opencode and the Rust compiler work well together
Rust gives the agent something most dynamic languages cannot: a compiler that rejects wrong code with precise, actionable messages. opencode can run cargo check, cargo test, cargo clippy, and cargo fmt through the same terminal you use, so it gets immediate feedback on lifetimes, ownership, and trait bounds. Because Rust has no hidden runtime or reflection, the agent can reason about the code statically as it edits. AGENTS.md is the key: you can encode workspace boundaries, forbid unsafe without comments, require Result instead of unwrap, and tell it where unit and integration tests live. If you are new to the tool itself, the step-by-step guide at How to use opencode: a step-by-step guide covers the basics; the rest of this article is Rust-specific.
What to put in AGENTS.md for a Rust project
Place an AGENTS.md at the repository root. It should be short and prescriptive, not a general essay. For Rust, the most important pieces are the exact build, test, lint, and format commands; the directory conventions; and rules that prevent common Rust mistakes. A realistic example:
# AGENTS.md
## Commands
- Build: `cargo build --workspace`
- Test: `cargo test --workspace`
- Lint: `cargo clippy --workspace -- -D warnings`
- Format check: `cargo fmt --all -- --check`
## Layout
- Library code lives in `crates/`; binaries in `src/bin/`.
- Integration tests go in `tests/`, unit tests in the same file under `#[cfg(test)]`.
- Do not create new crates or features without asking.
## Rust rules
- Avoid `unsafe` unless there is no safe alternative; add a `// SAFETY:` comment.
- Prefer `&str` over `String` for function parameters that do not need ownership.
- Return `Result` from fallible functions; do not `unwrap()` in library code.
- Keep public API documented with `///`.
- Run `cargo fmt` before finishing a task.
Keep the file updated as the project evolves. opencode reads it at the start of a session, so a changed AGENTS.md takes effect on the next run.
A tight edit, test, lint loop with opencode
Start opencode in the project root. Give it one focused task at a time instead of a broad request. Ask it to show the diff before applying changes if you want to review first. After each change, have it run the relevant cargo commands and paste the output. A reliable loop is:
- Describe the change and the acceptance criteria.
- Let the agent edit the code.
- Ask for
git diffand read the changes. - Run
cargo testandcargo clippythrough the agent. - Approve or ask for a smaller revision.
Example prompts for common Rust tasks:
- Add a new public function
parse_configtosrc/config.rsthat returnsResult<Config, ConfigError>and add unit tests for valid and invalid input. - Refactor
src/main.rsto extract argument parsing into a separate module usingclap; keep behavior identical and runcargo testafter the change. - Fix the borrow checker error in
src/parser.rs: the iterator borrowsinputwhile the loop mutates the same buffer. Propose a minimal change and explain why it satisfies lifetimes. - Run
cargo clippyon the workspace, fix all warnings without changing public APIs, and show the diff before applying. - Change the error type in
src/error.rsfromBox<dyn Error>to athiserror::Errorenum; update all?sites and add a test that matches on the variant.
The more precise the prompt, the less likely the agent is to wander into a large unrelated refactor.
Where opencode shines on Rust and where to double-check
opencode is strong at mechanical, well-scoped Rust work: adding trait implementations, updating Cargo.toml versions, splitting modules, converting match to if let, and writing unit tests. It is also good at iterating on compiler errors when you paste the exact error into the prompt.
The table below lists typical Rust tasks, example prompts, and where to review the output carefully.
| Task | Example prompt | Rust-specific watch point |
|---|---|---|
| Add a trait implementation | Implement Display for ConfigError using thiserror. | It may add unneeded 'static bounds or use Box<dyn Error> instead of source(). |
| Fix clippy lints | Run clippy and fix all warnings in src/lib.rs. | Clippy suggestions like needless_range_loop can change performance or semantics if applied blindly. |
| Refactor a module | Split src/parser.rs into lexer.rs and ast.rs without changing behavior. | It may create cyclic module dependencies or move use statements incorrectly. |
| Resolve a borrow error | The compiler says value does not live long enough; propose a fix using owned data or a scoped thread. | It might sprinkle clone() everywhere or introduce Rc<RefCell<T>> where a simpler lifetime suffices. |
| Add async code | Convert this blocking function to async using tokio. | It may mix Send bounds across runtimes or miss cancellation safety. |
The two biggest pitfalls are the borrow checker and workspace feature unification. The agent sometimes tries to satisfy the borrow checker by cloning values or adding redundant lifetime annotations, which compiles but hurts performance and readability. Always ask why a lifetime was changed and whether an owned value or a different function signature would be cleaner. In workspaces, a change in one crate can activate features in another and break cargo test --workspace; insist on running the full workspace check before the task is done.
Verifying changes with cargo, clippy, and rustfmt
Never accept generated code without running the full Rust verification chain. Have opencode run:
cargo check --workspace --all-targetsto catch type and borrow errors quickly.cargo test --workspaceto run unit, integration, and doc tests.cargo clippy --workspace -- -D warningsto enforce lint cleanliness.cargo fmt --all -- --checkto keep formatting consistent.
For failing tests, ask the agent to run cargo test <test_name> -- --nocapture and include the output in its analysis. The agent can read the compiler output and propose a fix, but you should verify that the fix addresses the root cause rather than only silencing the error. In particular, watch for changes that loosen trait bounds, change lifetimes from borrowed to 'static, or replace a concrete error type with Box<dyn Error> just to make ? work. After a task, ask for a compact summary of files changed and the commands that passed.
Running parallel Rust agents with separate worktrees
For larger Rust refactors, consider running several opencode agents in parallel with a tool like AgentVera. Each agent can work in its own git worktree, so changes to Cargo.toml or Cargo.lock never collide. When an agent finishes, a second model reviews the code and links findings to file:line, which catches missed lifetime annotations or unsafe blocks. Checkpoints let you revert a botched borrow checker fix and replay the session. Token budgets stop an agent from spending too long on a single lifetime puzzle. These controls matter because Rust compilation is strict and small mistakes cascade across the crate graph.
A short checklist for daily Rust work
opencode is a productive Rust companion when you treat it like a capable junior engineer: give it clear, small tasks; codify the project rules in AGENTS.md; and always verify with cargo and clippy. The compiler is your safety net, but code review of the diff is still on you. Start with one small refactor or test addition, then expand once the workflow feels reliable.