Skip to content

Latest commit

 

History

History
109 lines (80 loc) · 3.86 KB

File metadata and controls

109 lines (80 loc) · 3.86 KB

Contributing to Catalyst Code

Thanks for your interest in contributing! Catalyst Code is a coding-agent harness made of four cooperating components around a single stdio JSONL protocol.

Architecture at a glance

Component Language Role
core/ Rust (tokio) The engine: conversation, model streaming, tools, sessions, plugins, subagents
tui/ Go (Bubble Tea) Terminal UI; spawns core and speaks JSONL
sdk/ TypeScript Thin pi-compatible wrapper so pi-web can swap in the harness
web/ Rust (axum) Thin HTTP + WebSocket hub; spawns core and never thinks

Getting started

Build the core and TUI from the repo root:

./build.sh            # cargo --release --all-features (core) + go build (tui), in parallel
./build.sh --run      # build, then launch the TUI with that exact core

Or individually:

cargo build --release --all-features --manifest-path core/Cargo.toml   # → core/target/release/core
cd tui && go build -o catcode .                          # → tui/catcode

The web hub is a Rust crate: cargo run --manifest-path web/Cargo.toml.

Before opening a PR

Core (Rust):

cd core
cargo fmt --all -- --check
cargo clippy --all-targets
cargo test --locked

Linux source builds need WebKitGTK 4.1 + GTK 3 headers (libwebkit2gtk-4.1-dev libgtk-3-dev). Runtime also wants xvfb on headless hosts. Run /browser inside catcode if those packages are missing.

TUI (Go):

cd tui
gofmt -l .            # must be empty
go vet ./...
go test ./...
go build ./...

CI runs all of the above, so run them locally first to save a round-trip.

Code style

  • Rust: cargo fmt (rustfmt default). Avoid unwrap()/expect() on data that comes from the model, files, or the network — prefer ?/unwrap_or/ explicit error returns so adversarial input can't crash the core.
  • Go: gofmt -s. The TUI is single-threaded Update + channel-only goroutines; keep shared state behind the session model and communicate via channels/tea.Cmd, not shared mutable globals.

Security notes for contributors

  • File tools confine paths to the workspace (../absolute/symlink escapes are rejected). Don't add a path-handling tool that bypasses workspace::resolve.
  • The bash tool runs under an optional microVM sandbox (--sandbox microsandbox, --no-network). Treat the denylist as a tripwire, not a sandbox. When sandboxing is enabled, the denial-of-host-access is real (separate kernel + filesystem root).
  • Secrets: never log API keys or OAuth tokens. The set_key path logs only the provider name, never the key. Config files holding keys are written 0600.
  • Plugins from a repo's .catalyst-code/plugins/ load only with an explicit --trust-project-plugins opt-in — never read that flag from a config file a repo could ship.

Sandbox subsystem

The Microsandbox integration lives in core/src/sandbox/ (backend, manager, preflight, setup, policy, error) behind a microsandbox cargo feature that is on by default. All Microsandbox SDK calls are isolated behind CatCode-owned abstractions (a ExecutionBackend trait with HostExecutionBackend / MicrosandboxExecutionBackend implementations) — do not call the SDK or spawn msb/firejail/sandbox-exec/unshare directly from tools, plugins, git helpers, or diagnostics. Add a new agent-controlled workload by routing it through the shared sandbox execution layer.

Commit messages

Use a short, imperative subject (add fetch SSRF hardening, not added). Reference the issue/PR number in the body when relevant.

Reporting security issues

Please do not open a public issue for security vulnerabilities. See SECURITY.md if present, or contact the maintainers privately.

License

By contributing, you agree your contributions are licensed under the MIT License (see LICENSE).