Thank you for considering contributing to claude-code-rust! This document provides guidelines and information for contributors.
This project follows the Contributor Covenant Code of Conduct. By participating, you agree to uphold this code.
- Use the Bug Report issue template
- Include reproduction steps, expected vs actual behavior, and environment details
- Run with
RUST_LOG=debugand include relevant log output
- Use the Feature Request template
- Check existing issues and discussions first
- Describe the problem being solved, not just the desired solution
- Fork the repository
- Create a feature branch from
main:git checkout -b feat/my-feature - Make your changes following the coding standards below
- Add or update tests as appropriate
- Ensure all checks pass:
If you have the MSRV toolchain (
cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings cargo test --all-features cargo fetch --locked1.88.0) installed, also verify:cargo +1.88.0 check --all-features
- Commit using Conventional Commits:
feat: add keyboard shortcut for tool collapse fix: prevent panic on empty terminal output - Push to your fork and open a Pull Request against
main - Fill out the PR summary, validation, and any relevant notes
Labels use a namespace: value convention so they group visually and filter cleanly.
Apply one type: label per issue or pull request. The exception is a dependency
update that also carries a security fix, which takes type: dependencies and
type: security together.
| Namespace | Values | Meaning |
|---|---|---|
type: |
bug, fix, feature, docs, refactor, security, dependencies, release |
What kind of work it is. Use bug for a reported defect and fix for the change that resolves one. |
area: |
tui, core, agent-sdk, install, ci |
Which part of the project it touches. |
status: |
triage, blocked, needs-info, discussion, wontfix |
Where it sits in the workflow. |
good first issue and help wanted stay unprefixed because GitHub uses them to
populate the repository contribution page.
Issue templates apply type: and status: triage automatically, Dependabot
applies type: dependencies plus the matching area: label from
.github/dependabot.yml, and the weekly Dependency Monitor workflow applies
type: security to the advisory issue it opens. Renaming any of those labels
requires updating that config in the same change.
- Rust 1.88.0+ (install via https://rustup.rs)
- npm for contributor JavaScript tooling and package scripts.
- Bun for source runs, bridge runtime checks, and release packaging validation.
The Agent SDK bridge must be built before the app can spawn it:
git clone https://github.com/srothgan/claude-code-rust.git
cd claude-code-rust
npm ci --prefix agent-sdk
npm run build --prefix agent-sdk
cargo run
# Run with debug logging
RUST_LOG=debug cargo runSee Development for release-mode source builds, the bundled Bun runtime layout, and manual bridge overrides.
These match the core checks in .github/workflows/pr.yml:
# Formatting
cargo fmt --all -- --check
# Linting
cargo clippy --all-targets --all-features -- -D warnings
# Tests
cargo test --all-features
# Lockfile integrity
cargo fetch --locked
# Cargo dependency policy
cargo deny check bans licenses sources advisories
# MSRV (requires the 1.88.0 toolchain)
cargo +1.88.0 check --all-featuresAdditional GitHub-only checks include the separate PR title lint workflow, CodeQL analysis, path-aware package layout validation, scheduled cross-platform smoke tests, and release packaging validation.
Release workflow changes are maintainer-owned and should preserve the package architecture described in docs/src/architecture.md.
Repository protection, workflow permission, and release approval policy are documented in docs/src/governance.md.
Important invariants:
- The root npm package must not use
postinstallor install-time binary downloads. - The root npm package owns the
claude-rsbin throughbin/claude-rs.js. - Native binaries and private Bun runtimes live in platform-specific optional npm packages.
- Platform packages must not expose their own npm
claude-rsbin; otherwise npm can link the payload package over the root resolver. - Platform packages must publish before the root package for a given version.
- npm publication must use Trusted Publishing, not a checked-in token or
NPM_TOKEN. - npm and GitHub Release publication must pass through the
npm-releaseenvironment approval gate. - Release artifacts should be generated, verified, packed, and smoke-tested before publication.
For local package-layout validation, use the platform mapping in scripts/shared/npm-package-config.mjs rather than duplicating package names in docs:
npm ci
npm ci --prefix agent-sdk
npm run build --prefix agent-sdk
node scripts/npm/generate-npm-packages.mjs
node scripts/npm/verify-npm-packages.mjs
node scripts/npm/smoke-npm-package-install.mjs --platform <platform> --real-binary --no-system-runtime
node scripts/npm/smoke-npm-package-install.mjs --platform <platform> --registry-smoke --real-binary --no-system-runtimeDo not trigger releases, create tags, or publish npm packages from contributor PRs.
- Formatting: Use
rustfmt(configured viarustfmt.toml) - Linting:
cargo clippymust pass with zero warnings (configured viaclippy.tomlandCargo.toml[lints.clippy]) - Naming: Follow Rust API Guidelines
- Error handling: Use
thiserrorfor library errors,anyhowin main/app - Comments: Only where the logic isn't self-evident
- License headers: Every new
.rsfile should include// SPDX-License-Identifier: Apache-2.0
The project is split into a Rust binary and an in-repo TypeScript bridge:
src/
├── main.rs # Entry point – CLI parsing, tokio runtime + LocalSet
├── agent/ # Bridge spawning, NDJSON client, wire types, event handling
├── app/ # Application state, event loop, config, permissions, input
└── ui/ # Ratatui widgets – chat view, markdown, diffs, footer, themes
agent-sdk/
└── src/ # TypeScript NDJSON stdio bridge wrapping @anthropic-ai/claude-agent-sdk
How the pieces connect:
main.rsboots atokio::task::LocalSet(required because the bridge child process handles are!Send) and hands control toapp::run_tui.agent::client::BridgeClientspawnsagent-sdk/dist/bridge.jsas a child process and communicates over NDJSON on stdin/stdout.- The Rust side sends
CommandEnvelopes (start session, submit prompt, permission responses, …) and receivesEventEnvelopes (assistant messages, tool calls, errors, …). app/ties everything together: it owns theAppstate, routes terminal events and bridge events throughtokio::sync::mpscchannels, and drives the TUI render loop.ui/is a pure rendering layer built on Ratatui + Crossterm (cross-platform).
By contributing, you agree that your contributions will be licensed under the Apache-2.0 license, the same license as the project.