Rust TUI chat agent with a Grok Build–style layout: fullscreen scrollback, bottom prompt, status chrome, slash commands, and streaming replies.
This is the Rust vessel for cale — a clean foundation to grow tools, memory, and identity into.
┌─ cale · model @ host · ready ─────────────────────┐
│ session title │
│ │
│ you │
│ hello │
│ │
│ cale · streaming │
│ hey — … │
│ │
├─ prompt · Enter send ──────────────────────────────┤
│ ▌ │
└─ Enter send · /help · Ctrl+C quit when idle ───────┘
cd ~/Code/cale-rs
cargo run --releaseDemo mode (no API key): streams a local reply so you can exercise the UI.
Live mode — Meta Muse Spark for coding (recommended):
export META_API_KEY=... # from https://dev.meta.ai/
export META_BASE_URL=https://api.meta.ai/v1 # optional
export META_MODEL=muse-spark-1.2-contributor # optional, contributor tier
cargo run --releaseContributor tier (muse-spark-1.2-contributor) retains submitted data to improve Meta products; standard tier (muse-spark-1.2) does not. Both are the same coding model.
Live mode — Cohere Chat V2 (alternative):
export COHERE_API_KEY=...
export COHERE_BASE_URL=https://api.cohere.com/v2 # optional
export COHERE_MODEL=north-mini-code-1-0 # optional
cargo run --releaseCALE_API_KEY, CALE_BASE_URL, and CALE_MODEL remain supported as generic aliases, and CALE_PROVIDER=meta|cohere forces the provider when both keys are set. MODEL_API_KEY / MUSE_SPARK_API_KEY are also accepted as Meta aliases.
Copy .env.example → .env if you prefer dotenv.
Sessions persist to SQLite by default and the most recently updated session is restored on startup.
Set CALE_STORAGE=off for an ephemeral run, or configure Convex for cloud persistence as described
below.
Chat messages use a deliberately small Markdown renderer: headings, bold/italic text,
inline code, links, lists, quotes, rules, and fenced code blocks. Code fences show
their optional language label, a clickable ⮻ action that copies only that block, and
syntax highlighting when the language is recognized. Ordered-list markers use the
monospace digits defined in CHARMS.md.
Completed assistant responses show ⮻text | markdown: text copies an unwrapped,
formatting-free version, while markdown preserves the original response.
Failed and cancelled responses show a clickable ↻ retry action.
| Key | Action |
|---|---|
Enter |
Send |
Shift+Enter / Ctrl+J |
Newline |
Ctrl+C |
Clear prompt; cancel if empty + generating; quit if empty + idle |
Ctrl+U |
Clear prompt |
Ctrl+W |
Delete word |
PgUp / PgDn |
Scroll history |
| Mouse wheel / trackpad | Scroll history |
Ctrl+↑ / Ctrl+↓ |
Scroll line |
? (empty prompt) |
Help |
/… |
Slash command |
/help— help overlay/clear— clear session/new— new session/retry— retry the latest failed or cancelled response/run <command>— run a foreground shell command and show its output/read <path>— read a text file (or return base64 for images/binary files)/replace path|search|replacement— replace exactly one matching occurrence/write <path> <content>— write a file/ls [path]— list a directory/grep [-r] <pattern> [path]— search text, optionally recursively/model [name]— show or set model (auto-switches provider formuse-spark)/provider [meta|cohere]— show or set provider/demo— force demo stream/quit— exit
Cale serializes a versioned SessionDto; runtime-only rendering state and provider credentials are
never written to storage. A snapshot is queued when a generation starts and again when it completes,
fails, or is cancelled, as well as on new/clear/retry/quit. An interrupted streaming response is
restored as cancelled and can be retried safely. Backend writes run serially outside the terminal
event loop, and both stores reject stale snapshots.
| Setting | Meaning |
|---|---|
CALE_STORAGE=sqlite |
Local SQLite; the default |
CALE_STORAGE=convex |
Convex cloud deployment |
CALE_STORAGE=off |
No persistence |
CALE_HOME=/path |
SQLite data directory override (sessions.sqlite3 is appended) |
CALE_SQLITE_PATH=/path/file.sqlite3 |
Exact SQLite database path; takes precedence over CALE_HOME |
CALE_CONVEX_URL / CONVEX_URL |
Convex deployment URL |
CALE_CONVEX_TOKEN |
Shared service secret for a personal Convex deployment |
CALE_CONVEX_AUTH_TOKEN |
OIDC JWT alternative for per-user Convex ownership |
Without an override, SQLite uses the operating system’s standard application-data directory. The database uses a versioned schema, WAL journaling, a busy timeout, and a bundled SQLite build, so no system SQLite installation is required.
The checked-in convex/ schema and functions store the same DTO JSON used by SQLite. To attach a
personal deployment:
npm ci
npx convex dev --once
npx convex env set CALE_CONVEX_TOKEN
export CALE_STORAGE=convex
export CONVEX_URL=https://your-deployment.convex.cloud # if not written to .env.local
export CALE_CONVEX_TOKEN='the same secret entered above'
cargo run --releasenpx convex env set can prompt for the value, keeping it out of the command itself. Use a long,
random secret and keep it outside the repository. For a multi-user deployment, configure an OIDC
provider in Convex and supply its JWT through CALE_CONVEX_AUTH_TOKEN; authenticated identities are
isolated from one another. Set only one credential mode. Use npm run convex:dev while editing the
backend and npm run convex:deploy for its production deployment.
src/
main.rs entry
app.rs state + event loop + dispatch (Elm-style)
action.rs Action / Effect
chat.rs Session + Message
persistence/ versioned DTO + SQLite/Convex repositories + save worker
stream.rs demo + Cohere Chat V2 SSE
slash.rs slash commands
config.rs env config
theme.rs colors
ui/ ratatui widgets + minimalist Markdown rendering
Action → Effect → bounded stream channel → Action keeps rendering off the network path. A separate serialized persistence worker keeps disk/cloud writes off the UI path. The event loop redraws only after input, stream, or storage-error events, and scrollback caches completed messages so a streaming delta does not repeatedly parse and highlight the entire transcript.
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets
npm run convex:typecheckCancellation/retry and the local/cloud persistence foundation are complete. The next recommended feature is the Milestone 2 session library and picker, followed by a provider-neutral transport boundary. See ROADMAP.md for the ordered plan and acceptance criteria.
MIT