Arroba is a daemon-centered framework for running and orchestrating native AI coding CLIs and compatible agent runtimes through a shared terminal interface.
The project is intentionally local-first. A daemon node owns live sessions on the user's machine, local or remote members attach to that node, and a lightweight server can relay remote connections without becoming the authority for runtime state or provider behavior.
M0, "Foundations", is complete in this repository.
M1, "Core Session Runtime", is complete.
M2, "End-to-End Local OpenCode Baseline", is complete.
M3 is largely delivered for the local baseline hardening work.
M4 is now in progress with the first manual multi-agent session runtime slice landed in main.
M4.5, "Kernel Runtime Refactor", is now in progress in parallel with the remaining M4 stabilization work.
v1 scope includes both:
- single-agent sessions
- manually directed multi-agent sessions
- multi-agent workflow execution
Current delivery priority:
- first: close the OpenCode-first runtime cycle, including capabilities, agent harnessing behavior, and multi-machine session work
- then: finish the kernel runtime refactor so interactive commands stay responsive while background work, provider I/O, history reads, and replay/reconnect paths run concurrently
- then: polish the TypeScript CLI as the reference client
- then: add multi-platform clients such as web and iOS/Android on the same daemon/protocol model
- finally: add more providers such as Claude Code and Codex and harden the generic provider-adapter/protocol shape
The current codebase provides:
- a pnpm workspace for TypeScript packages
- a minimal Fastify server with a health endpoint
- a shared domain package for workflow-oriented core v1 entities
- a Rust daemon runtime with config/bootstrap wiring, in-memory session lifecycle, shared attachment participation, provider-run orchestration, prompt queueing/config propagation, and PTY-backed terminal fan-out
- a real local daemon IPC surface, a TypeScript OpenTUI local CLI with an OpenCode-inspired transcript/prompt layout, and a working OpenCode baseline path with prompt submission and live streamed output
- a kernel-hosted WebSocket transport for the TypeScript CLI, including pushed events, resumable subscriptions, heartbeat/liveness, and reconnect-friendly behavior
- the first M4.5 kernel runtime slices: normalized kernel commands, an event log service with replay-gap handling, a command router, bounded interactive routing, safe command-id retry handling, typed CLI replay-gap notices, provider-run actor coverage for structured submit/cancel/poll paths,
KernelSessionServicefor session lifecycle/focus/resize/end/delete operations,KernelAgentServicefor prompt submit/cancel/complete/queue-advance lifecycle behavior, per-agent prompt command mailboxes including prompt completion/cancellation routing with owner-backed active-prompt resolution, per-session UI/lifecycle command mailboxes with projected delete/detach lane lookup, projected focused-agent fallback for untargeted prompt routing, projection-first reads for warmed session/list/resolve/history/provider-run/process/catalog and agent/workflow inspection state, list-hydrated session-state projection reads, a shared kernelPromptStateOwnerfor active/queued prompt mutation, direct owner-backed and agent-runtime active/queued prompt reads including queue-advance and provider-settlement inspection, agent-mailbox prompt submit/cancel/complete projection publication through one shared prompt read model, agent-mailbox completion consuming lifecycle-published session projections, a dedicatedPromptRuntimeStatemodule for flattened compatibility prompt mirroring/projections, provider actor enqueue error propagation, prompt lifecycle projection publication for complete/cancel, session response-borne projection refresh/removal from the session mailbox, trimmed router-side snapshots for non-state terminal control commands, canonical agent-runtime prompt-count projections in daemon health, daemon health queue snapshots, explicit file-writing capability worktree claims, provider prompt lifecycle worktree claims, local provider prompt dispatch writes/enqueues running behind spawned provider-operation dispatch after synchronous claim admission, kernel prompt submit history appends and remote relay prompt dispatch deferred out of the acknowledgement path with failure cleanup, terminal stream cleanup on session end/delete, session, agent, and workflow request handling consolidated behind their runtime boundaries, workflow lane missing-session rejection from warmed projections, workflow response-borne projection refresh, runtime-tool workflow projection refresh, workflow node blocking/retry on workspace claims, relay-client daemon/workflow requests routed through the kernel command router instead of direct compatibility request handling, local/forwarded runtime MCP tool calls routed through the same router boundary, relay config/remote-machine registry mutations handled explicitly by the router, exhaustive normal/background router dispatch without the old generic local compatibility fallback, and direct named router helpers instead of productionhandle_local_requestcalls - a real manual multi-agent session slice in the daemon and TypeScript CLI: agent records, focused-agent prompt routing, per-agent provider-run ownership/history metadata,
/agent ...management commands,Ctrl+Afocus cycling, andindividual/splitresponse views - a Rust compatibility launcher for the TypeScript CLI
- a local daemon smoke harness for managed-session flows
- a Prisma schema aligned with workflow-oriented runtime entities
- baseline CI for TypeScript and Rust checks
Current implementation caveat:
- the OpenCode-backed multi-agent path still needs stabilization, but the current daemon and CLI suites are green
- the current split-pane TypeScript CLI is still an initial slice centered on the primary transcript plus up to two auxiliary panes
- the M4.5 ownership refactor is closed: the direct-cutover baseline, session ownership, prompt ownership, provider process/output ownership, workflow/runtime-tool ownership, transport/relay ownership, runtime fallback deletion, and dead-code purge are complete;
DaemonAppremains as bootstrap/composition scaffolding, not the command-state owner - current workspace claims are a bounded safety and scheduling layer, not the final I/O-conflict-control design; deeper file-level, port-level, sandbox, or transactional patch coordination is deferred until after actor/projection ownership is complete
- generic agent transport is intentionally deferred for now; OpenCode continues to use its native local HTTP + SSE adapter path
The project specification and architecture remain the primary source of truth for behavior beyond this bootstrap.
.
├── agents/ # project-level instructions and status for coding agents
├── apps/
│ ├── cli/ # TypeScript OpenTUI CLI client
│ ├── daemon/ # Rust daemon crate
│ └── server/ # Fastify TypeScript server bootstrap
├── docs/ # product, architecture, protocol, roadmap, and ops docs
├── packages/
│ └── domain/ # shared TypeScript domain model
├── prisma/ # baseline Prisma schema
├── package.json # root workspace scripts and dev tooling
├── pnpm-workspace.yaml # pnpm workspace package discovery
└── tsconfig.base.json # shared TypeScript compiler baseline
The daemon is the runtime authority in Arroba v1. It is responsible for hosting sessions, managing PTYs, coordinating provider runs, and eventually owning the capability and control lanes described in the architecture docs.
The current local baseline is one local CLI, one provider (opencode), one prompt path, and live streamed output through the daemon. The near-term plan is to close that one-provider cycle fully before broadening to more clients or more providers.
Architecturally, the daemon is now better thought of as a node runtime:
- it owns sessions and prompt routing
- it will eventually route both local and relay-attached members in the same session domain
- it will eventually own workspace coordination to reduce edit/integration conflicts between top-level agents
The primary CLI path now uses the kernel WebSocket event stream. The daemon implementation target is an actor/event/projection kernel: commands enter through a router, actors own mutation, ordered kernel events drive recovery and replay, and clients read projections. The current DaemonApp shape is bootstrap/composition scaffolding around those runtime owners, not the long-term command-state owner.
The primary local CLI is now the TypeScript OpenTUI app in apps/cli. arroba-cli remains the familiar entrypoint by launching that TypeScript client through a small Rust compatibility wrapper.
This package is the new local terminal client. It uses the same OpenTUI stack as OpenCode and intentionally borrows the OpenCode prompt/transcript visual language: a boxed transcript pane, sticky bottom scrolling, a visible side scrollbar, and a boxed multiline prompt composer.
The CLI remains daemon-first: it is only a transport client over the kernel-owned transport surface, not a second runtime authority.
The server is the future relay and control-plane surface. In v1 it is intended to stay lightweight: authentication, discovery, presence, and relay responsibilities should live here, not session execution or provider logic.
At M0 it exposes a single /health endpoint and a smoke test.
This package defines shared TypeScript contracts for the core v1 entities used across the repo. It exists to keep terminology and shape definitions consistent between daemon, server, and future client surfaces.
The package includes runtime enum constants and a minimal contract test suite so the baseline shapes are verified, not just typed.
The Prisma schema is the initial persistence model for the same core entities defined in the domain package and docs. It is included now to establish naming, relationships, and status enums early, before implementation details spread across the codebase.
agents/AGENTS.md: high-level design constraints and current statusdocs/spec-v1.md: the product specification for Arroba v1docs/ARCHITECTURE.md: implementation-oriented architecture viewdocs/PROTOCOL.md: protocol lanes and structured message contractsdocs/RUNNING_LOCAL.md: how to run the current local daemon + CLI pathdocs/LOGGING.md: shared logging setup, configuration, and inspectiondocs/ROADMAP.md: milestone plandocs/M4_5_KERNEL_RUNTIME_REFACTOR_PLAN.md: implementation plan for the actor/event/projection kernel refactordocs/CONTRIBUTING.md: contributor workflow and testing expectationsdocs/M0_IMPLEMENTATION_CHECKLIST.md: M0 definition of done and execution checklistdocs/M1_IMPLEMENTATION_CHECKLIST.md: detailed execution checklist for the core session runtime milestonedocs/ops/TASKS.md: lightweight repo-native task trackingdocs/ops/PROGRESS_LOG.md: chronological handoff log
- Node.js 22 or later
- pnpm 9.15.0
- Bun 1.2 or later for the TypeScript OpenTUI CLI runtime
- Rust stable toolchain with
cargo,rustfmt, andclippy
pnpm installFor a fuller local-runtime guide, see RUNNING_LOCAL.md.
The current local runtime is two processes:
arroba-daemonarroba-cli(Rust shim that launches the TypeScript OpenTUI client)
OpenCode setup currently requires:
opencodeinstalled locally and reachable onPATH, orARROBA_OPENCODE_BINset to the executable pathARROBA_OPENCODE_PORTset to an explicit local TCP port foropencode servebuninstalled locally and reachable onPATH, orBUN_BINset to the executable path
Example:
export ARROBA_OPENCODE_PORT=43111
cargo run --manifest-path apps/daemon/Cargo.toml --bin arroba-daemonThen in another terminal:
export ARROBA_OPENCODE_PORT=43111
cargo run --manifest-path apps/daemon/Cargo.toml --bin arroba-cliDirect TypeScript CLI development path:
export ARROBA_OPENCODE_PORT=43111
pnpm --filter @arroba/cli run devCurrent migration status:
apps/cliis the primary local client implementationarroba-cliis a compatibility launcher for that TypeScript client
Current local CLI controls:
/stoprequests cancellation of the active provider turn; queued work advances only after the provider confirms the stop/exitdetaches from the current session and exits the CLI/session create [alias]creates and attaches to a new session/session attach <ref>attaches to a session by full id, unique id prefix, alias, or unique alias prefix within the current workspace/session delete [ref]deletes the current or referenced session; deleting the active session returns the CLI to its no-session landing state- manual multi-agent session commands exist today:
/agent spawn [alias] [model]/agent spawn <number_of_agents>spawns that many agents/agent delete [name-or-alias]/agent focus <id>/agent list/agent cycleCtrl+Acycles focused agent in the current session
/view <split|individual>switches between split-pane and single-transcript multi-agent views- these agent controls now drive the local manual multi-agent runtime path: prompts follow the focused agent, the daemon tracks provider runs per agent, and the TypeScript CLI can render individual or split multi-agent transcript views
Optional executable override:
export ARROBA_OPENCODE_BIN=/absolute/path/to/opencodeOptional Bun override:
export BUN_BIN=/absolute/path/to/bunFor the full logging guide, see LOGGING.md.
Arroba now uses one machine-local shared log root for runtime processes instead of ad hoc debug files.
Default log root resolution:
ARROBA_LOG_DIR, if setXDG_STATE_HOME/arroba/logs~/.local/state/arroba/logs./.arroba/logsas a final fallback
Current process coverage:
arroba-daemon- the Rust
arroba-clilauncher - the primary TypeScript CLI process in
apps/cli - the Fastify server process in
apps/server
Current defaults:
- log format: NDJSON, one JSON record per line
- retention: roughly 7 days and 200 MB total per log root
- privacy: metadata, lifecycle, warnings, and errors by default; prompt/provider content should only be captured via explicit debug-oriented changes
Useful env vars:
export ARROBA_LOG_DIR=/absolute/path/to/arroba-logs
export ARROBA_LOG_LEVEL=debugInspect logs directly:
tail -f ~/.local/state/arroba/logs/*.ndjson
jq 'select(.session_id=="session-1")' ~/.local/state/arroba/logs/*.ndjsonOr use the built-in viewer:
cargo run --manifest-path apps/daemon/Cargo.toml --bin arroba-cli -- logs --follow
cargo run --manifest-path apps/daemon/Cargo.toml --bin arroba-cli -- logs --session session-1
pnpm --filter @arroba/cli run dev -- logs --process-kind daemon --level errorRun the current repository verification set from the repository root:
pnpm lint
pnpm build
pnpm test
cargo test --manifest-path apps/daemon/Cargo.tomlOptional Rust checks:
cargo fmt --manifest-path apps/daemon/Cargo.toml --check
cargo clippy --manifest-path apps/daemon/Cargo.toml --all-targets --all-features -- -D warningsThe code in this repository is guided by a few non-negotiable rules:
- preserve the native provider terminal experience
- keep the daemon as the runtime authority
- keep the server lightweight
- separate raw terminal streaming from structured capability and control lanes
- implement reusable behavior below any one client surface
These constraints are described in more detail in agents/AGENTS.md, docs/spec-v1.md, and docs/ARCHITECTURE.md.