Documentation
What’s new in v0.16.4
Published 2026-09-05. This page is generated from the immutable release changelog.
Added
- Added selectable
astra-lite,astra-default, andastra-heavyCODEX presets withASTRA-labels, plusastra-fableandastra-fable-opuscross-family review combinations. Existing presets and automatic provider recommendations remain unchanged. - An interactive
gjcnow shows up inside Paseo by itself, controllable from the desktop and mobile apps, instead of only being reachable when Paseo started it. Every terminal session already registered its SDK endpoint with the broker, and GJC's ACP surface already resolves aliveindex entry straight to the running host — asession/loadattaches to it rather than resuming a second copy — so the only thing missing was telling the Paseo daemon the session exists. That is now done at interactive startup withpaseo import --provider <key> --cwd <cwd> <session-id>, which makes the terminal session and the Paseo agent the same live session rather than two transcripts. The announcement is gated so it costs nothing when it cannot apply: an absent$PASEO_HOME/config.json(default~/.paseo/config.json), no enabled GJC ACP provider entry, nopaseoon PATH, a daemon that is not listening, or a session the broker does not yet report as live each stop it before anything is spawned. The daemon check is a plain socket probe rather than a CLI invocation because the Paseo CLI blocks indefinitely when its daemon is down (measured: no output and no exit after two minutes), and the liveness check exists because importing a not-yet-registered id would makesession/loadfork a second host for a session that is already running. While the daemon is merely not up yet, the probe retries every 30 seconds for approximately ten minutes on unref'd timers, so launching Paseo after the terminal still works; the loaded opt-in can cancel its own pending or active announcement, changes made by another process apply on the next launch, and Paseo's own duplicate-import refusal is read as success. Interactive-only by construction — agjc acpprovider process never builds the interactive mode, so an imported session cannot announce itself back. Create-only by construction too: GJC adds an entry and never deletes, archives, or rewrites one, so it can never remove an agent you still wanted. The consequence is yours to manage — every interactive start gets a fresh session id (includinggjc -c), so each launch adds one row, and ending a session leaves its row listed asidleuntil a send fails withSDK session attachment is staleand Paseo marks iterror; prune withpaseo delete <agent-id>. Opt-in: the new operator-ownedpaseo.autoImportsetting is off by default, so a repository cannot enable it and an installation that never asks for it never reads a Paseo file, probes a socket, or spawns the CLI; enable it withgjc config set paseo.autoImport true(Settings → Interaction → "Announce Sessions to Paseo"). Seedocs/terminal-app-integrations.md. - Corrected a stale claim in
docs/external-control-readiness.md: interactivegjcsessions are broker-registered and are listed by ACP clients, and an ACPsession/loadagainst a live entry attaches to the running host instead of resuming a copy. - An externally submitted prompt against a session on the SDK-only host runtime no longer hangs forever after its turn has already finished. That runtime published the lifecycle boundary as a bare
{ type, sessionId }frame: it computed each ended invocation'scommandId/turnIdfor durable reconciliation and then discarded them at publication, and it never carried a normalized outcome at all — only theagent_faileddiagnostic was published per invocation with its correlation. An ACP client matches a terminal against the correlation it was acknowledged under and requires the outcome, so a realagent_endwas rejected asacp_prompt_terminal_dropped/incomplete_correlation,session/promptnever settled, and the client sat inworkinguntil the 30-minute prompt deadline (reproduced against Paseo 0.6.1 attached to a live interactive session: the terminal rendered the full answer while Paseo showed the agentrunningindefinitely). An ownedagent_endis now published once per ended invocation carrying that invocation's correlation and a normalizedstoppedoutcome, mirroring the existingagent_failedshape. Frames that terminalize nothing are unchanged and stay uncorrelated:agent_start, a host-originated run with no owning invocation (autonomous continuation, cron, monitor), and a continuing maintenance checkpoint (pruned/compacted/promoted) — which is published but is deliberately not a terminal boundary, so stamping it would settle a client's prompt mid-turn. The ACP ownership gate is untouched. - An ACP client attached to a live interactive session now receives the turn it submitted: assistant text, thinking, and tool calls stream as they happen instead of arriving as an empty completed turn. The SDK-only host runtime subscribed to lifecycle and watchdog events only — its two
tool_execution_*handlers just renewed a deadline watchdog and it never subscribed tomessage_update/message_endat all — so it published no agent wire events and an attached client could drive the session and watch the turn settle without receiving a single word of the answer (measured against Paseo 0.6.1:paseo logsshowed the prompt and nothing else, with--filter toolsand--filter textboth reporting no activity). It now streams the same five events the notifications runtime does (message_update,message_end,tool_execution_start/update/end), built with the same sharedtoAgentWireEventPayloadproducer so the wire shape cannot drift from what ACP maps. Delivery matches the notifications runtime too: one frame per owning invocation, sent directly to the connection that submitted the turn and carrying that invocation's correlation. It deliberately does not go through the session event ring — that ring is bounded by frame count with no byte ceiling, so streaming high-frequency chunks through it would evict the lifecycle events clients depend on (including theagent_endthat settles their prompt) and would broadcast a turn's content to every authenticated subscriber rather than the one that asked for it. A turn nobody submitted over the SDK (an ordinary terminal prompt, an autonomous continuation, cron, monitor) has no owning connection and streams nothing. gjcno longer reports an error at every interactive launch when the Paseo daemon requires a password.paseo importrefuses withCannot connect to daemon ...: Password required, which the socket probe cannot anticipate because the TCP connect succeeds; that refusal is now read as a quiet skip instead of a failed announcement. GJC has no credential setting and reads no Paseo credential file:paseo importruns with the session's own environment, so an exportedPASEO_PASSWORDis used and an absent one simply skips.- Status-line settings now include a draft-local spatial custom editor with exact-slot keyboard reordering, hidden-segment palette management, command text configuration, persisted Confirm/Exit semantics, live multi-row preview compatibility, narrow/Unicode rendering, and deterministic visual evidence.
- Added opt-in
reasoningLanguage: englishguidance for technical work while preserving the user's requested response language; the default remains off.
Changed
- Interactive assistant
text_deltapresentation now coalesces eligible updates into the latest message projection before the existing TUI frame while preserving ordered event processing, immediate non-text updates, and authoritative final output. Session/transcript replacement and disposal cancel stale presentation; temporary TUI stop/start rearms current live text before the first restarted frame without invalidating live historical image callbacks.
Fixed
- Credential replacement lookups now propagate the owning request's cancellation through scoped and allowed unscoped retries, preventing aborted turns from continuing OAuth preparation or selecting another key.
- Removing the committed status-line command segment or clearing its trusted command now cancels the running process and clears stale output; draft-only previews remain side-effect-free.
- Slack inbound acknowledgment reactions now use bounded, abortable, tracked provider work that drains on shutdown or attachment retirement without delaying accepted turns; rejected or timed-out reactions emit sanitized diagnostics.
- Task repository bindings now accept explicit
relativeSubdir: "."as the already-bound worktree root, avoiding unnecessary launch retries while retaining traversal, absolute-path, symlink-escape, and sibling-repository rejection. - Blank optional task output schemas now inherit the configured agent/session schema instead of failing successful subagents at completion; malformed nonempty schemas and required-field validation remain fail-closed.
- The read-URL cache is now bounded (FIFO, 64 keys), so long-lived TUI and SDK-host processes no longer retain every fetched page's full output and image payload for the process lifetime; an evicted entry simply refetches on the next read, and unpersisted sessions sharing a working directory remain isolated by session identity.
- The insane-search web bridge now kills the engine's whole process group instead of only the
python3process.killChildpromised a group kill but the engine was not spawned detached, so when the bridge timeout fired mid-flight (25s default vs the engine's internal 90s playwright budget),nodeand headlesschromiumchildren survived as orphans. The engine now leads its own POSIX process group and receives group-wide SIGTERM→SIGKILL escalation even when the group leader exits during the grace period, with a direct child-kill fallback on Windows. - Contribution-prep outbound artifacts now redact complete AWS credentials, including AKIA/ASIA access-key IDs and SecretAccessKey/SessionToken values in shell-style and escaped JSON forms, while preserving structured output and existing GitHub, Slack, authorization-header, and cookie redaction.
- Model preset registry URL and disable overrides now resolve only from explicitly inherited or user-owned environment sources, so a checkout
.envcannot suppress updates or redirect signed-registry polling while dependency injection, HTTPS validation, signatures, ETags, cache, and offline behavior remain unchanged (#5300). - OpenCode Go's provider conversation identity now remains distinct from generic cache affinity across normal turns and maintenance calls, so the required session header reuses the session manager's opaque lifecycle without accepting auth-gateway prompt-derived cache keys (#5295).
- Perplexity web search now clamps upstream search breadth to the API's 3–100 contract, retries one structurally empty completion, rejects malformed or ungrounded success payloads through the provider fallback path, and preserves valid grounded responses.
- Architect/task subagents now retry API-key lookup without the parent session id after a scoped miss, so broker OAuth that works for
gjc -p --no-sessionis not thrown away asAgent run failed/ 0 tokens (#5081 follow-up). Failures still throwprovider_unavailablewithout leaking the token. - Python work that completes after strict session disposal now returns its result without attempting to append to the closed session transcript.
- SDK-hosted workflow tools now retain the logical session id for ask, skill, deep-interview, and ultragoal state paths while job, monitor, bash, cron, task, and subagent ownership routes through a separate opaque async endpoint key. Explicit provider session identities no longer create encoded duplicate workflow trees or redirect endpoint-owned work to another live session.
- Explicit root startup
--thinking offand--thinking=offnow override a configured higher startup default while leaving the providerEffortcatalog unchanged. - Skills installed from marketplace plugins are now enumerated into sessions instead of only resolving by exact name.
loadSkillsasked thenativeprovider alone, so every installed plugin skill was absent from/autocomplete and from theskilltool'sAvailable:list whilegjc skill listreported it and the discovery fallback still loaded it — 46 installed skills presented as 5. The already-registered marketplace provider is now loaded alongsidenative, keeping<plugin>:<skill>namespacing and per-item scope trust. - File-content search now has a call-wide timeout (
timeout, default 5 seconds, range 0.5–60) that is forwarded through internal-URL resolution and native grep together with cancellation. Native scans poll cancellation around each bounded file, and the tool joins cancellation cleanup before returning instead of leaving scope resolution, archive scratch, or grep workers running after a timeout. Timeout failures tell callers to narrow the scope or explicitly increase the budget, while user cancellation remains a distinct tool abort. restart:sdk-broker -- --close-session-hostsnow continues replacing the broker when its pre-restart session-host listing fails, reports the partial teardown with exit code 1, tolerates another authenticated restart caller retiring the same exact broker identity, and catches other top-level failures instead of emitting an unhandled-rejection crash record.install:devnow builds the workspace native addon before linking the source CLI, preventing fresh or cleaned development checkouts from failing startup with a missing or stale addon. The installer also supports the local--devbinary shortcut.- Plain and explicit-model launches now refresh a missing provider's cached dynamic catalog before resolving a qualified startup selector, so configured models such as
glm-zcode/glm-5.3no longer open inno-modelstate while preserving cache-only startup for already available models. - The explicit thinking-choice gate for xAI models now derives from the parsed grok generation (4.5+) shared with
@gajae-code/ai, instead of the exact idsgrok-4.5/grok-4.6. A future grok release failed the id list, sosupportsReasoningEffortstayedfalseand the user's thinking level was silently dropped from requests; reseller-hosted grok routes (OpenRouter & co.) keep their existing audited-transport behavior. - The status-line usage segment now paints only the active model's provider, so switching to Grok no longer keeps a stale Claude 5h/7d pair. Canonical Grok Build reports render only their authoritative weekly window, while monthly credits are omitted instead of being mislabeled as
7d. - Bundled plugin MCP launchers now execute Node
.mjsentrypoints on Linux from startup-authenticated interpreter bytes and a complete copied-file snapshot. Runtime options cannot precede the entrypoint, path-qualified/shebang commands fail closed, unexpected post-install files quarantine the bundle, and canonical registry identity plus the complete copied-file manifest are rebound before every spawn. Runtime captures the interpreter and authenticated bundle files through bounded stable handles into a unique owner-only launch capsule; the Node loader returns authenticated captured module bytes while preserving file-URL relative imports and blocking package/CommonJS/native escapes. Concurrent connections use separate authority. Capsule cleanup failures retain ownership and fence reconnect until cleanup succeeds. Bun, macOS, and Windows bundled stdio launch fail closed pending equivalent loader and owner/process-tree authority; capsules do not provide hostile-same-UID process isolation. - Moving the
/modelpreset cursor now reuses the authentication snapshot produced by catalog and credential refreshes instead of resolving every profile against the full model catalog on each Up/Down keypress; auth-dependent preset actions remain blocked until the initial static refresh and the availability snapshot are complete. - Bundled Grok Build models now explicitly declare
reasoning_effortsupport only for catalog-supported models, sogrok-build/grok-4.6:xhighreaches the Responses request while unsupported Grok models remain fail-closed. (#5264) - Mid-run OpenAI remote-compaction fallback failures now stop before another provider request, surface the local summarization error through ACP/SDK terminal handling, and leave the uncompacted context unsubmitted. Successful local fallback still commits the compaction and resumes normally.
- Opening
/modelnow renders the preset landing before constructing the full model browser catalog. Canonical search indexing, sorting, and the redundant offline registry refresh are deferred until the user searches or chooses a browse action, while the lightweight preset-availability check remains immediate and scoped or direct-search selectors still load immediately. - Slack lean notifications now publish only finalized assistant answers and actionable states instead of the internal lifecycle, identity, and activity frame stream. Final answer delivery uses the message reference as a durable publication identity, so repeated unpositioned SDK frames no longer post duplicate replies; accepted inbound Slack messages receive a 👀 reaction while GJC awaits the agent's answer.
/modelprovider-tab refreshes now reuse the already loaded static catalog and update only the selected provider's discovery state, avoiding repeated signed preset registry work while retaining full-catalog refresh behavior for static configuration changes.- Added the
commandstatus-line segment for user-produced HUD content. It runs configured user/global shell commands in the background with scheduled cached refreshes, bounded timeout/output, ANSI sanitization, placeholder degradation, disposal cancellation, and custom-editor configuration while preserving synchronous TUI rendering; project-scoped settings cannot trigger execution. - Business/Enterprise/Team ChatGPT accounts can bind GPT-5.6 Sol again. The Codex entitlement preflight treated only
plan_typevalues containing"pro"as eligible, so anopenai-codexOAuth account on a Business/Enterprise/Team plan was rejected at model-binding/subagent setup time with a spurious entitlement error even though the backend accepts the request. Exact Pro/Business/Enterprise/Team tiers are now recognized as entitled, Plus/Free remain rejected, and unfamiliar plan names are deferred to the provider rather than guessed locally.
Upgrade
Download the matching standalone binary from the latest release, replace the existing executable, then verify:
gjc --version && gjc --smoke-test
Download the latest standalone binary. See the full v0.16.4 release on GitHub.