rsclaw 2026.6.26

AI Agent Engine Compatible with OpenClaw
# Contributing to RsClaw

Thanks for the interest. This file is the **human-oriented** quick-start. The full engineering bible — architecture, internal abstractions, what RsClaw is and isn't — lives in [AGENTS.md](AGENTS.md). Read that before any non-trivial work.

---

## Ground rules

- **Branch**: work on `dev`. `main` is for releases — never push to it directly. Tags `vX.Y.Z` (CLI) and `app-vX.Y.Z` (desktop) are cut from `main` once `dev` is stable.
- **License**: by submitting code you agree it's dual-licensed under MIT **OR** Apache-2.0 — same terms as the rest of the project.
- **Identity scope**: RsClaw is an agent product, not a multi-provider LLM gateway. Read the "Identity" section of [AGENTS.md]AGENTS.md before adding features that "feel gateway-shaped" (vault, tiered pricing, cross-provider routing exposed to clients).
- **Don't introduce abstractions or scope on speculation.** A bug fix doesn't need a refactor. Three similar lines beats a premature trait. If the task is small, the PR is small.

---

## Setup

```bash
git clone https://github.com/rsclaw-ai/rsclaw.git
cd rsclaw
git checkout dev

# Rust 1.91+
rustup show          # confirm toolchain
```

