Repository navigation
v2026.10.24-2
·
711 commits
to main
since this release
@code-yeongyu/senpi
Breaking Changes
Added
- Shared RPC hosts support live-only
attach_session, one-holdrelease_attachment, and atomicreclaim_session. Attachments are fenced by durable session identity, and temporary releases let active turns finish (#3795, #3814). - MCP config hashes, catalog credential identities and log fingerprints are HMAC-SHA-256 under a private per-installation key (
config-identity.keyin the agent directory, created once with mode0600), instead of plain hashes that could be guessed offline. A catalog cached by an earlier version is kept and rewritten under the keyed identity only when both its config and its credential still match (#3858). - Every value of at least four characters a configuration reference resolves to, rotated ones included, is treated as sensitive (even non-secret values such as paths) and redacted from MCP logs, the persisted MCP catalog, server status and RPC snapshots, connect diagnostics,
/mcperrors and the shared stderr and stdout scrubbers, in raw and URL-encoded form; data sent back to servers keeps its exact bytes (#3858). mcp.jsonaccepts$file,$envand$concatreference objects inheaders,envandargs. A reference is read only where${NAME}would be expanded (your own and trusted project or Claude files, trusted stdio skills); extension declarations, remote and untrusted skills refuse it before reading anything. Each connection, reconnect included, reads it again, and a server whose reference fails reports a named error while the other servers keep working (#3858).auth.jsonaccepts$file,$envand$concatreference objects in an API key'skeyand in each pooled account'skey. Each one is read again on every use, relative to the auth.json directory; a slot-scoped request resolves only the selected account, and a malformed object is a named configuration error (#3858).- The package manifest declares
"senpiCapabilities": { "configReferenceObjects": 1 }, so a setup tool can confirm that the installed engine resolves reference objects before it writes any (#3858). - Configuration-value resolution supports typed file, environment, and concatenation references with source authority checks and bounded, validated file reads; a
$filepath is absolute, under~/(the home directory), or relative to the declaring file; reference output remains literal rather than entering command or environment interpolation again (#3858).
Changed
- The terminal guidance now states what the code does: a plain
&job dies with a foreground call's PTY hangup (native backend);nohupat best leaves an untracked orphan that the call's timeout still group-kills (the full race andsetsidanalysis lives in the terminal tracker); a non-persistent monitor'stimeout_mskills the watched command; a timed-out local command watch now summarizes aswatcher killed at deadline (timed_out)while RPC watches keepwatcher timed_out— they kill nothing (#3611). - Socket-host session mutations now require attachment. This release serves legacy unattached mutations with a deprecation line;
SENPI_RPC_REQUIRE_ATTACH=1enforces immediately.release_sessionexcludes the caller's own holds when checking for other attached clients (#3795, #3814). - JSON print mode now exits non-zero when the final settled assistant response fails or is aborted, as text print mode does. Before, JSON mode exited 0 on these stops and left the failure to the event stream, so scripts that relied on exit 0 now see exit 1. A run that recovers from an earlier provider error still exits 0 (#4061).
- The
show_html_pagetool description now tells the agent to load the bundledvisualizeskill before building a page (#2869). - The agent no longer pauses after 150 turns it starts on its own after one message:
engineTurns.maxPerUserInputnow defaults to0(off). Set it to a number to bring the pause back; the breaker for automatic turns that do no work (engineTurns.maxToolFreePerMinute, 12 per minute) is unchanged (#4150)
Fixed
- An itemized
sendMessagethat re-sends a delivery ticket whose message is still queued, with different items, is now rejected withDeliveryTicketRefused(reason: "different_items") instead of receiving receipts for items that were never written; the queued message keeps its first content (#4106). - After a hot reload (
/reload, a settings or extension change,omo update), a control endpoint registered by the previous extension generation is closed with that generation, so inbox and command wakes no longer repeat "control endpoint drain failed: stale extension generation after reload" and stop delivering (#3246). - A generation handoff from a client whose agent directory differs from the running host's is refused (
foreign_agent_dir, naming both directories) instead of replacing that host on its socket. A sandboxed dev server pointed at the user's realrpc.sockcan no longer take it over.get_protocol_inforeports the host'sagentDir(#3560). - Forking a session file whose line-1 header was lost no longer fails with "source session file is empty or invalid". A file whose every entry is a session entry is forked whole under a new header, and an empty file and a file that is not a session now get distinct errors (omo#10375).
- On macOS and Linux, the private hop between the RPC host supervisor and its engine is now authenticated and sealed. Each launch hands the engine a fresh key once through stdin; both sides prove that key before any traffic, and every record is encrypted with AES-256-GCM, so a process that reaches the private socket can neither read session traffic nor inject into it. The engine learns of its supervisor's death as an event (a private lifetime FIFO on Linux, the end of that stdin on macOS), with the recorded supervisor PID and start time only as a rare backstop, so wrappers and re-exec no longer break the lifetime binding, an idle host no longer wakes several times a second, and an unreadable identity no longer counts as a dead supervisor. A child that accepts the private hop but never answers now fails startup after 10 seconds instead of retrying for the full 30. An engine that is started without its key refuses to run within two seconds (#3795).
- An RPC session whose unattached output queue overflowed now refuses reattachment with a typed
session_output_overflowerror instead of silently dropping replies. Clients can unload the retained runtime and reopen its transcript. Queue capacity accounting no longer walks every retained event on each enqueue, avoiding quadratic stalls during synchronous bursts (#3913, #3914). - An extension can no longer open or transfer a work obligation under the keys the engine uses for its own delivery tickets and wake sources (
delivery:andwake-source:);pi.lifecycle.obligationsrefuses them withReservedCustodyKey, so an extension ticket is no longer cancelled by a queue clear or retired as a stale wake source (#3986). - A project skill's MCP server that declares a reference object is skipped with the named refusal, trusted project or not, because the project environment policy expands only plain
${VAR}strings; skills you own andmcp.jsonservers keep reference objects (#3858). - Configuration references no longer corrupt structured MCP data when a value matches a key, boolean or number: only string leaves are redacted, including in cached catalogs, with cycles and deep data handled safely. A broken
models.jsoncredential-slot reference now skips only that slot with a named diagnostic; the request fails with a named error only when no slot remains. Authentication-required MCP errors are redacted in status and RPC snapshots. An invalid installation identity key warns once with its path, problem and repair steps without changing the file (#3858). - MCP server echoes of resolved configuration references are redacted from tool and resource results, progress, errors and spill files, including results sent to the model provider. Missing file and unset environment references now report a named error with a degraded server state in
/mcp status, logs and RPC loaded surfaces while other servers continue working (#3858). - A session on the worker session runtime now sees the same subscription limits as an in-process one:
pi.getSubscriptionLimits()andonSubscriptionLimitsread the host's polled records from the start, and limits a turn reports inside the worker reach the host's clients (#3695). - Reading a session's lifecycle (
get_stateorsession.lifecycle) no longer writes a lifecycle record to the session file. A user shell command, compaction, branch summarization and other session work now update the lifecycle when they start and when they are released, so the state a client reads is already current, including after a manual compaction with no run (#3980). - A prompt that carries
toolBarrierand is refused before its turn starts (for example an automatic prompt after an interrupted run, which needs a person or Resume) no longer leaves its tool barrier armed until the ceiling (#4106). - When
clearQueueremoves a queued itemizedsendMessagebefore it is written, the send and any re-send joined to it now reject withQueuedDeliveryClearedinstead of never settling (#4106). - A prompt, a scheduled or
/looptick, or a triggered delivery that arrives while a tree navigation writes its branch summary now waits for the navigation, instead of starting a run on the leaf being moved (#4154). - When the host and a worker session update the same account's subscription limits at the same instant, a plan the latest usage poll dropped no longer comes back from the other side's older copy, and every isolate settles on the same plan whatever order the updates arrive in (#4158).
- A disposed session's lifecycle binding no longer writes the consumed delivery's transcript entry:
consume()now goes through the same sink as every other lifecycle write, which writes nothing once the session is disposed (#4149). - Required compaction now tries shorter safe suffixes when default retention exceeds the context budget; failed recovery reports actionable budget or replay failures with unique-boundary counts and candidate sizes. Reported by 승기 (OmO KakaoTalk room). (#4163)
- Context-budget notices are persisted after the cached system prefix but before the current user prompt, keeping fallback dispatch on the user's request. A notice and its numeric estimate remain in history until compaction; reload and resume do not repeat it in the same compaction epoch (#4166).
Removed
@code-yeongyu/senpi-ai
Breaking Changes
Added
CredentialStore.readSlot(optional) lets a store resolve one pooled account for a slot-scoped request.resolveProviderAuthuses it, and refuses a projected key that is still an unresolved reference object with a namedConfigReferenceError(#3858).- Shared configuration-value schemas and runtime validation recognize exact
$file,$env, and flat$concatobjects, with named errors for malformed references (#3858).