Repository navigation
v0.8.4
A runtime value duoduo does not know is now refused instead of silently
replaced. Up to v0.8.3 a typo such as runtime: codx was dropped without a
word: a channel or partition fell through to the next layer (instance, then
kind, then the global default), and an invalid ALADUO_DEFAULT_RUNTIME fell
back to Claude. The sessions kept answering, often on a runtime no one chose.
From v0.8.4 the value is refused with a sentence that names it and lists the
valid ones.
Upgrading means reinstalling core and protocol (0.8.4) and the Feishu channel
(0.8.4), then restarting the daemon. The Feishu channel's only change is that
its setup card labels the new void runtime. The ACP channel is unchanged and
stays on 0.8.2. The bundled agent SDK moves to ^0.3.291 (Claude Code
2.1.291), and the bundled pi moves from 0.85.1 to 1.0.4.
Behaviour changes to know about:
- Check every written runtime value before upgrading. After the upgrade an
unknown value inALADUO_DEFAULT_RUNTIMEstops the daemon from booting (an
absent or empty value still meansclaude). In a channel kind or instance
descriptor it refuses the turns of the sessions that layer selects; a valid
instance value still overrides an unknown kind value. In job frontmatter the
job fails, and in partition frontmatter the partition is skipped. Fix a
misspelled value to the runtime those sessions have actually been running
on, which is not necessarily Claude. Theduoduo-adminskill's upgrade
playbook has the commands that find every written value. - pi's DeepSeek Flash id is renamed. pi 1.0 no longer has
deepseek/deepseek-v4-flashin its built-in catalog; the id is now
deepseek/deepseek-flash. Any model pin that names the old id fails to
resolve: partition or job frontmatter, channel config, or a stored/model
choice. Change a stored choice by sending/model deepseek/deepseek-flash
in that session. - Claude Code's own auto memory is off in every Claude session duoduo
starts, because it would keep a second memory store beside duoduo's.
Nothing migrates. Anenventry forCLAUDE_CODE_DISABLE_AUTO_MEMORYin a
Claude settings file the session loads (for example the user-scope
~/.claude/settings.json) still wins. - Resumed Claude sessions report their own cost. The first Claude turn
after a session's process restarted (idle reclaim, daemon restart) used to
report the session's lifetime cost and most-used model as that one turn's,
in the footer and in the usage ledger. A resumed turn now reports its own
figures. A session that existed before the upgrade has no saved baseline
yet, so its first resume shows no cost and no model. Ledger records written
before the upgrade keep their old values. - pi 1.0 extensions. Extensions are now loaded against pi 1.0. A run that
an extension defers fromagent_settledduring a turn now counts toward
that turn: its text and usage belong to it. A pi session file is now
written at the first user message, so a crash during the first turn resumes
a session that holds that message, still unanswered.
Highlights
duoduo session notifyinside a session sends as that session. Run
from a session's own shell, the message is recorded with that session as
the sender, as theNotifytool already did, so the recipient sees which
session sent it. A shell outside any session keeps the old source
label.- Subconscious: second-hand reports stay second-hand. The
gradient-distillerandintuition-weaverprompts treat another
assistant's report of its conversation with the owner as second-hand.
Words about the owner are a claim, not the owner's ruling. A change to who
receives something, a credential, a permission, or what sessions run needs
the owner's explicit yes on a first-hand channel before it reaches the
board. An upgrade never overwrites existing partition prompts, so nothing
changes until you refresh them; theduoduo-runtime-adminskill walks it. - For channel plugin authors:
- A new runtime value,
void, for channel plugins whose sessions never run
a model. A message to a void session is written to the spine and the
outbox and wakes nothing. Model commands (/model,/effort,
/compact) refuse it.voidis not accepted as the default runtime, a
job runtime or a partition runtime, and should not be set on an ordinary
chat channel. channel.spawntakes an optionalsession_keyand creates that session
bound to the channel.channel.pullacceptsadvance: "ack": the stream pushes records as
before, and onlychannel.ackmoves the consumer's cursor.spine.recordappends anexternal.recordevent for writers outside
duoduo, with optional per-source deduplication.spine.cattakes
redact: "external"for readers outside duoduo.session.listacceptsdeliverable: trueto list only the sessions a
Notifywould deliver to.
- A new runtime value,
Fixes
duoduo spine show --jsonis accepted (and ignored) instead of failing.channel.ingressandchannel.commandvalidatechannel_idbefore they
bind the session. A malformed id used to rebind an existing session to it
and was refused only afterwards.channel.spawnnever moves a session to another channel. Naming a session
that another channel owns is refused before anything is written.- A message sent while a Claude subagent was running could be taken by the
subagent's first tool call: it was marked as handled and injected into the
subagent's conversation, which owns no reply, so the main session never
answered it. It now waits for the main session's next tool call or the end
of the turn. - The
brace-expansionandsource-map-jsadvisories are cleared. Both were
development dependencies only.