DuoDuo docs

Install, use, and operate DuoDuo.

These docs cover durable files, event ordering, sessions, the scheduled subconscious, the intuition layer, and host operations.

Check health, logs, channels, and memory.

Operate

Host Operations

Check health, find config, read logs, and upgrade safely.

DuoDuo runs as a daemon on your machine. The duoduo CLI tells you whether it is healthy, which configuration it is using, and what happened when something goes wrong.

Check before you change#

duoduo daemon status
duoduo daemon config
duoduo daemon logs
  • status reports process and scheduler health.
  • config resolves active paths and settings.
  • logs shows the readable tail; request more only when diagnosis needs it.

Start with what the running daemon reports. Its effective configuration is more useful than a copied default.

What is running right now#

When tool calls are in flight, status lists each one: which session, which tool, how long ago it started. When no tool calls are open, the list is empty.

It passes no judgement. There is no threshold, no watchdog, no timeout that decides a call has taken too long—status reports, and /cancel acts. Read the empty list carefully: it means no tool call is open, which is equally true while the model is writing.

Read the event history#

duoduo spine cat --date <yyyy-mm-dd> --session <key>
duoduo spine cat --date <yyyy-mm-dd> --count-only
duoduo spine show <event-id>

The Spine WAL is the source of truth, and on a busy host a single day of it is tens of megabytes of JSONL. Read it through the CLI rather than opening the files: cat prints speech in full and folds each tool call together with its result, and show prints one event whole.

Size a window with --count-only before pulling it into an agent's context, and continue a long read with --after <event-id> rather than starting over. A cat with no narrowing filter refuses to print a body unless you pass --unfiltered.

The by-id index is a bounded recency cache, compacted at boot, so it does not grow without limit on a long-lived host. ALADUO_SPINE_INDEX_RETENTION_DAYS sets how much it keeps. Nothing becomes unreadable when an id falls out of it—the read falls back to scanning that day's partition.

Upgrade#

duoduo --version
npm view @openduo/duoduo version
duoduo upgrade

One command does the whole job. It installs into the prefix that owns the binary currently running, reinstalls and restarts the channel plugins, restarts the daemon with the version as the reason, and waits for a health check before reporting success.

The prefix part matters if duoduo was installed outside npm's default global prefix — which is how the menubar app installs it. A plain npm install -g there writes a second copy elsewhere, leaves the running binary untouched, and reports success anyway.

It is safe to run from inside a DuoDuo conversation: the work is handed to a detached process that the daemon restart cannot kill. Add --wake <session-or-alias> for a session that should be told when it is done.

DuoDuo reconnects a teal ribbon from an open file cabinet to a wheel in its base.

For a manual upgrade in the default npm prefix, install the package and restart the daemon. Then reinstall and restart each channel as described in Channels:

npm install -g @openduo/duoduo@latest
duoduo daemon restart -r "upgraded @openduo/duoduo to <version>"

Installing a new package does not hot-swap the detached process. Restart the daemon so it runs the new code, and say what changed: the reason reaches every session that wakes afterward, and a session whose turn the restart ended has no other way to learn why.

Upgrades that cross a major boundary occasionally need a manual step. Those are called out in the release notes.

Skills upgrade separately#

The published agent skills are separate from the npm package. CLI and npm upgrades do not refresh them; Manager’s upgrade flow does. To refresh them yourself:

npx -y skills add https://github.com/openduo/duoduo --global --all

How the daemon is reached#

The daemon serves its full interface on a unix socket with owner-only permissions, so the operating system decides who may drive your agent. The CLI, the channel gateways, and the menubar app find it by default; there is nothing to configure.

127.0.0.1:20233 is a read-only surface for the dashboard. It is pinned to loopback, answers only the methods the dashboard needs, and does not speak WebSocket. Control belongs to the CLI; do not point scripts at that port.

SettingWhat it controls
ALADUO_PORTThe read-only TCP port, default 20233. Always loopback.
ALADUO_DAEMON_SOCKETAbsolute path override for the socket. Rarely needed.
ALADUO_DAEMON_HOST + ALADUO_REMOTE_PORT + ALADUO_DAEMON_TOKENThe opt-in remote listener.

Reaching a daemon from another machine#

Remote access is opt-in and always carries a token.

duoduo daemon token new

The token is stored with owner-only permissions, and every remote request must carry it. The listener starts only when host, port, and token are all present, and the remote port must differ from the read-only one. A misconfiguration — a public address with no token, or a port collision — refuses to start rather than exposing anything.

Install the operations skills#

npx -y skills add https://github.com/openduo/duoduo \
  --global \
  --yes \
  --skill duoduo-admin duoduo-channel-admin duoduo-runtime-admin

These skills teach a coding agent how to inspect, configure, recover, and manage channels for the version you actually installed. Ask for the work in plain language.

Tool access is an allowlist#

Claude sessions receive a fixed core tool surface. Extra built-in tools—such as web search or fetch—must be added in a channel kind or instance descriptor under claude.tools.

claude:
  tools:
    - WebSearch
    - WebFetch

The list adds tools to Claude's fixed core set. Codex manages tools separately.

A scheduled job can carry the same block in its own frontmatter, with host-wide defaults in kernel/config/job.md. See Loops & Jobs.

If a tool is missing, run duoduo session config <target> get and check the configuration that session actually received.