Skip to content

Contributing

Chronos is a Rust Cargo workspace plus a pnpm workspace, driven end to end by just. This page covers what you need installed, where things live, and the conventions every change follows.

  • Rust 1.80+ (stable) — the workspace pins rust-version = "1.80" and rust-toolchain.toml pins the stable channel.
  • Node 22.5+ — the panel API uses the built-in node:sqlite; the docs site and dashboard tooling also run on Node.
  • pnpm — package manager for the JS/TS workspace.
  • just — the canonical task runner; CI runs just ci.

Some recipes need extra tooling, installed once:

  • cargo install typeshare-cli — for just gen-contract.
  • cargo install tauri-cli --version "^2" — for just desktop / just desktop-build (see Desktop app).
crates/
chronos-core/ domain types, session FSM, capabilities, audit model (no I/O)
chronos-contract/ IPC messages + framed transport; source of the generated TS types
chronosd/ daemon: state store (SQLite), orchestration, scheduler, audit
chronos-cli/ the `chronos` binary (thin client of the daemon)
chronos-git/ worktree / branch / diff management
chronos-adapters/ AgentRunner trait + Claude Code, Codex, OpenCode, mock adapters
chronos-broker/ governed MCP + context: signed catalog, cascade, broker proxy
chronos-sandbox/ per-OS isolation policy (worktree scoping + egress allowlist)
apps/
desktop/ Tauri desktop shell (standalone workspace, excluded from `just ci`)
docs/ this documentation site (Astro Starlight)
cloud/
api/ enterprise panel API (catalog, credentials, users, audit)
dashboard/ web panel
packages/
contract-ts/ TS types generated from chronos-contract
tokens/ design tokens (CSS variables) — single source of styles

Dependency rule: chronos-core and chronos-contract depend on nothing else in the workspace. chronosd depends on all client crates. The CLI depends only on the IPC contract, never on the daemon’s internals.

RecipeWhat it does
just buildBuild the whole Rust workspace (cargo build --workspace).
just testUnit + integration tests (cargo test --workspace).
just lintcargo clippy --workspace --all-targets -- -D warnings + cargo fmt --all --check.
just fmtFormat everything (cargo fmt --all).
just run-daemonRun chronosd locally.
just demoDev-only: dashboard at http://127.0.0.1:4173 with a seeded capability catalog (Pulse + Tempo + Brainstorming) and the mock agent (CHRONOS_DEV_CATALOG=1 CHRONOS_AGENT=mock).
just cli -- <args>Run the CLI against the daemon, e.g. just cli -- ping.
just gen-contractRegenerate packages/contract-ts from the #[typeshare] DTOs in chronos-contract (needs the typeshare CLI).
just desktopRun the Tauri desktop app in dev: stages the chronosd sidecar, then cargo tauri dev.
just desktop-buildBuild the distributable desktop app (.app + .dmg) for the host architecture.
just panel-runRun the enterprise panel API locally (cloud/api).
just panel-testPanel test suites (node --test); the Postgres suite self-skips unless TEST_DATABASE_URL is set.
just perfCriterion benchmarks of the hot paths (cargo bench --workspace).
just packageLocal dry run of the release packaging: stages the release tarball layout under target/dist/ (unsigned).
just docsDocumentation dev server.
just docs-buildStatic build of the docs, served by the dashboard at /docs.
just ciWhat CI runs: lint + test + build.

Two recipe-specific notes:

  • Whenever you change types in chronos-contract, run just gen-contract and commit the regenerated packages/contract-ts in the same PR.
  • The docs / docs-build recipes are being migrated from mdBook to this Starlight site at apps/docs: just docs runs the docs dev server, and just docs-build produces a static build in apps/docs/dist that the dashboard serves at /docs.
  • No unwrap()/expect() in library code or production paths. Propagate errors: thiserror for typed library errors, anyhow only at the top edge of the binaries.
  • Strict clippy — CI runs cargo clippy -- -D warnings; treat warnings as errors.
  • rustfmt with default config — formatting is not discussed in PRs.
  • Async discipline — no blocking I/O inside async tasks; heavy filesystem or git work goes in spawn_blocking; every session must be stoppable without orphan processes.
  • No mutable global state — state lives in the daemon behind clear types.
  • Types over strings — session IDs, paths and git refs are newtypes; a SessionId is not a BranchName.
  • Cross-platform always — use std::path, never assume POSIX paths; OS-specific behavior goes behind a trait with per-platform impls.
  • Conventional Commits: feat:, fix:, refactor:, docs:, test:, and so on.
  • Small, focused PRs with a description of what and why — one PR per phase or subtask.
  • Do not mix refactor and feature work in the same PR.
  • Before opening a PR, run just ci locally: it is exactly what CI runs.