Skip to content

v2026.10.24-2

Choose a tag to compare

@github-actions github-actions released this 24 Oct 14:36
· 711 commits to main since this release

@code-yeongyu/senpi

Breaking Changes

Added

  • Shared RPC hosts support live-only attach_session, one-hold release_attachment, and atomic reclaim_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.key in the agent directory, created once with mode 0600), 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, /mcp errors and the shared stderr and stdout scrubbers, in raw and URL-encoded form; data sent back to servers keeps its exact bytes (#3858).
  • mcp.json accepts $file, $env and $concat reference objects in headers, env and args. 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.json accepts $file, $env and $concat reference objects in an API key's key and in each pooled account's key. 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 $file path 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); nohup at best leaves an untracked orphan that the call's timeout still group-kills (the full race and setsid analysis lives in the terminal tracker); a non-persistent monitor's timeout_ms kills the watched command; a timed-out local command watch now summarizes as watcher killed at deadline (timed_out) while RPC watches keep watcher 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=1 enforces immediately. release_session excludes 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_page tool description now tells the agent to load the bundled visualize skill before building a page (#2869).
  • The agent no longer pauses after 150 turns it starts on its own after one message: engineTurns.maxPerUserInput now defaults to 0 (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 sendMessage that re-sends a delivery ticket whose message is still queued, with different items, is now rejected with DeliveryTicketRefused (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 real rpc.sock can no longer take it over. get_protocol_info reports the host's agentDir (#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_overflow error 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: and wake-source:); pi.lifecycle.obligations refuses them with ReservedCustodyKey, 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 and mcp.json servers 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.json credential-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() and onSubscriptionLimits read 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_state or session.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 toolBarrier and 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 clearQueue removes a queued itemized sendMessage before it is written, the send and any re-send joined to it now reject with QueuedDeliveryCleared instead of never settling (#4106).
  • A prompt, a scheduled or /loop tick, 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. resolveProviderAuth uses it, and refuses a projected key that is still an unresolved reference object with a named ConfigReferenceError (#3858).
  • Shared configuration-value schemas and runtime validation recognize exact $file, $env, and flat $concat objects, with named errors for malformed references (#3858).

Changed

Fixed

Removed

@code-yeongyu/senpi-agent-core

Breaking Changes

Added

Changed

Fixed

Removed

@code-yeongyu/senpi-codemode

Breaking Changes

Added

Changed

Fixed

Removed

@code-yeongyu/senpi-tui

Breaking Changes

Added

Changed

Fixed

Removed