This file provides instructions for Claude Code when working in this repository.
- Keep code simple, explicit, and maintainable.
- Fix root causes, avoid temporary band-aids.
- Preserve user changes, never revert unrelated edits.
This project uses a pinned Rust nightly toolchain: nightly-2025-11-30. All commands go through just recipes which apply the correct toolchain automatically.
- Format:
just format - Format check:
just format-check - Lint (clippy):
just lint - Test:
just test - Full CI suite:
just ci - Run app:
just run - Run HTTP daemon:
just run-httpd
Always run these checks before committing and fix any issues:
just format— auto-fix formattingjust lint— must pass with zero warnings (-D warnings)just test— all tests must pass
If any check fails, fix the issue, then commit the fix.
Never skip just format or just lint before a commit, even for small changes.
Conventional commits: feat|fix|docs|style|refactor|test|chore(scope): description
No Co-Authored-By trailers. Update README.md features list with feat commits.
- Do not use
unwrap()orexpect()in non-test code. In test modules, use#[allow(clippy::unwrap_used, clippy::expect_used)]on the module. - Use clear error handling with typed errors (
thiserror/anyhowwhere appropriate). - Use
arbor_core::ResultExtandarbor_core::OptionExtfor.context()onResult<T, E>andOption<T>— prefer these over ad-hoc.map_err()with format strings. - Use
SessionIdandWorkspaceIdnewtypes fromarbor_core::idinstead of rawStringfor session/workspace identifiers. These are#[serde(transparent)]for wire compatibility. - Keep modules focused and delete dead code instead of leaving it around.
- Collapse nested
if/if letstatements when possible (clippycollapsible_if). - Never shell out to external CLIs (
gh,gitviaCommand::new, etc.) for GitHub API calls or operations that can be done with Rust crates. Useoctocrab,reqwest, or other Rust HTTP/API crates instead. The only acceptable use ofstd::process::Commandis where no Rust crate equivalent exists.
- Split large files by domain: types, constants, helpers, actions. Keep files under ~800 lines where practical.
- Use
pub(crate)visibility for items shared within a crate but not exported. Apply to struct fields, methods, and free functions in submodules. - Use
pub(crate) use module::*glob re-exports in parent modules to keep call sites clean after extraction. - When splitting
implblocks across files, the struct definition stays intypes.rsand method impls go in the relevant domain file.
Optional functionality is gated behind Cargo features:
- arbor-gui:
ssh,mosh,mdns(all on by default). Use#[cfg(feature = "...")]on modules, functions, and imports that depend on optional crates. - arbor-httpd:
mdns(on by default). - arbor-core:
ssh,mosh(propagated from downstream crates). - When adding a new optional dependency, use
dep:crate_namesyntax in the feature definition and mark the dependency asoptional = true. - Feature flags should be hierarchical:
moshimpliesssh.
All third-party dependency versions are centralized in the root Cargo.toml under [workspace.dependencies]. Crate-level Cargo.toml files must use { workspace = true } (with optional extra keys like features or optional). Never hardcode a version in a subcrate — add it to the workspace root first.
- Treat
git status/git diffas read-only context. - Do not run destructive git commands.
- Do not amend commits unless explicitly asked.
- Only create commits when the user asks.
When working in a worktree linked to a pull request, check .arbor/pr-comments.md for
review comments left by reviewers. This file is auto-generated by the Arbor GUI and
contains all PR review threads grouped by file path. Address unresolved comments when
they relate to your current task. Delete .arbor/pr-comments.md before merging to main.
The native GPUI desktop app (arbor-gui) is the primary UI. When adding or modifying UI features, implement in the native app first, then port to the web UI (arbor-web-ui). This ensures the native app stays the reference implementation and avoids drift between the two.
When adding or modifying UI, use screencapture -x /tmp/screenshot.png to take a screenshot and verify the result visually. Run the app with just run, capture, then inspect the image.
- Use
git-clifffor changelog generation (config:cliff.toml). CHANGELOG.mdis generated for release artifacts instead of being tracked in git.just changelog/just changelog-file <path>/just changelog-unreleased/just changelog-release <version>
| Crate | Description |
|---|---|
arbor-cli |
Command-line interface (arbor binary) for scripting and automation |
arbor-core |
Worktree primitives, change detection, agent hooks, shared types (SessionId, WorkspaceId, ResultExt) |
arbor-daemon-client |
HTTP client for talking to arbor-httpd |
arbor-gui |
GPUI desktop app (Arbor binary) |
arbor-httpd |
Remote HTTP daemon (arbor-httpd binary) |
arbor-mcp |
MCP server for AI agent integration |
arbor-mosh |
Mosh shell backend (optional) |
arbor-ssh |
SSH shell backend (optional) |
arbor-terminal-emulator |
Terminal emulation layer |
arbor-web-ui |
TypeScript dashboard assets + helper crate |
| File | Contents |
|---|---|
main.rs |
App entry point, ArborWindow struct and its impl blocks, GPUI rendering |
actions.rs |
actions!() macro definitions |
constants.rs |
All const values, font registration |
types.rs |
Struct/enum definitions (DTOs, UI state types) |
helpers.rs |
Free functions, impl blocks for helper methods |
terminal_runtime.rs |
Terminal backend traits and impls (SSH, Mosh, local) |
| File | Contents |
|---|---|
main.rs |
Server startup, router setup |
types.rs |
AppState, config types, API error types |
routes.rs |
All route handler functions |