opencode-xk is a stability-first fork of OpenCode for long-running local agent workflows.
opencode-xk is an independent maintenance fork of OpenCode. It keeps the upstream MIT license and attribution intact while focusing on the parts of an AI coding agent that decide whether real work continues safely: session control, recovery, retry, task/subagent lifecycle, sync state, notifications, and CLI/TUI responsiveness.
This is not the official OpenCode project, and it is not affiliated with the OpenCode team. Use anomalyco/opencode for official releases, packages, documentation, and support.
OpenCode moves quickly. That is good for features, but it also means workflow regressions can land in the exact places that matter during real coding sessions: old tasks continue after a new instruction, async prompts return before the session accepts work, provider stream errors leave confusing state, subagents lose their parent metadata, or multi-window notifications fire repeatedly.
This fork treats those workflow details as the product surface. The goal is not to add a bigger feature list. The goal is to make the local agent feel predictable when a session is long, interrupted, retried, resumed, delegated, or reopened.
| Area | Local behavior |
|---|---|
| Session control | Tracks the latest real user message and classifies prompts as redirect, pure_continue, mixed_continue, or new_request so stale workflow reminders do not override the current request. |
| Recovery | Scans unfinished assistant turns, finalizes interrupted tool parts, and returns idle sessions to a clean state before continuing work. |
| Retry boundary | Normalizes provider, stream, HTML, malformed SSE, network, and quota-shaped errors into one retry policy while leaving context overflow and empty provider responses to the right fallback path. |
| Task and subagent flow | Writes child session metadata early, validates task_id, supports background subagents, and keeps cancellation from tearing down parent workflow state incorrectly. |
| Async prompt handoff | Adds client-side acceptance and handoff checks around prompt_async and command_async, with local pending state so the UI reflects submitted work before remote status catches up. |
| Sync and cache | Uses revision gates, inflight dedupe, session cache cleanup, and status snapshots to avoid stale session, todo, diff, and message data overwriting newer state. |
| TUI and app polish | Reduces false busy states, empty assistant shells, stale unfinished turns, repeated notifications, and session navigation flicker. |
| Local build boundary | Keeps XK-* builds separate from upstream versioning and official package/update channels. Public release automation is intentionally removed from this fork. |
| Repository hygiene | Removes upstream issue/PR bots, publish/deploy jobs, Discord notifications, and official-team ownership metadata; keeps only ordinary CI checks on GitHub-hosted runners. |
See FORK_DIFF.md for the deeper local-vs-upstream diff summary.
The fork is intentionally biased toward workflow correctness instead of broad feature expansion. The most important local changes are below.
| Difference | What upstream tends to expose | What opencode-xk changes |
Main code paths |
|---|---|---|---|
| Latest user intent wins | Long sessions can keep following old workflow reminders, old task summaries, or previous continuation context after the user gives a new instruction. | Adds prompt intent classification and latest-real-user tracking so new_request, redirect, pure_continue, and mixed_continue flows are separated before the agent continues. |
packages/opencode/src/session/control.ts, packages/opencode/src/session/prompt.ts |
| Interrupted session recovery | A stopped or crashed run can leave unfinished assistant turns, running tool parts, or stale busy state behind. | Adds idle-only recovery that seals interrupted assistant turns, finalizes running tool parts, and restores the session to an idle state before new work starts. | packages/opencode/src/session/recovery.ts, packages/opencode/src/session/run-state.ts, packages/opencode/src/session/index.ts |
| Provider retry boundary | Stream failures, malformed SSE, HTML responses, socket drops, decompression errors, quota-shaped errors, and API errors can surface as inconsistent failures. | Normalizes provider and stream failures into a single retry policy, while keeping context overflow and genuinely empty provider responses on separate fallback paths. | packages/opencode/src/session/retry.ts, packages/opencode/test/session/retry.test.ts |
| Task/subagent lifecycle | Child sessions can be created without enough parent metadata, invalid task_id values can drift, and cancellation can leak back into the parent workflow. |
Writes child session metadata during setup, validates resumed task sessions, supports background subagents, and contains cancellation so parent state is not corrupted. | packages/opencode/src/tool/task.ts, packages/opencode/src/session/prompt.ts, packages/opencode/test/tool/task.test.ts |
| Async prompt handoff | prompt_async or command_async can return before the session visibly accepts or starts the new work, making the UI look like the message disappeared or stalled. |
Adds client-side acceptance/handoff checks plus local pending state so the app reflects submitted work immediately and waits for real session evidence. | packages/opencode/src/server/instance/session.ts, packages/app/src/components/prompt-input/submit.ts, packages/app/src/components/prompt-input/pending-state.ts |
| Sync cache safety | Session lists, todos, diffs, messages, and status can be overwritten by stale refreshes during reconnect, archive/delete, navigation, or event replay. | Adds revision gates, inflight dedupe, session cache cleanup, status snapshots, and event reducer guards to keep stale data from winning over newer state. | packages/app/src/context/sync.tsx, packages/app/src/context/global-sync/* |
| Streaming event replay | Part deltas can arrive before their matching part, and replay gaps can leave partial message state behind. | Buffers part deltas until the matching part arrives, detects replay gaps, and clears stale message/diff/todo/session cache together. | packages/app/src/context/global-sync/event-reducer.ts |
| Session UI busy state | The UI can stay busy because of old unfinished assistants, blank assistant shells, or aborted windows. | Prefers explicit status and local pending state, marks queued user messages interrupted when needed, and reduces blank unfinished turns. | packages/app/src/pages/session/session-busy.ts, packages/app/src/pages/session/helpers.ts, packages/ui/src/components/session-turn.tsx |
| Multi-window notifications | Multiple app windows can play duplicate sounds or show duplicate completion/error notifications for the same session event. | Claims notification events per local window and dedupes sounds, app notifications, child-session events, and repeated errors. | packages/app/src/context/notification.tsx, packages/app/src/utils/notification-dedupe.ts, packages/app/src/context/notification-helpers.ts |
| Public repository boundary | Upstream carries official release, publish, issue bot, PR bot, Discord, stats, vouch, and ownership automation that does not belong in a public fork. | Removes those workflows and metadata, keeps only normal CI checks, and documents source builds instead of public package or binary release flows. | .github/workflows, .github/ISSUE_TEMPLATE, package.json, script/publish.ts |
This means opencode-xk is best understood as a reliability fork for people who keep one local agent session alive for real work: stop, retry, resume, delegate to subagents, reopen the UI, and continue without the agent drifting back to stale context.
bun install
OPENCODE_VERSION="XK-2.0.0" bun run build:xkThe build guard requires OPENCODE_VERSION=XK-* so this fork does not accidentally produce an official OpenCode version. Build artifacts are written under packages/opencode/dist/.
This repository documents source builds only. It does not include a public release, npm, Docker, Homebrew, AUR, or official update-feed publishing flow.
bun run --cwd packages/opencode typecheck
bun test --cwd packages/opencode test/session/control.test.ts test/session/retry.test.ts test/session/recovery.test.ts test/tool/task.test.ts
bun test --cwd packages/opencode test/cli/tui/prompt-submit-request.test.ts test/cli/tui/textarea-keybindings.test.tsTests must run from package directories such as packages/opencode, not from the repository root.
Changes intended for official OpenCode should be split onto a fresh branch from upstream/dev and kept small:
- no
XK-*versioning - no fork branding
- no fork release policy
- no local workflow instructions
- one behavior fix per PR with targeted tests
Good upstream candidates include prompt handoff fixes, task/subagent lifecycle hardening, session recovery edge cases, retry classification, and small UI state corrections.
This fork preserves the upstream MIT license. See LICENSE. Upstream copyright and license text are retained as required by MIT.