Contributing
Thanks for looking. newt is early and changes quickly, so open an issue before starting anything large.
You need the Rust toolchain pinned in rust-toolchain.toml (1.99.1, with clippy and rustfmt; rustup installs it on first use) and Docker for Postgres.
docker compose up -d --wait # Postgres 18 on localhost:55432export DATABASE_URL=postgres://newt:newt@localhost:55432/newtexport NEWT_DATABASE_URL=$DATABASE_URLDATABASE_URLis read by the tests: each#[sqlx::test]creates a throwaway database from it and appliesmigrations/.NEWT_DATABASE_URLis the variableserver.example.tomlnames for the server’s own connection (database.url_env).
Run the server against the example config:
NEWT_CONFIG=server.example.toml cargo run -p newt-serverThe example config also needs OPENAI_API_KEY, ANTHROPIC_API_KEY and ASSISTANT_TOKEN set (any value works until a turn calls the model). The README walks through the demo.
Checks
Section titled “Checks”CI (.github/workflows/ci.yml) runs these against Postgres 18, in this order. Run them locally before you push:
cargo fmt --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspacecargo deny check # licences, yanked crates, wildcard versions, unknown registriescargo machete # unused dependenciesCI then builds the release binary, starts it with server.example.toml, waits for /healthz to return 200 and sends it SIGTERM, which must exit cleanly. cargo deny and cargo machete are installed with cargo install cargo-deny cargo-machete.
Code rules the compiler enforces
Section titled “Code rules the compiler enforces”These come from [workspace.lints] in Cargo.toml. With -D warnings, every warning below fails CI.
- No
unsafe(forbid). - No
unwrap(),panic!,todo!,unimplemented!ordbg!(deny).expect()is a warning: use it only for a true invariant and say why in the message. Tests may unwrap by opening the file with#![expect(clippy::unwrap_used, reason = "...")]. - No
println!oreprintln!(deny). Usetracing. - No holding a
Mutexguard or aRefCellborrow across.await(deny). - No
#[allow(...)](deny). Suppress a lint with#[expect(lint, reason = "...")]; the reason is required. - Clippy
allandpedanticare on. Three pedantic lints are switched off:module_name_repetitions,missing_errors_doc,must_use_candidate. - Public types implement
Debug(missing_debug_implementations). #[must_use]results must be used (unused_must_useisdeny).- Large futures,
Rc<Mutex<_>>andclone()on reference-counted pointers are warnings.
Style the compiler does not check
Section titled “Style the compiler does not check”- Errors:
thiserrorenums innewt-core,anyhowwith.context(...)innewt-server. Do not drop the source error. - Fail loudly on bad config or a bad provider response instead of falling back.
- Prefer concrete types. Add a trait only where the design already has a seam (
EventSink,Model,ToolHost,Journal). - Do not block the async runtime. Use tokio’s APIs or
spawn_blocking. - Comments only for a constraint the code cannot express.
- A new dependency needs a reason in the pull request, and
cargo deny checkmust pass.
Tests assert behaviour on inputs. A bug fix comes with a test that fails without the fix. See the README’s “Running the tests” section.
Pull requests
Section titled “Pull requests”- One change per pull request, with a description of what changed and why.
- Rebase on
mainand run the checks above first. - If you change the context-provider protocol, the MCP
_metafields or a config key, update Protocol or Configuration in the same pull request. - By contributing you agree your work is licensed as
Apache-2.0 OR MIT, like the rest of the project.
For security issues, see Security. Please follow CODE_OF_CONDUCT.md.