System deps (only what you'll touch needs to be installed):

- `protoc` — Linux: `apt install protobuf-compiler` · macOS: `brew install protobuf` · Windows: `choco install protoc`
- `ffmpeg` — only for voice channels / TTS
- Chrome — only for browser-automation features (rsclaw will install one if absent)

---

## Build

**Always `cargo brd`** (alias for `cargo build --profile release-dev`):

```bash
cargo brd                                    # default
RUST_LOG=rsclaw=debug cargo run -- gateway run
```

Why not `cargo build` or `cargo build --release`?

- `cargo build` (debug) is too slow for the agent loop — tail latencies blow up and you'll waste hours chasing phantom perf regressions.
- `cargo build --release` (publishing profile) costs ~10 min cold. Reserve for actual release builds.
- `release-dev` is optimized but with debug-info — fast enough to behave like prod, fast enough to iterate.

Restart a running gateway after a rebuild:

```bash
./target/release-dev/rsclaw gateway restart      # uses your dev binary
# (do NOT `cargo run -- gateway restart` — that re-enters cargo, debug profile, slow)
```

---

## Test

**Never `cargo test --lib` without a name filter.** Some tests (e.g. `store::redb_store::tests::upgrades_v2_database_to_v3_*`) historically `current_exe()`-self-spawned and fork-bombed the host. This is fixed under `cfg(test)` since `0f54a02`, but the discipline stands — running the full suite blindly is rarely what you want, and a filter:

- catches the test you care about in seconds
- isolates expensive integration tests
- works on Windows / macOS / Linux uniformly

```bash
cargo test --lib store::redb_store::tests::upgrade
cargo test --lib agent::memory::tests::
cargo test --lib provider::rsclaw
```

For CI parity (full suite), use the release-cli.yml flow on a tag push — local `cargo test --all` on macOS can hit CJK-font panics absent on CI runners (and vice versa).

---

## Code style

- **Comments**: write the *why*, not the *what*. Don't reference the current task / PR / issue — that belongs in the commit message and rots in the code.
- **No emojis in source** unless the user asks for them on a UI string.
- **No multi-paragraph docstrings**. One line max.
- **Error handling**: only validate at system boundaries (user input, external APIs). Trust internal callers and framework guarantees.
- **No feature flags or back-compat shims for hypothetical futures**. If the API is changing, change it; clean up the call sites.
- **CJK safety**: never `&s[..n]` for truncation — panics mid-CJK-char. Use `crate::util::truncate_str`. (Background: [feedback_cjk_safe_truncate]docs/lang/ — swept 36 sites in `ae11ddc`.)
- **Tools field**: never move tool definitions from the LLM request's `tools:` field into messages-as-text. It tanks tool-calling quality.

---

## Commits

Conventional-commits-ish format, scope optional but encouraged:

```
fix(memory): extractor must preserve user's language (no auto-translate)
fix(cmd/gateway): missing CommandExt import broke Windows release build
ci: explicit rustup target add to work around dtolnay action regression
feat(provider/rsclaw): v1.9 user_tools wire — base/user tool segment split
chore(deps): bump tokio from 1.49 to 1.50
```

Body (optional) explains the *why* and the constraint, not the *what*. Example:

```
fix(store/redb): cfg(test) guard against current_exe() fork bomb

Under `cargo test`, current_exe() resolves to the test binary — which
does NOT contain main.rs (cargo generates its own harness entrypoint).
The spawned child has no dispatch for LEGACY_REDB_UPGRADE_HELPER_ENV
and runs the FULL test suite, which re-triggers the upgrade test, which
spawns ANOTHER child — fork bomb.

In test builds, just do the upgrade in-process. We forfeit the
library-isolation guarantee, but tests run in controlled environments
where mixing v2 + v3 redb symbols isn't a concern.
```

- Don't add `Co-Authored-By` lines.
- Don't `--amend` published commits — make a new commit.
- Don't `--no-verify` on hooks.
- One concern per commit. Easier to revert, easier to review.

---

## Pull requests

1. Branch from `dev`, push your branch.
2. Open a PR against `dev`. Title = a single conventional-commit line; body = problem + approach + verification.
3. CI must pass. If CI flakes (it does — see `.github/workflows/release-cli.yml` + the dtolnay action saga in commit history), document the flake in the PR thread and re-run.
4. One reviewer LGTM minimum; two for anything touching `src/a2a/`, `src/agent/runtime.rs`, `src/store/`, `src/server/mod.rs`, or `src/provider/`.
5. Squash-merge by default. Keep merge commits for cross-cutting refactors that genuinely benefit from preserved history.
6. After merge, delete the branch.

### What needs explicit pre-discussion (open an issue first)

- New protocol surfaces (A2A method extensions, custom WebSocket frames)
- New core dependencies (anything that pulls 50+ transitive crates)
- Behavior changes that break config-file compatibility
- Changes to `tests/fixtures/baseline-*.json` (these anchor the rsclaw-llm KV prefix cache — coordinate with the fleet team)
- Anything in `src/a2a/relay.rs` — hub-spoke topology has subtle invariants

---

## Reviewing

If you're reviewing someone else's PR:

- Verify the build (`cargo brd`) and the relevant test (with a filter) actually pass.
- Read the diff with the question: "what's the smallest change that would also pass the test?" — if the PR is larger, ask why.
- Don't sit on stale PRs. Decline + explain is better than ghosting.
- Suggest, don't dictate. Style preferences are not blockers; correctness, safety, and architectural fit are.

---

## Releasing (maintainers)

Releases are dual-tagged. For version `X.Y.Z`:

```bash
git checkout dev
# verify tests; bump Cargo.toml [package].version if needed
git push origin dev:main                # FF dev → main
git tag vX.Y.Z app-vX.Y.Z               # both tags at the same commit
git push origin vX.Y.Z app-vX.Y.Z
```

Pushing the tags triggers `release-cli.yml` (binary tarballs for mac/linux/windows × arm64/x86_64) and `release-desktop.yml` (DMG / DEB / EXE). After the workflows finish, the `update-tap` job auto-updates [`rsclaw-ai/homebrew-tap`](https://github.com/rsclaw-ai/homebrew-tap) Formula and Cask — `brew upgrade rsclaw` picks it up.

To publish to crates.io:

```bash
cargo publish --dry-run       # sanity-check packaging
cargo publish                 # irreversible
```

---

## Questions

- 🐛 Bug or unclear behavior — open an [Issue]https://github.com/rsclaw-ai/rsclaw/issues with a minimal repro.
- 💡 Design idea or RFC — start a [Discussion]https://github.com/rsclaw-ai/rsclaw/discussions or open an issue tagged `design`.
- 💬 Community channels — [WeChat / Feishu / QQ / Telegram]https://rsclaw.ai/en/community.

Thanks for showing up.