Liking cljdoc? Tell your friends :D

dvergr-cli

The dvergr command-line entry point. clojure -M:cli starts the daemon (the system), an nREPL server on :7888, and — unless --no-tui — a terminal chat UI over your rooms, built on spindel-tui

  • the dvergr.runtime.bus + dvergr.discourse.llm substrate. The TUI is a frontend: the same daemon also drives the web dashboard, Telegram, and nREPL clients.

Run

# From a dvergr checkout — daemon + nREPL(:7888) + TUI
clojure -M:cli

# Headless: daemon + nREPL only (a server box, or attach a client later)
clojure -M:cli --no-tui

# Server box: daemon + nREPL + web dashboard, no TUI
clojure -M:cli --no-tui --web

Flags

FlagDefaultMeaning
-p, --port PORT7888nREPL port (written to .nrepl-port for editor/clj-nrepl-eval auto-discovery)
--nrepl-port-file PATH.nrepl-portwhere to write the nREPL port (parent directories are created; a file that cannot be written stops the start with exit code 1)
--no-tui—run without the TUI (daemon + nREPL only)
--web—also start the web dashboard
--web-port PORT17880web dashboard port (with --web)
--web-bind IP127.0.0.1web bind address. Every request needs a credential wherever it comes from: the CLI prints a login URL (http://127.0.0.1:17880/?token=…, the local token of $DVERGR_HOME/local-token) that opens a browser session (kept by the page, sent as a header, never a cookie), or send Authorization: Bearer; an authenticator (:auth, doc/mcp.md) adds others. The server also checks the Host header (DNS rebinding) and the Origin of every state-changing request; a reverse proxy's name and origin go in :http {:allowed-hosts […] :allowed-origins […]}
--mcp—also serve MCP on the home's Unix domain socket (clients connect through bin/dvergr-mcp; mcp.md). The daemon names its state root in server/discover's _meta (dvergr/home), and the relay refuses a daemon of another state root
--mcp-tcp—with --mcp, also on loopback TCP (off by default: a TCP client sends its token to whoever holds the port)
--mcp-port PORT17888MCP TCP port (with --mcp-tcp)
-h, --help—show usage

Provider, model, and agents are not CLI flags — they come from config.local.edn (with an env fallback). The shipped default leaves the provider unpinned and auto-selects the best one you have a key or login for (Anthropic → Fireworks → OpenAI → native Codex subscription → isolated Codex CLI → the local claude CLI). See provider-setup.md and configuration.md.

Views

The TUI has a few views; Tab switches between the tree and the process list, and leaves a room for the tree.

  • Tree (Rooms · Agents · Forks): rooms, their forks and the agents. Keys not listed below go to the tree component (moving the selection), Enter opens a room (or an agent's config), and single keys act on the selection.
  • Room: the room's messages with an input line; a reply streams in as it is written. Typing / opens the command menu (↑/↓ select, Tab or Enter complete).
  • Processes: the running processes of the chat, with abort / continue / extend.
  • Agent config: an agent's fields, edited in place.

Keys

KeyWhereAction
Ctrl-CanywhereQuit
TabanywhereSwitch view: tree ↔ processes; from a room, back to the tree
Ctrl-OanywhereToggle mouse reporting (on: wheel scrolls; off: the terminal selects and copies text)
EntertreeOpen the selected room, or the selected agent's config
n / atreeNew room (asks for a slug) / new agent (asks for an id); Esc cancels the prompt
ctreeChat with the selected agent
ftreeFork the selected room (:ctx isolation)
mtreeMerge the selected fork into its parent: a :ctx fork at once (conflicting fields reconciled by an agent), a conversational fork after y / n
xtreeDiscard the selected fork (asks y / n)
dtreeArchive the selected room
EnterroomSend the input line (a /command runs instead)
EscroomCancel the running turn; when none runs, back to the tree
PageUp / PageDown, wheelroomScroll
Ctrl-RroomVoice input — press to start recording, again to stop; transcribes and posts as a 🎤 message (setup)
Ctrl-T / Ctrl-EroomToggle the trace view / per-agent context bars
j / k, e or Enter, p, c, x, Escagent configMove, edit a field, edit the prompt in $EDITOR, chat, delete (asks y / n), back
j / k, a / c / eprocessesMove; abort, continue, or extend the focused process by $0.10

Persistence

Rooms, their message history, knowledge, and per-agent budget persist automatically in Datahike under the state root ($DVERGR_HOME, default ./.dvergr; the daemon owns the stores). There is no save/resume step — restart clojure -M:cli and your rooms rehydrate from the registry + stores, the agent continuing with full conversational state. Forks made with :isolation :ctx carry their own branched stores until merged or discarded.

(Long conversations are kept in bounds by context compaction — summarize + prune before a turn as the model's window fills; see tools-and-sandbox.md.)

Agents & tools

What the TUI talks to are the agents joined to each room, configured in config.local.edn / resources/agents/*.md — not a CLI flag. Each agent's tool set is its capability boundary (a :tools allowlist or a role tag like #{:coding}); the default secretary (var) routes and chats. See programming-model.md and tools-and-sandbox.md.

Telemetry

The TUI renders each room from the live :room-messages signal (a fold of the room bus) plus per-chat stats. The header reflects:

  • Live budget / cost — from the chat-ctx :budget-signal + dvergr.rooms.stats
  • Generation status — ● generating / ○ idle / ✕ error

(:partial/token streaming and :telemetry/* turn events are bus primitives — see examples/scenario_streaming_partial.clj — not currently wired into the header.) External consumers (the web dashboard, a billing system, a logging agent) subscribe to the same bus channels.

Troubleshooting

Agent doesn't reply — make sure a provider is configured (a key in env or config.local.edn). Reply errors print to stderr; the daemon log is dvergr.log in the state root ($DVERGR_HOME, default ./.dvergr). List registered models with (dvergr.model.registry/list-models) over the nREPL.

Garbled output / Unicode issues — the terminal needs UTF-8 + 256-color. The TUI uses JLine; in an unusual terminal set TERM=xterm-256color.

See also

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close