- Added daemon incident notices to the agents view: recent worker crashes, command-timeout bursts, and update restarts surface as a dismissible status line pointing at
prime-agent incident. - The Anthropic subscription-auth warning now names the risk: subscription requests identify as Claude Code, which may violate Anthropic's terms and can get the account restricted or banned; an API key avoids the risk.
- Branch summaries now run through the
auxiliaryModelsetting, not just refinement and compaction passes. Branch summarization fires at a tree-navigation context boundary and the summarizer uses its own prompt prefix, so running it on the session model paid full input price at context peak for a one-off call outside the session's cached prefix. The summary falls back to the session model when the setting is unset, unusable, or its context window cannot hold the branch the summary covers plus the reserve the summary call needs. - Capped the spawning cell source attached to kernel host requests at 2KB with a truncation marker, so oversized cells stop re-shipping their full source on every spawn/progress-note/collect round trip and in each child's persisted spawnCode.
- Changed bundled model and MCP catalog assets to be generated during build and release instead of committed snapshots.
- Added bundled model and MCP catalog snapshots with hourly background refresh and last-good disk caches.
- Compaction summaries now run through the
auxiliaryModelsetting, not just refinement passes. Compaction fires at context peak and the summarizer uses its own prompt prefix (a different system prompt and no tools), so it cannot hit the session's cached prefix: on the session model the summary re-reads its whole input at peak price, plus a one-shot 1.25x cache write on Anthropic-style providers, and on OpenAI-style providers its divergent prefix still rides the session'sprompt_cache_key, which is the documented way to depress hit rates. Routing throughauxiliaryModelmoves that call off the session model. The summary falls back to the session model when the setting is unset or unusable. - Compaction summaries no longer request the session's thinking level. Summarizing is transcription rather than reasoning, and with no reasoning requested the summary call stays cheap and cannot trip an invalid reasoning effort on the summary model.
- Context-tree rebuilds (top-bar cost refresh, /context) now reuse a per-file parse cache keyed by file size and mtime instead of re-reading every finished child session on each refresh.
- Cleaned up contract hygiene in the agent family surfaces:
agent_observerows now carry the shared familystatus(running/idle/inactive) plus a separate typed liveactivity, the publicturn_endandmessage_updateevents are typed as assistant-only, Ctrl+C in the standalone config selector is remappable through the keybinding config, and the daemon revision catalog, agents-view emptiness comment, andpi-agentREADME no longer state facts the code contradicts. - Fixed quota parks restored after their wake time: a daemon wake or restart now keeps the park count so
retry.provider.waitForUsage.maxParksstill bounds re-parking, and the stale wake job is settled by the resumed session instead of lingering. - Bumped the daemon schema revision for the structured update-restart error info, so mismatched daemon and CLI builds around that change are detected by the self-update checks.
- Fixed agents-view roster summaries going stale when a session's spawn code changed while every other summary field stayed the same.
- Added
prime-agent incidentto reconstruct daemon incidents from logs into an operator timeline (supervisor events, session anomalies, recovery actions) with--since/--untilwindow and--sessionfilters. - The daemon supervisor, both daemon clients and the agents view now share the daemon protocol module's response and session-summary guards. The agents view now rejects a session summary that has no working directory instead of accepting it as complete (the daemon has always required it).
- Fixed session switches fetching the full transcript twice: a switch consumes the streamed replacement snapshot instead of refetching, so the history crosses the wire once when switching to a large session, while a switch whose replacement stream fails or never lands still reloads the transcript.
- Fixed a session switch reading a replacement snapshot streamed for another session (an earlier switch's late stream, or another client's switch on the same daemon session) as its own transcript, and made the switch wait end when the connection closes terminally or a re-attach resync delivers the requested session, instead of relaying its timeout.
- Prime Inference login and agent trace uploads now share one set of HTTP helpers (request timeout, error-body parsing, field readers). A Prime Inference request that is still waiting on its timeout no longer keeps the process alive on its own.
- Reduced per-model-request CPU cost by fingerprinting a bounded turn-body subset (model identity, shaping options, system prompt, message count, last message, tool schemas) instead of re-serializing the full request body, with the tool-schema digest memoized per session.
- Reduced event-flood CPU on busy workers: child update previews now collapse only the trailing ~200 chars of the streaming message (O(L²) → O(200) per streamed child message) with per-child update emits capped at ~1/s, roster flushes coalesce into a 250ms window and recompose only trigger-marked sessions (lifecycle mutations still flush everything on the next tick), top-bar cost refreshes from session status are throttled to 1/s (agent_end and attach stay unthrottled), and recap summarizer model calls are capped at 4 concurrent fleet-wide with the most recently active session admitted first.
- Fixed the daemon worker client keeping a stale socket after a failed or timed-out connect, so the next connect attempt on that client threw "already connected" instead of opening a fresh socket.
- Fixed a bridge write into a dead or stopped owned session worker (write EPIPE) crashing the whole CLI frontend: pipe errors are now absorbed so the existing worker close-based recovery (failing pending RPC commands and relaunching) runs instead.
- Fixed RPC commands that arrive while the worker bridge is down being reported failed ("uncertain and was not replayed") and then replayed to the replacement worker anyway: a command is now tracked as pending only once it is actually written to a worker, so buffered commands replay exactly once and commands that reached a dead worker fail exactly once.
- Fixed a worker that closed its stdin read end while staying alive hanging the frontend forever: the absorbed bridge EPIPE now kills the worker so the crash-recovery loop (failure responses, relaunch from the recovery descriptor) runs, and commands that were only buffered are failed when no recovery can replay them.
- Fixed
rlm.delete_subagentholding a deleted child's session name until its background unwind finished: the name now frees at the delete receipt, so a replacement child can be spawned immediately under the same name. - Fixed
rlm.collectthrowingNo direct RLM child matcheswhen a requested target was deleted moments earlier: collect now returns a settledcancelledenvelope for just-deleted targets immediately, without spending the timeout budget. - Fixed a daemon-mode respawn under a just-deleted child's name failing the name check: the delete receipt now frees the child's session name in the daemon catalog too — and the daemon host's runtime-boundary re-assert honors the same freed ids the spawn admission forwarded, instead of only the parent session's local run map.
- Fixed
rlm.collectresolving a reused child name to the previous generation'scancelledenvelope while the new child's delete was still in preflight: the selector now reports no match until the delete settles. - Fixed
rlm.collectthrowingNo direct RLM child matcheswhen a live child's background unwind had already finished before the parent collected it: the accepted delete now leaves a tombstone, so its settledcancelledenvelope stays addressable by child id and session name until the parent session is disposed. - Fixed
rlm.collectfor retained children deleted without an active run: a retained completed child or a daemon-hydrated child that never had a run now leaves the same delete tombstone as a live child, so collect answers with the settledcancelledenvelope its delete receipt promised, and a still-pending run-less delete blocks a reused selector instead of resolving to the previous generation's envelope. - Fixed
rlm.collectresolving a reused child name to the previous generation'scancelledenvelope while a live daemon-hydrated run-less replacement owns the name, including one whose delete failed and left it resident for a retry: the selector now reports no match until that replacement is deleted, matching the existing delete-preflight convention. - Fixed a Python cell raising an exception with a huge message restarting the kernel through protocol repair: error text and traceback entries are now capped at 1 Mi characters with a truncation marker, like result text, so the error is reported in the cell.
- Fixed an oversized
host_requestpayload (for example a huge skill-call argument) tearing the kernel protocol and restarting the kernel:rlm.host_request()now raisesValueErrorin the calling cell, likeemit()does for display payloads. - Fixed a stale background
bash()completion notice waking the model after it had already read the finished handle's result in the same turn (#2372). - Fixed kernel startup re-running the Python skill sync and rewriting the venv marker on every session when a skill depended on a sibling skill; such venvs now take the same zero-cost warm-start path as any other synced venv.
- Reduced Python kernel snapshot cost: auto-snapshots serialize each variable exactly once into a length-framed payload instead of a second whole-namespace dump (and no prefix re-dump at the aggregate cap), compaction re-serializes each variable once (bounded by the per-variable cap) and prunes only the ones that still measure oversized, so a value shrunk in place or redefined after an earlier snapshot is never deleted on a stale size, and a resumed kernel skips the auto-snapshot that would rewrite the just-restored namespace until a real cell changes it.
- Changed live Prime Inference catalog refreshes to rebuild each model's thinking levels and reasoning compat from the route's declared parameters, so stale bundled templates no longer override what the gateway actually accepts.
- Fixed the stored Prime team selection being hidden whenever the API key came from a runtime or environment override: an ambient PRIME_API_KEY supplies the key, never the team, so the stored login's team still scopes the credentialed catalog and private-model fetches and team-private internal routes keep appearing in the model picker.
- Fixed Prime Inference team headers having two owners: the provider layer no longer reads
team_idfrom the Prime CLI profile (~/.prime/config.json), so a runtime orPRIME_API_KEYcredential that deliberately has no saved Agent team stays team-less instead of inheriting an unrelated CLI team. The agent's auth storage stays the single source forX-Prime-Team-ID(saved team orPRIME_TEAM_ID). - Fixed shell-command credentials (
!commandAPI keys and header values) caching failures forever: a command that resolved to nothing is now retried on the next lookup, so a locked keychain or a transient failure no longer disables the credential for the lifetime of the process. - Fixed proxy streaming: a truncated response now ends with an error instead of leaving the turn waiting forever, and the service tier setting is now sent through the proxy like it is for direct provider calls.
- Fixed a queued prompt disappearing from the interactive queued-messages area while its own pre-turn compaction runs; it now stays visible there (as a "Starting" entry) until the turn begins.
- Added
/tierto show or set the session service tier (default, flex, priority, auto), aDefault service tierrow in/settingsthat also applies to the running session, and a footer badge for any non-default tier (RES-1326). - Folded the twelve per-kind continual-harness CRUD methods into three:
rlm.harness.create_memory(title, content, kind=...),rlm.harness.update_memory(id, title, content, kind=...), andrlm.harness.delete_memory(id, kind=...). Prompt notes, skills, and subagent specs are subtypes of memory, sokindselects them; it defaults tomemory, only skill entries acceptreference/arguments, the nine removed names raise an error naming their replacement, and the positional-kindcreate/update/deletemethods are removed as well. - Renamed the harness entry grouping from
pathtotopicin the kernel API, the refinement planner schema, and the harness digest; state files written before the rename still load, and saves keep writing the grouping under both names while older builds can still reach the shared global store. - Removed
rlm.harness.record_refinementandplan_refinementfrom the model-facing kernel surface. The refinement engine already records an event for every refinement it applies, so the manual call only duplicated those events or added unverified ones. Reading stays unchanged throughrlm.get_harness_state().refinementsand the harness overview; the old name now raises an error explaining that events are recorded automatically. - Provider retries now add +/-25% jitter to their computed exponential backoff so concurrent sessions spread out during a shared outage instead of retrying in lockstep; server Retry-After waits are still honored exactly.
- Cut redundant broadcast work under streaming and fleet load: the supervisor now compares roster rows against their last published serialization so repair pulls, snapshot applies, and staleness sweeps no longer re-broadcast identical entries to every subscriber; child update dedup compares fields instead of building and serializing a full snapshot per streamed delta (the prompt label is computed once per run); and queue updates serialize the snapshot once instead of twice per mutation.
- Fixed provider safety-filter failures (e.g. content_filter) being auto-retried: they are permanent rejections.
- Stopped fanning supervisor heartbeat lists, scheduled-job wake recomputes, and cron-store mutations out to every worker, client, and artifact path: worker heartbeat snapshots refresh per reporting worker, the wake timer arms from a cached aggregate (a changed stale-while-revalidate refresh re-arms it), heartbeats_changed pushes reach only clients that track heartbeats (by scheduled-job command or the heartbeat_catalog attach capability; daemon-side lookups now also resolve paused and cancelled passive jobs), and cron-store mutations lock just the paths they write with one fsync and non-blocking retries.
- Added
prime-agent sessions, a one-line-per-agent operator table (status, activity, staleness, last error, usage) rendered client-side from the existing daemon session summaries. - Runtime extension discovery now applies the same rules as package resource discovery: entries matched by a
.gitignore,.ignoreor.fdignorefile in the extensions directory, dot entries andnode_modulesare skipped, so a directory excluded from package discovery is no longer loaded at runtime. - Ignore-file parsing, extension entry-point resolution, resource path expansion and path containment checks now each have one implementation instead of two to four copies, so the loaders can no longer drift apart.
- Fixed unclear blocked-update warnings: the refusal now names the blocking session, and the report now says to run
prime-agent shutdown, then runprime-agentto restart and apply the update. - Fixed
shutdown --forcefailing with "Daemon shutdown admission was lost" when slow daemon scans delayed the admission lease refresh. - Changed agent trace uploads to report every scheduled upload and retry wait, and to expose when the startup catch-up and in-flight uploads have finished.
- Added
PRIME_AGENT_PROBE_TIMEOUT_SECONDSso an install can override the executable probe deadline that otherwise defaults to 60 seconds. - Changed the daemon worker supervisor monitor to report when each availability check settles, so its recovery behavior is observable instead of timing-dependent.
- Fixed inline pickers drawing two stacked separator rules when an empty placeholder child preceded the search box, which also cost the list a visible row.
- The per-service accounts menu (open /mcp and select a connected service) is rebuilt as a static choice list in the onboarding-choice visual language: "Accounts — Cloudflare" became "Cloudflare MCP" with the service description moved above the options (muted, wrapped, capped at three lines), the no-op search box and the account-name row are gone, and the rows are
Reconnect,Disconnect <account>andAdd another account— one reconnect/disconnect pair per account, labelled with the connection id, with no right-hand status column. Reconnect runs the existing re-verify path and never disconnects; Disconnect keeps the store-locked removal and its durable◆ Disconnectedentry (ENG-6108). - The /mcp catalog picker shows the "Connect" trailing status in the plain text colour instead of the accent purple, and the "No matching services" empty state now has one blank row above the shortcuts line and starts in the same column as the row labels.
- Fixed alias ("Add another account") MCP connections always registering an OAuth provider: per-account connection ids now follow the same catalog classification as their parent service, so a second account of a paste-a-key token service (or a requires-setup or otherwise non-OAuth service) is never offered a browser login whose stored grant dispatch would reject. The account keeps its parent's token-based treatment instead — a pasted
mcp_static_tokenstored under the account's ownmcp:<connectionId>key makes it dispatchable and verifiable exactly like the first account — and an account of a public no-auth service stays credential-free rather than being reclassified as OAuth (ENG-6108). - The MCP service surface (/plugins picker, mcp host handlers, system-prompt inventory) now advertises only one-click DCR or user token/key connectors (2026-09-15 final catalog cut): the user-own-app OAuth path (GitLab, Miro, Supabase, Vercel, monday.com, ZoomInfo, …), the 32 local stdio adapters and the url-only tenant templates were removed from the shipped catalog, so the picker no longer surfaces providers Prime cannot connect with one-click auth or a user token/api key (ENG-6108).
- Removed the duplicate sentence under an MCP connect entry: the
◆ Connected <service> · <n> tools verifiedheader now stands alone, and the body keeps only what the header omits (added account, verification issue and next step, deferred activation). - Added the same durable feedback for MCP disconnects: a successful
/pluginsdisconnect,/mcp logout <name>, or/logoutof an integration now leaves a muted◆ Disconnected <service>entry in the chat, with the removal scope and account on expand. A failed or partial removal keeps its honest warning and records nothing. - Added a bundled
mcpskill that teaches catalog search, connection checks, schema inspection, generic tool calls, and error handling for any MCP service. - Added discovery APIs to the pre-imported
mcpmodule:list_plugins,search_plugins,list_connections,search_tools, anddescribe_tool, with bounded pages, complete-or-fail tool discovery, isolated schema copies, and no credentials or raw provider errors in inventory results. - Removed the bespoke Linear and Notion Python integration packages; those services now use the generic
mcpmodule and connection records like every other service. - Hardened MCP endpoint verification so an unresponsive server can never hang it: fetches, response bodies, and session-termination cleanup are now bounded by an abort signal with a cleanup grace deadline, and connection-record writes create the store file exclusively so a first writer cannot wipe another process's records, requeueing failed writes until they commit (ENG-6108).
- Fixed MCP verification and background probes so they can no longer overwrite an in-flight login's account claim; every verification write is compared against the record and credential snapshot it was computed from.
- Added an honest "Login in progress" state for accounts with an active login attempt, replacing the misleading missing-credential Reconnect across the service picker, connection inventory, and host actions; a second Connect or Verify waits while Remove stays available.
- Made reserved built-in names conflict-aware: an equivalent user declaration keeps working, while a disabled or conflicting same-name entry now shows an explicit conflict or disabled state instead of a Connected card that cannot dispatch.
- Restricted installed-account repair to its exact saved connection id at its durable approved endpoint, so changed catalog URLs are never silently followed and a pending placeholder alone is not treated as approval.
- Changed unreviewed imported OAuth entries to offer an explicit Connect attempt (with an unverified notice) instead of a blanket metadata-review block, while keeping real API-key, setup-required, and registered-client restrictions.
- Ordered the service catalog so connected accounts and ready-to-connect services appear first, with every service still searchable and visible.
- Added optional per-server OAuth client identity settings (
oauthClientId,oauthClientSecretEnvVar,oauthClientMetadataUrl,oauthScopes), wired through one shared provider factory into both login and refresh registrations; a configured secret environment variable that is missing or empty fails closed before any network request. - Changed the kernel runtime readiness check to require the MCP discovery methods (list_plugins, search_plugins, list_connections, search_tools, describe_tool), so a stale cached kernel venv is rebuilt instead of silently accepted (ENG-6108).
- MCP account logins and the /login and /logout service selectors now mount inline under the chat through the same auth-panel surface as provider logins (#2331) instead of centered overlay popups: the guarded staged OAuth dialog, the mcp-connections tab, and the /mcp login route replace the prompt area with stacked closers, focus restore, and terminal-rows-aware list sizing (ENG-6108).
- Paste-a-key MCP services are now connectable from the TUI: selecting a requires-setup token service (GitHub, PagerDuty, the Zoom endpoints, and the other catalog token services) opens an inline masked paste panel on the same inline surface as the OAuth login panel, prompts exactly ONCE for the service's single credential (labelled from the field, e.g. "GitHub personal access token"; alternative field names for the same credential share one prompt), and stores the result in the agent credential store (auth.json under the same
mcp:<connectionId>key OAuth uses) with an explicitmcp_static_tokencredential shape — never settings.json, never a status line, log, or transcript entry (ENG-6108). - The picker row for a pasteable service now reads as an action ("Enter paste token") instead of a dead-end hint, and an account picker for a stored token service keeps a "Paste a new token" row so a rejected or rotated token gets a new paste rather than a re-verify of the same value (ENG-6108).
- Catalog token services accept the stored pasted token as a credential source alongside the settings env var: eligibility,
mcp.configdispatch (acredentialSource: "static-token"marker; the kernel attachesAuthorization: Bearerfrom the endpoint-bound stored credential only), and verification all consume one shared usability rule (typed, endpoint-bound, non-empty bearer). Every fail-closed rule is kept — setup field ids are never read as env vars, credentials bind to the exact connection id and endpoint, reserved/shadowed names still fail, and an unset env var with no stored credential still reports setup_required. A service whose upstream collects more than one distinct credential (the catalog cuts those at import; a local source could still declare one) is not pasteable and stays honest setup_required instead of collecting values the single-bearer runtime would never send (ENG-6108). - Token-service verification uses the stored pasted token for the real MCP handshake: success records the same durable "Connected · N tools verified" entry as OAuth, a rejected or failed verification reports unverified ("Token saved for , but connection verification did not complete: …") and never claims Connected, and a token rotated or removed mid-probe discards the result instead of marking the new token verified (ENG-6108).
- Reworked the generic MCP OAuth engine: SDK-standard client-auth-method negotiation (client_secret_basic/post/none), full RFC 7591 registration responses with persisted DCR client identity/secret and expiry, client-initiated metadata (SEP-991, configured client-metadata URL as client id when advertised), SEP-835 scope precedence (configured > protected-resource > omit, never a server-wide join), RFC 9728 origin-level resource audiences for pathful endpoints (Notion/Slack shape) with audience-pinned refresh binding, bounded and cancellable discovery/registration/token requests, and sanitized typed OAuth errors (ENG-6108, PR2256).
- Hardened MCP account recovery so no edge can silently strand a credential: logging out an account now removes a credential-only integration even when no connection record exists, a failed commit or its failed rollback now reports an explicit recovery-required state instead of claiming nothing changed, an ordinary login that wrote the account key mid-flight is never clobbered or deleted by a concurrent staged login, and one-shot store operations settle cleanly when the file lock itself cannot be acquired (ENG-6108).
- Staged MCP logins now move their credential to the account key with a disk-authoritative compare-and-set under the auth backend's own file lock (set-if-absent move, exact-own restore, remove-only-if-matching): a bystander credential written by another process can no longer be overwritten or deleted by a get/set race across instances, and disconnects whose record save fails after the logout report the honest partial state (logged out, change not saved, retry to finish) instead of claiming the account is still connected (ENG-6108).
- The generic /logout route now delegates an MCP account logout to one shared store-locked operation (verified credential deletion plus pending-attempt cancellation under the store->auth ordering, before the route touches auth): a concurrent finalize can never re-create the credential after the logout, a failed verified auth removal fails the whole operation and cancels nothing, completed account records are preserved (honest unbound/Reconnect state), and staged keys map back only through their recorded attempt nonce — never a blind split (ENG-6108).
- A staged-key logout (a login attempt's pending credential selected in /logout) now cancels the attempt — invalidating its reservation nonce so the in-flight login can neither finalize nor delete the record — while preserving the account shell record and never touching another client's ordinary-login credential on the real key; the route reports it state-neutrally ("This login attempt is no longer current; manage the account from /plugins") instead of claiming Logged out or Connected (ENG-6108).
- Every user-facing MCP OAuth login (initial /plugins connect, error-state reconnect, add account, /mcp login, the generic /login service options, and the config menu) now routes through ONE guarded host operation: the account is claimed under the connection store's file lock first (a nonce claim on existing records, a pending reservation for fresh ids — even credential-only legacy accounts, whose current on-disk grant identity is captured), the OAuth credential always stages under a per-attempt key, and a guarded finalize commits it with a full-identity compare-and-swap (set-if-absent for fresh accounts, replace-only-if-matching for intentional replacements) that consumes the attempt nonce and marks the record pending-verification; a cancelled or failed login releases the claim without touching the existing account, a failed record write restores the PREVIOUS credential under the same lock, and a concurrent logout cancels the attempt so a late OAuth callback can never reactivate or clobber the account (ENG-6108).
- Fixed explicit MCP logins disconnecting connected accounts, false login-success results, and unguarded OAuth fallback paths. Cancelled logins keep account settings available for reconnect or removal.
- Catalog MCP entries without OAuth now fail closed: only explicitly public no-auth, setup-ready rows are eligible for credential-free dispatch, and an expired grant without a refresh token, a wrong-type, or an empty-access credential is no longer treated as authenticated; a configured bearer env var is the only credential source when set (ENG-6108).
- The MCP service catalog cap now always keeps installed connections — including entries whose descriptor is still in a source — and reports explicitly when installed connections alone exceed the cap (ENG-6108).
- Added
/pluginsand bare/mcpas a searchable external-service picker showing honest connection states (Connect, Connected with verified tool counts, Reconnect, Needs verification, Requires setup, Disabled), with connect via browser OAuth, automatic post-login verification, and disconnect (ENG-6108). - Added kernel host requests
mcp.list_plugins,mcp.search_plugins, andmcp.list_connectionsexposing the supported-service catalog and the user's actual connections, with strict status filtering, bounded limits, and honestnextCursorpagination (ENG-6108). - Added local MCP connection records (
~/.prime/agent/mcp-connections.json) separatingconnectionIdfrom catalogserviceIdand binding verification to the endpoint; a stored token alone now reports as pending, never Connected (ENG-6108). - Connected catalog services (Linear, Notion) are now served through the generic Python
mcproute (system-prompt inventory +mcp.config), so per-service wrappers are no longer required for dispatch (ENG-6108). - Changed MCP connection verification to run through the official @modelcontextprotocol/sdk client with explicit session termination, fixed safe failure categories (no endpoint URLs or server text persisted), and queued activation at the next turn/compaction boundary so a login during streaming never asks for a manual /reload (ENG-6108).
- Changed connection records to use file-locked read-modify-write writes with unique temp files, and bound every verification result to the grant it verified so a stale probe can never mark a rotated or disconnected account Connected (ENG-6108).
- Bound every stored MCP credential to its endpoint for catalog services and user servers alike: unbound or cross-endpoint grants are refused before any token fetch or probe, surface as Reconnect with a fixed category, and are excluded from dispatch; the OAuth registry reset hook now re-runs a full atomic provider reconciliation so catalog providers survive refresh and removed user overrides restore in one pass (ENG-6108).
- Verification guards now re-read fresh auth.json state at persist time, so a probe finishing after another client logs out or rotates the grant can never persist a stale Connected record (ENG-6108).
- mcp.connect reports connected only after a verified handshake (with tool count) and maps handshake failures honestly; stdio servers managed through settings can be disabled from /plugins instead of showing a fake disconnect (ENG-6108).
- Wired the /plugins picker and the mcp host handlers to one shared catalog resolver: the merged built-in SERVICE_CATALOG plus settings-declared local sources (mcpCatalogSources, ~-expanded, missing-file and duplicate-id diagnostics, total cap), with unreviewed imported entries surfacing as candidates rather than one-click Connect and user-placed local files connectable through the login dialog (ENG-6108).
- Added per-account connections: adding an account allocates a distinct connection id (its own credential key, record, and OAuth provider), the account picker reconnects or disconnects the chosen account, and per-account ids stay dispatchable through the same integrations, inventory, and verification machinery (ENG-6108).
- Account ids are allocated through a durable, file-lock-atomic reservation written before the login starts: cross-process races produce exactly one winner, configured user/catalog ids are never taken, and a cancelled login releases only its own pending marker (ownership-validated), so a late callback cannot remove or resurrect another client's account (ENG-6108).
- Service cards aggregate every account of a service: all account ids are listed and searchable, the inventory emits one row per account with its own status, and a remaining account keeps its service visible and manageable after the default account disconnects; connections whose optional catalog source vanished keep a pinned definition at the recorded endpoint (ENG-6108).
- Pending accounts retry verification explicitly without a relogin, error accounts keep Reconnect, every account has an explicit Remove action, and a login whose verification result could not be saved reports pending instead of a false Connected; one unreadable local catalog source no longer blocks startup — built-ins and other sources survive with a visible diagnostic (ENG-6108).
- Account logins stage their OAuth credential under a per-attempt key and commit it to the real account only through a lock-guarded finalize that validates the attempt nonce: cancelled, replaced, or failed-write reservations never receive a late credential, and reservation callbacks resolve only after the durable record write commits (ENG-6108).
- Every per-account status now flows through one computed helper (credential binding, expiry, and record combined): the plugin aggregate, the connection inventory, and the account picker agree, so stale Connected records surface as Reconnect; catalog metadata aliases are part of the search surface again (ENG-6108).
- Account-removal transactions now run under one store lock with finalize: disconnects delete the credential and the record atomically (removeAccount), a failed finalize write compensates its credential move under the same lock, and every one-shot store callback settles exactly once — batched reserves in a failing write all resolve false with no hang, no ghost, and a working retry (ENG-6108).
- Changed the MCP catalog and account pickers to match the compact inline model and provider pickers, with searchable single-line rows, selected connection details, explicit action hints, and preserved editor drafts.
- Clarified local-server disable and settings-only HTTP actions, preserved explicit verification and saved-data cleanup, and hid unsupported OAuth account actions for settings-managed connections.
- The MCP service surface (/plugins picker, mcp host handlers, system-prompt inventory) now advertises only zero-app self-serve connectors (2026-09-14 product decision): providers that require a provider-registered OAuth client (Figma, Slack, Gmail, Google Calendar/Drive, MongoDB Atlas) or whose self-serve path stayed unverified (Shopify, HubSpot, LogRocket, and others) were removed from the shipped catalog, so the picker no longer surfaces providers Prime cannot connect without a vendor-registered OAuth app (ENG-6108).
- Collapsed a service's /mcp accounts menu to exactly one Reconnect, one Disconnect, and one Add-another-account row: with several accounts, Enter on Reconnect or Disconnect opens a second inline picker that lists the accounts, and picking one runs the action on that connection id only (Esc or left there returns to the accounts menu without acting). Left arrow from a service's accounts page now navigates back to the /mcp catalog, remounted fresh; Esc still closes the whole chain and left in the catalog itself stays inert.
- Changed MCP connect outcomes ("Connected Linear (12 tools verified)" and its saved-but-unverified variants) from transient status lines into persistent chat entries styled like harness refinement notices: a purple
◆ Connected <service> · <n> tools verifiedheader over the existing wording, account and activation details on expand, and the same durable record when a mid-turn connect activates at the next safe boundary. - Fixed paste-a-key connection outcomes rendering as a malformed-message error, named the service instead of the picked row, told rejected tokens how to recover, and tightened the accounts menu spacing and selection bar.
- Fixed duplicated rows and scroll counters in the MCP service picker: multi-line catalog descriptions are flattened so a rendered line is always exactly one terminal line.
- Fixed the /mcp picker chrome from live testing: the scroll counter aligns with the row indent, one blank line separates the list from the description line in catalog and accounts mode, and every inline picker opens with exactly one separator rule between the chat view and the picker (a titled panel draws the rule above its title; a headerless panel keeps the bordered search's top border as that rule, never both).
- Changed Enter on an account row in the accounts picker to re-verify the account instead of disconnecting it; only the explicit Remove row removes, and the accounts search now matches only the fields that distinguish rows (account label and connection id) instead of the description text every row shares.
- Reworked the picker search ranking: exact/prefix/word-start/substring matches on label, service id, and aliases rank far above description and setup-hint text, scattered subsequence hits no longer qualify, and a query that matches nothing shows the "No matching services" empty state — searching "vercel" against a catalog without Vercel now returns zero rows instead of eight unrelated connectors.
- Fixed the /mcp and /plugins service-catalog picker: the selected connector now gets exactly one fixed description line with the shortcuts directly underneath (no blank separator, no viewport-driven description resize), the visible row window rebuilds from current state on every render so frames can never disagree about which rows are visible or selected, and the scroll counter stays honest — it counts every rendered row, which is the shipped catalog plus installed connections pinned from records (75 + 2 = 77 for the ENG-6108 cut).
- Kept the /mcp picker open after every connect, disconnect, reconnect, paste, or add-account action instead of dropping to the prompt: the chain re-enters the right surface (that service's accounts menu while it still owns an account, otherwise the catalog), rebuilt from the live catalog and connection store so a removed account is gone and a fresh one shows. Esc still closes the whole picker, and an action that cannot proceed reports its status and never re-opens.
- Fixed Escape and Ctrl+C while steering messages are queued: the active run aborts and all queued user steering messages now start together in one new agent turn, preserving order and consuming the queue; an empty queue stays abort-only and the steering mode setting is unchanged.
- Private worker framing now decodes large frames in linear time across socket chunks: delivered chunks are kept as-is and a completed frame's bytes are joined exactly once, and consumed chunks are skipped via a head cursor with amortized compaction instead of being shifted off the queue one per chunk, so a multi-MB frame arriving in small writes can no longer pin the event loop.
- Fixed no-skill kernel bootstrap calls (postinstall, runtime-bootstrap) wiping the recorded Python skill map from the .bootstrap-version marker, which forced the next real session to re-sync every skill: a no-skill call now leaves the recorded skill set untouched and only skill-syncing callers rewrite the marker.
- Classified Windows worker named pipes as worker sockets in
prime-agent ps, so worker pipes are no longer listed as daemons. - Made the collapsed summary/header rows clickable in fullscreen chats: tools and IPython cells, agent messages, refinement and compaction/branch summaries, skill and injected-prompt cards, bash and shell blocks (including inside side-question popups), collapsible errors, startup resource sections, and custom messages toggle only the clicked item; Ctrl+O still resets all conversation detail globally.
- Harness digest ranking and harness search now weigh matched query terms by document frequency (tf-idf style), so rare distinctive terms rank above entries dense in ubiquitous words.
- Sped up first-run installs by skipping pip/setuptools/wheel seeding when creating the kernel Python venv; every kernel package is installed with
uv pip, so the seeded tools were never used. - Reduced Python kernel startup time by deferring the event-loop import stack (asyncio plus the shell tool's heavy stdlib imports) until after the ready event, with no protocol or behavior changes.
- Fixed harness digest re-delivery busting the provider prompt cache: cold boundaries (resume, context rebuild, post-compaction head) now compare a harness state fingerprint instead of the rendered digest text, so unchanged harness state no longer re-delivers a digest that turn-drifted relevance terms made look stale; the compaction summary carries the fingerprint for the same skip rule, and ranked digests break score ties on stable identifier order instead of
updated_atrecency so an unrelated entry update can no longer reshuffle the visible window. - Fixed: compaction, branch, and refine summaries now label each serialized tool result with its tool name, so parallel tool calls can be paired with their results.
- Fixed: failed tool results are marked as errors in the label, keeping failure attribution visible in summaries.
- Fixed: serialized tool calls now carry a sequential
#Nprefix and results repeat the matching index, so repeated calls of the same tool pair unambiguously. - Fixed the kernel stderr log (
kernel-stderr.login the session artifact directory) being created world-readable: the log is now owner-only (0600), and its directory is created owner-only (0700) when the kernel manager creates it, matching the kernel state snapshot and the other private session artifacts, because kernel stderr can carry exception payloads. - Corrected the documented defaults in
docs/settings.mdanddocs/themes.md: unset thinking starts atmedium(notxhigh), the default theme isprime/light(notdark),transportdefaults toauto(notsse, andwebsocket-cachedis a valid value), and the removedcollapseChangelogsetting is no longer documented. - Chats now start at the middle conversation-detail level (edit diffs expanded, thinking visible, tool output still summarized) instead of the most-collapsed overview; Ctrl+O keeps cycling overview -> details -> all unchanged.
- Added a pre-push guard hook that refuses mirror-like pushes and remote branch deletions to real GitHub remotes, with an opt-out via PRIME_AGENT_ALLOW_MIRROR_PUSH=1.
- Fixed opening an agent from Agents View during a daemon auto-update failing with "Daemon is preparing an update restart": the open now waits through the update restart (bounded) and reconnects once the daemon returns, with a notice that it waited instead of a hard failure.
- Fixed
heartbeats_listtiming out on busy daemons: the supervisor now answers from a shared in-memory scheduled-jobs snapshot (one in-flight disk scan serves every concurrent catalog request, heartbeat mutations drop the snapshot, aged snapshots refresh in the background), and sibling name scans no longer hold the serialized ledger queue that scheduled-catalog topology reads wait on. - Fixed an unhandled error on the kernel child stderr pipe crashing the daemon worker: the stream now records a kernel diagnostic like stdin and stdout instead of reaching the daemon uncaughtException handler and exiting with every hosted session.
- Fixed short-lived sessions re-paying the whole Python kernel skill sync or wiping and rebuilding the venv after being killed mid-sync: the bootstrap version marker is now written atomically and persisted incrementally (base first, then after every installed skill), so the next session resumes only the remaining skills instead of starting over.
- Fixed spawn name reservations releasing before admission was durable, which let two parallel same-name spawns both admit and write duplicate ledger edges that made child selectors ambiguous.
- Added model and reasoning effort pickers for ACP clients such as Zed, with model-specific effort options.
- Reduced daemon disk churn: the scheduled-jobs catalog now re-parses only when its file changes, instead of on every heartbeat and agents-view poll and two to three times per mutation.
- Fixed worker CPU growing with session size: roster heartbeat flushes no longer re-walk every message for the latest-activity timestamp, no longer re-compose and re-serialize unchanged session summaries each cycle, and the heartbeats list no longer builds a full session summary per registered job per poll. Unchanged sessions reuse their last composed roster entry; any live-state change (new message, streaming, bash, compaction, verdict, or registration flag) still recomposes and publishes the same wire delta as before.
- Timer-driven goal and autonomous continuations now pause while background
bash()handles are still running instead of re-prompting the waiting agent: the last handle settling is the wake-up (its completion notice is delivered first, then the held continuation resumes behind it without spending continuation budget while it waits), and the kernel now notifies the host when its live background handles settle or the kernel tears down. - Added the
/speed [on|off]session command: toggles a compact footer readout of model output tok/sec (latest response plus session average), computed from existing stream events with no provider protocol changes. - Harness store writes now validate entry shape before persisting:
rlm.harnesscreate/update/upsert calls reject non-string or emptytitle/content, empty or non-string ids, malformed paths, non-dictreference/arguments/metadata, and skill entries without a valid Python reference, with a clear error naming the entry and the violated entry field; refinement events reject non-string triggers and invalidchanges/ids./refineand rollback edits reject the same shapes throughvalidateEdit. - The harness digest and refine overview now skip malformed persisted entries and refinement events (non-object events plus events with non-string ids, triggers, change elements, or outcomes, labeled by bounded type instead of value) with a
harness: skipped malformed entry <id> (...)diagnostic line instead of crashing session creation, so a single corrupt store entry can no longer brick every session and child spawn. - Added an
imageModelsetting that routes image-attaching turns to an image-capable model when the session or subagent model is text-only. - Image turns on a text-only session model now fail with an actionable error naming
imageModelinstead of silently dropping the images when the setting is unset or unusable. - Attached TUI windows now recover automatically when the daemon restarts: a shutdown close polls the same socket path for the reconnect window (60s by default) and then re-attaches the session and refreshes the transcript instead of dying; if the daemon stays gone, the saved-transcript message remains.
- Daemon update restarts now announce the update close reason on every attached window, so all windows (not just the one running /update) restore their sessions.
- A one-line banner reports restart recoveries, and warns to restart the window when the restarted daemon is newer than this window's binary.
- Fixed withdrawn background command completion notices silently dropping parked next-turn messages: cancelling a queued turn now re-parks its undelivered prefix records, so deferred context (kernel state restore notices, goal context, deferred RLM child terminal notices) is delivered on the next turn instead of being lost.
- Changed the session catalog scan to count tool-result (and extension-role) message entries from their serialized header instead of parsing their payloads, cutting the CPU a cold scan spends on transcripts whose tool output dwarfs everything else.
- Parked quota-blocked sessions now resume from a wake that survives aborts, restarts, and daemon-delivered wakes instead of clearing the park or stalling the resume, and a park no longer fails an active goal: the goal resumes with the task at the wake.
- Catalog metadata updates (renaming a saved session, archiving a stopped worker, marking a recovered session interrupted) no longer parse the whole transcript: each appends a single line after validating the session header, so routine actions on multi-MB sessions avoid the full-load stall and memory spike. A missing or header-invalid session file now fails the update with a clear error instead of being recreated or silently rewritten as a fresh session. The interruption notice stays advisory during worker recovery: a notice that cannot be written is logged, and recovery still reaps orphaned processes and resolves its journal.
- Changed the daemon to start its session catalog process on demand: the catalog is no longer spawned at supervisor boot, so an idle daemon keeps one fewer compiled runtime resident. The catalog spawns on the first session-file operation (agents view,
list --all, session rename/delete/archive) and stays resident once started. - Changed session context assembly to carry only the newest harness digest: older digest custom messages are skipped when the context is built, a fresh cold-boundary digest replaces the copies it supersedes instead of stacking, and a compaction head's digest snapshot yields to any digest appended after the compaction. Persisted transcripts are unchanged; the newest digest remains authoritative.
- Cached the active branch path in the session manager, so per-turn compaction checks and context-usage updates no longer rebuild the whole leaf-to-root path after every assistant message.
SessionManager.getBranch()now returns the live shared branch array (public API): repeated reads return the same array object and straight-line appends extend it in place. Callers must treat it as read-only and take.slice()for a snapshot;session_before_compactalready passes a snapshot.- Fixed compaction summaries drifting behind the retained conversation: the summarizer now receives the newest kept-tail assistant text as a
<recent-state-anchor>and the in-context[compaction-summary]prefix states that the retained messages below are authoritative. - Fixed compaction file lists compounding through repeated summaries:
<read-files>/<modified-files>blocks are stripped from the previous summary before the update prompt (entry details plus the fresh append remain the single source), and the combined file lists are capped at 6000 characters, dropping read-only entries first. - New request timing diagnostics:
PI_REQUEST_TIMING=1(or settingsrequestTiming: true) logs the phase timeline for each request made by the agent stream - prompt-built, request-sent (with body bytes), first-byte, first-token, stream-done - to~/.prime/agent/logs/agent.jsonlundercoding-agent.request-timing, so a longWaitingstate can be attributed to client-side build, upload, provider prefill, or a prompt-cache miss (summary usage shows cacheRead/cacheWrite). Zero overhead when disabled. - Added a session-start
[python-skills-unavailable]notice when a pre-imported Python skill fails to import into the kernel. The report names each failed skill import and its import error so the model learns before its first call instead of from the unavailable-skill placeholder, in both the TUI and headless sessions. - Fixed kernel REPL protocol output that could buffer unbounded memory in the host: Python-level stdout/stderr writes now ship as 64 Ki-char frames, oversized result reprs are capped at 1 Mi chars with a marker, oversized display payloads fail the cell, and the host repairs a kernel that streams an oversized protocol line.