Inspiration

Coding agents write code faster than you can read it. In Rust, where closures, iterator adapters, lifetimes and trait bounds are each a thing to learn, that leaves two bad options: accept code you do not understand, or tell the agent to avoid everything you have not learned and never learn it.

molt takes a third path. A crab grows by molting: it sheds a shell that has become too small and grows a larger one. molt treats what you can already write as your shell. It writes freely inside it, and every time the code needs something outside it, molt stops, explains, and lets the shell grow by one step. Grow your Rust, one shell at a time.

What it does

molt is a terminal coding agent for cargo projects, backed by three NVIDIA Nemotron 3 models on Nebius Token Factory.

  • Profile. molt init asks what Rust you have written (ten categories of syntax elements, plus the crates of a repository of yours with --repo). A small model judges the answers and saves a profile: each construct is known, seen or unknown.
  • Main line. You type a request at molt>. molt reads and writes files through tools, runs cargo check after each turn, shows the diff, proposes a commit message, and commits only the files it changed, only when you approve. Code made of known constructs is written in bulk and never stops.
  • Boundary. When the code needs a construct that is not known, molt writes it as one small step (at most 3 such items and 30 changed lines), stops right after it, and opens a side line. A large reasoning model explains exactly those lines, shows how the same part looks with only your profile, and answers any questions. Then you choose:
    1. Understood: keep it; the items become known.
    2. Without them: take it back and rewrite it within your profile.
    3. I'll write it: take it back; you write it, and molt checks and reviews what you wrote.
    4. Later: keep it, and explain again next time.
  • Guard rails. Every write goes through a static checker (syn) before it lands, so the model cannot slip an unknown construct past the boundary. Writes are confined to the project root; .git/ and target/ are refused. cargo runs only from an allow-list, and cargo add needs approval. The API key is read from an environment variable and never written to logs.
  • Session log. Everything molt did (tool calls, findings, choices, cargo results) is recorded as JSONL.

How we used NVIDIA Nemotron and Nebius Token Factory

molt sends each request to one of three roles, so that a request goes to a model of the size it needs. All three defaults are Nemotron 3 models served by Token Factory through its OpenAI-compatible API (https://api.tokenfactory.nebius.com/v1).

  • light: nvidia/Nemotron-3_5-Lightning (reasoning_effort: low). Judges the molt init answers into the profile (one category per request, 3 in parallel) and writes the one-line policy after choice 2.
  • generate: nvidia/nemotron-3-super-120b-a12b (medium). Writes the code through tools (read_file, write_file, edit_file, run_cargo, …), the rewrite after choice 2, the review for choice 3, and the commit message.
  • reason: nvidia/Nemotron-3-Ultra-550b-a55b (high). Explains a step, shows the same part within your profile, guides choice 3 (where to write what), and answers side-line questions.

Token Factory features molt relies on, all confirmed by molt doctor for the three models: tool calls (tool_choice: required and auto), response_format: json_schema for the profile judgement (never prose to parse), reasoning_effort, and streaming, so a long explanation is not cut off by the request timeout. molt doctor records what each model supports, and molt sends only what was confirmed.

Measured on Token Factory in a fresh cargo init project: molt init with five categories answered took 19 s. A request that stopped at a boundary (numbers.iter().map(|&x| x * x).collect(), three unknown items), was explained by Nemotron 3 Ultra, kept with choice 1, passed cargo check and was committed took 29 s. A request with no boundary took 24 s.

How we built it

Rust (2024 edition), reqwest with rustls, syn for the checker, clap, crossterm and rustyline for the terminal UI. The design is written down in PRD.md (English, with a Japanese version), and the module dependency graph in the PRD is enforced by a test. Nearly 1,000 unit tests plus integration tests. A --fake mode replays scripted model responses, so the whole pass (request → boundary → choice → cargo check → commit) runs offline in CI. Real-API tests are #[ignore] and were run against Token Factory. CI runs fmt, clippy -D warnings and test on every PR, and a release workflow builds the macOS and static Linux binaries.

Challenges we ran into

  • Making "stop after a small step" real, not a prompt wish. The checker inspects every write before it lands, counts the unknown items and changed lines, and rejects a write that exceeds the step. The model is told why and asked again; after two rejections molt stops at a boundary with what it has.
  • Macros hide code from the checker. molt parses the arguments of the std macros that take expressions and patterns, and treats any other macro call as an item that must itself be known.
  • Keeping the side line honest. Questions on the side line never enter the main line's message list, so the explanation cannot change what the agent writes next; only the choice does.

What's next

  • molt login to keep the API key in the OS keychain instead of an environment variable.
  • A profile that decays: items you have not written for a while become seen again.
  • Richer boundaries for crates and lifetimes, and a molt init --repo that also reads embedded and async code.

Built With

  • clap
  • crossterm
  • nebius-token-factory
  • nvidia-nemotron
  • reqwest
  • rust
  • rustyline
  • syn
Share this project:

Updates

Submission history