Agora is a local CLI + daemon for running headless "agent" executables. Each message spawns a fresh process, captures stdout/stderr, and persists agent registry + conversation IDs in SQLite.
This README focuses on intended usage and the contract between the daemon and agent executables.
For the full documentation set, see docs/index.md.
- Start the daemon (it owns state and spawns runs).
- Register an agent with
agora new(first run happens immediately). - Send follow-up messages with
agora send. - Stream or read logs via
agora send --followoragora log. - Delete the agent when you are done.
Build once:
cargo build --releaseTerminal 1 (daemon):
./target/release/agora daemonTerminal 2 (client commands):
# register the agent and start the first run (defaults to a built-in shim label)
./target/release/agora new my-agent /path/to/workdir "hello"
# register with an exec label or explicit executable path
./target/release/agora new my-agent /path/to/workdir "hello" --exec codex
./target/release/agora new my-agent /path/to/workdir "hello" --exec /abs/path/to/agent.sh
# send a follow-up message (stream output)
./target/release/agora send my-agent "next message" --follow
# print logs from the most recent run
./target/release/agora log my-agent
# unregister the agent and delete its runs
./target/release/agora delete my-agent
# register/update an exec label
./target/release/agora set-exec codex /abs/path/to/agent.sh
# update an agent's exec reference
./target/release/agora set-agent-exec my-agent codexIf you prefer a visual interface, build and run the GUI server:
./target/release/agora-guiIt prints a local URL (for example http://127.0.0.1:57041). Open that URL in a
browser on the same machine. The GUI talks to the daemon and mirrors the same
daemon discovery order as the CLI.
Agora is organized as a Cargo workspace with focused crates:
crates/cli: theagoraCLI binary and command handling.crates/daemon: the daemon + HTTP API surface.crates/gui: theagora-guiserver plus GUI client/cache helpers.crates/core: shared protocol, state, DB, and API model types.
To install the binary and bundled shims under a prefix:
PREFIX=/usr/local ./install.shNotes:
- If the install prefix isn't writable,
install.shexits early and suggests rerunning withsudo -E(or choosing a writablePREFIX). - When run with
sudo,install.shbuilds as the invoking user (SUDO_USER) to avoid root-ownedtargetartifacts. - If
--execis not provided, Agora defaults to the first available built-in exec label (currentlycodex, thenecho) and prints a note to stderr. - If
--execis provided, Agora treats it as either:- An explicit path, or
- An exec label resolved in this order:
- A label set via
agora set-exec <label> <path> <exe-dir>/agents/<label>/agent.sh<prefix>/share/agora/agents/<label>/agent.sh$PATHlookup for<label>
- A label set via
newcreates thetarget_dirif it does not exist and sets it as the agent working directory.- Only one run per agent is active at a time; additional sends are queued FIFO.
The daemon spawns the agent executable for every new and send.
Invocation:
cwdis set to the agent's workdir.- Environment:
AGORA_AGENT_NAMEAGORA_RUN_ID
- stdin receives exactly one JSON object, then EOF:
{
"version": 1,
"run_id": "uuid",
"agent_name": "name",
"cwd": "/abs/path",
"conversation_id": "opaque-or-null",
"message": "user message"
}Stdout requirements:
- Must be JSONL (one JSON object per line).
- The first stdout line must include a "conversation started" event:
{ "type": "thread.started", "thread_id": "..." }or
{ "type": "conversation.started", "conversation_id": "..." }If the started event is missing, or if a send run reports a different
conversation ID, the run is marked failed.
Stderr is treated as opaque diagnostics and is logged verbatim.
State root (in priority order):
--state-root <dir>(CLI flag)AGORA_STATE_ROOTXDG_STATE_HOME/agora~/.agora
State layout:
<state_root>/agora.db<state_root>/runs/<run_id>/stdout.jsonl<state_root>/runs/<run_id>/stderr.log
Daemon discovery (client-side):
- If
AGORA_DAEMON_URLis set, it is used directly. - Otherwise, the client reads
<state_root>/daemon.addr. - Fallback:
http://127.0.0.1:5522.
If you run multiple daemons, use distinct --state-root values or set
AGORA_DAEMON_URL when invoking client commands.
-
Register once, then send many:
agora new codex ~/projects/demo "start" agora send codex "continue" agora send codex "summarize" --follow
-
Follow runs from another terminal:
agora send codex "long task" agora log codex
- No interactive TTY agents; all runs are non-interactive.
- No global scheduling or parallel runs per agent; one active run per agent only.
- No attempt to standardize the agent's internal conversation storage.