Duoduo Runtime Admin
This skill owns host-mode runtime flags, daemon diagnostics, and persistent
settings in ~/.config/duoduo/.env.
Start With Runtime Discovery
- Confirm host mode with
duoduo daemon status. - Read
duoduo daemon configbefore changing persistent settings. - Use
duoduo daemon logswhen the user is debugging behavior rather than requesting a config change.
Read references/runtime-settings.md for the main host-mode knobs, references/codex-runtime.md before enabling Codex, references/grok-runtime.md before enabling Grok, and references/pi-runtime.md before enabling Pi — its Context and compaction section also covers a pi session that has started answering with a single character (a filled context window, not a broken model).
Persistent Host-Mode Settings
Edit ~/.config/duoduo/.env with
scripts/update_host_env.py instead of ad-hoc
shell edits when you want predictable results.
When the user asks whether duoduo itself is outdated, check:
duoduo --version
npm view @openduo/duoduo version
Then explain whether an update is actually needed before changing anything.
Typical keys:
ALADUO_DEFAULT_RUNTIMEALADUO_LOG_LEVELALADUO_LOG_RUNNER_THOUGHT_CHUNKSALADUO_LOG_SESSION_LIFECYCLEALADUO_TELEMETRY_ENABLEDALADUO_CADENCE_INTERVAL_MSALADUO_SPINE_INDEX_RETENTION_DAYSALADUO_CODEX_SANDBOX(codex is auto-detected; no enable flag — see codex-runtime reference)
After changing daemon env settings, run:
duoduo daemon restart -r "changed <setting>"
unless the user explicitly asked for an edit only.
Runtime Selection
Be precise:
- Claude remains the conservative fallback when no runtime is declared.
- Claude, Codex, Grok, and Pi are peer runtimes for channel sessions,
jobs, and eligible background partitions. Codex and Grok are
auto-detected: install the CLI, restart the daemon, log in
(
codex login/grok login). Codex probes the login too, so it needs the restart after logging in; grok does not. Pi ships inside duoduo — nothing to install, always reported available, but every pi session needs a model pointer (provider/modelId) from job frontmatter,/model, or partition frontmatter. - Runtime selection can happen per actor, per channel kind, or globally with
ALADUO_DEFAULT_RUNTIME(claude,codex,grok, orpi). - Verify
codexis installed and authenticated before routing work to it. Forgrok, duoduo only checks the binary — verify the login yourself before routing work to it. Explicit grok that cannot be served is a hard failure — it does not fall through to Claude. Pi is the same posture: a pi session with no resolvable model fails with the fix named in the reply, never a silent Claude run.
Do not claim every existing session switches runtime automatically. Existing sessions keep their stored conversation state until they are rebound, archived, or naturally start a fresh runtime thread under the effective config.
Subconscious Refresh
Partition prompts under <kernel>/subconscious/ are NOT touched by a
npm install upgrade — install merges missing files only, preserving
local edits and agent self-programming. When the user wants the
revised partition prompts shipped with a newer duoduo version, they
must refresh explicitly.
Read references/subconscious-refresh.md before making any changes. It covers preconditions (clean kernel git tree, confirm target tag), the diff-before-overwrite discipline, how to handle user-authored partitions and local edits to shipped partitions, the commit-as-rollback-point pattern, and why no daemon restart is required after refresh.
The mechanical (no-LLM) half of memory maintenance is the
duoduo memory CLI: lint checks that post .pending signals into
partition inboxes, plus the manual orphan reclaim lifecycle. Read
references/memory-cli.md when an operator
or a partition needs it directly.
Cadence And Telemetry
- Before changing cadence, explain that a shorter interval increases background activity and token usage.
- Disabling telemetry persistence stops JSONL writes but does not necessarily suppress every in-process debug log line.
- Use
duoduo daemon configto inspect the current effective value before claiming what the default is on this machine.
Usage Ledger Maintenance
var/usage/<session_key>.jsonl is append-only with no automatic
retention — long-lived hosts accumulate hundreds of MB. The host
operator (or this skill on request) archives stale files into a
sibling var/usage-archive/<bucket>/. The daemon does not need to
restart; it scans var/usage/ per usage.get call.
Read references/usage-archive.md for
the verified find -mtime +N | xargs mv recipe, recovery, and the
race-window note.
Slash Commands (/compact, /model, /effort)
/compact shrinks the context window in place. It works on every
runtime and flows through the normal channel message pipeline
(spine → mailbox → drain), so the user gets a regular text reply
when the command finishes.
Read references/slash-commands.md for the runtime semantics, troubleshooting when a command appears not to work, and what to tell a confused user.
/model switches the model for a session at runtime without a restart.
Read references/model-switching.md
for syntax, Claude vs Codex timing differences, and how to recover
from an invalid model id. On Pi, /model is store-only and the
session's worker is rebuilt with the new model on the next message —
see references/pi-runtime.md.
When the user wants a model for many sessions rather than one — every
session of a channel kind, or the whole host — that is a model default
(claude.model / codex.model / pi.model / grok.model, 0.8.1+), set with
duoduo session config at the global, kind, or instance layer. Read
references/model-defaults.md for the layers,
what outranks what, and the two things /model now reports: the config layer a
session inherits from, and the model that actually served its last turn. Reach
for that file whenever a user says a model "will not stick" or "went back to
the old one" — the two lines are the diagnosis.
For hosts running third-party models, model profiles teach duoduo each model's real context window, its endpoint + credentials (per-model routing), and subagent tier aliases (Claude runtime only — codex has no profile namespace). Read references/model-context-profiles.md before answering any profile question — it is written as guided playbooks (add a model / route to an endpoint / remap tiers / troubleshoot / probe an endpoint) with plain-language phrasings to relay, plus the mechanism facts at the bottom for your own verification. Non-negotiables it enforces: secret custody (you may receive a key the human hands you — in chat, env, or file — but the raw value must never appear in anything you emit; take it into the profile store immediately and confirm masked), evidence before any number, confirm before writes that cost a rebuild.
/effort sets how hard the model reasons for a session
(low | medium | high | xhigh) — an independent axis from /model. It
applies live on Claude, and from the next message on Codex and Pi (on
Pi the levels map onto pi's native thinking levels), and stays in
effect across a /model runtime flip (the levels are valid on every
runtime). Invalid values are rejected up front. See the /effort
section of references/slash-commands.md.
Both knobs are also settable per session from the CLI (0.8.0+) via
duoduo session model / duoduo session effort — see
references/session-cli.md.
Session Management (duoduo session …)
These subcommands manage sessions from the CLI (human, agent-via-Bash, or external script — one entry point):
duoduo session list [--kind …] [--named] [--json]— the live route table.duoduo session alias <key> "<name>"— give a session a human label, so it is legible inlistand usable as anotifytarget. Unnamed sessions show—(they are NOT auto-labelled with their key).duoduo session notify <target> -m "<msg>"— wake a session by key OR alias and deliver a source-tagged notification. Onlychannel/jobtargets are allowed; the subconscious/kernel plane is isolated and refused.duoduo session model <target> [<id>|reset]/duoduo session effort <target> [<level>|reset](0.8.0+) — inspect or set a channel session's model / reasoning effort from the CLI, same knobs as in-chat/modeland/effort, without entering the session's chat. Channel sessions only.duoduo session archive <key>— move (never delete) a session's artifacts.
When the user says "name this session X" / "把这个会话叫 X", or wants to wake
one session from another by name, this is the surface. Read
references/session-cli.md for full usage, the
isolation boundary, output/--json discipline, and the refusal reasons.
Spine Inspection (duoduo spine …, 0.8.0+)
The event log (Spine WAL) is read through the CLI, not by opening the JSONL partitions — a single day can be 10-30MB with megabyte-long tool results, and 92% of raw lines are tool plumbing the reader does not need.
duoduo spine cat --date <yyyy-mm-dd> [--session <key>] [--type <t>]… [--kind external|all] [--from … --to …] [--after <id>] [--json]— a compact transcript: human/agent text in full, tool calls collapsed to one line withuse=/res=drill-down anchors, an honest multi-count header and anEND spinefooter (no footer = the read was truncated).--datedefaults to today. All times are UTC and every range is(from, to];--from/--toalso accept absolute ISO instants with an offset (2026-08-31T08:29+08:00), and such a range may span several days.--after <id>resumes strictly after one event inside the same bounds, so the output is a suffix of the same read.--kind externalis turn-scoped, not a source filter: it keeps events that came from outside plus the internal rows of the turn each keptchannel.messageopened. Job sessions do not expand. Default isall.duoduo spine cat --interval '<date>[t1,t2]' …— the machine-shaped bounded read (this is what the subconscious uses), one partition, same(t1, t2]edges. Always quote the interval: zsh treats the brackets as a glob and fails before the CLI runs.duoduo spine cat … --sessions— per-session summary (exact key, event count, first/last ts) for finding a session key on a busy day.duoduo spine cat … --count-only— sizes only, no body; check before pulling a large window into an agent's context.duoduo spine show <event-id> [--date <yyyy-mm-dd>]— one event, full JSON, nothing elided. Row ids are shortened for display;showaccepts any unique prefix and lists candidates when ambiguous. The by-id index is a boot-compacted recency cache. An older bare id falls back to a full partition scan;--dateonly narrows that scan, and the WAL row is unchanged.- A
catthat would print a body with no narrowing filter refuses unless--unfilteredis passed — that is protection for agent context windows, not a permission.--count-onlyand--sessionsprint no body and are exempt, so sizing a whole day never needs the flag. missing_partitions=/skipped_malformed=in the header are disclosures, not errors: a day with no events writes no partition file, and a torn final line is a normal crash artifact.
Operating Rules
- Prefer
duoduo daemon configover stale documentation when values disagree. - Treat
~/.config/duoduo/.envas the persistent source of truth in host mode. - When the user updates the installed
@openduo/duoduopackage, remind them thatduoduo daemon restartis still required because the running daemon is a separate background process. - If runtime behavior still looks wrong after config, restart, and logs have been checked, treat it as a likely duoduo bug and use the public issue flow from ../duoduo-admin/references/issue-reporting.md.
- If the request is really about channel install/start/prompt/workspace work,
hand off to
duoduo-channel-admin.