f/hold docs

OpenCode 2 migration: fhold agent handoff

Status: implementation brief, pending AKM and akm-plugins OpenCode 2 updates. Reviewed 2026-10-06. This migration is not implemented or qualified.

Objective and starting point

Move fhold to a pinned OpenCode 2 release without losing sessions, knowledge, scheduled work, native configuration or working app connections. Keep the single-container Assistant and current optional Guardian/Portal architecture. Work on a feature branch; this brief does not authorize changing live instances or publishing a release.

The current baseline is fhold 0.1.2610061043-beta.1, with opencode-ai@1.18.34, Guardian @opencode-ai/sdk@1.18.34, akm-cli@0.9.26 and akm-opencode@0.9.26202610051302. The reviewed V2 candidate is 2.0.24, distributed as @opencode/cli, @opencode/client and @opencode/plugin. Refresh upstream versions, release status and contracts before choosing the implementation pin. The existing @opencode-ai/sdk/v2 import is a namespace in the old SDK, not proof of OpenCode 2 compatibility.

This is not a dependency-only update. Upstream identifies incompatible plugin and server interfaces, while retaining supported configuration, agents, commands and skills. See the native migration guide. The prerequisite AKM work has a separate agent handoff.

The upstream dependency is tracked in itlackey/akm#1049. Before qualifying or releasing this migration, obtain the published compatible AKM CLI and OpenCode 2 plugin artifacts, their exact pins and the native V1/V2 compatibility receipt. That upstream work includes required V1 dispatch/history support and separate V1/V2 plugin artifacts sharing the current AKM core. Do not bypass this dependency with a downstream plugin fork, vendor patch or startup install.

Read AGENTS.md, core principles, recovery and release gates before implementing.

Constraints

Code ownership map

Paths are relative to the fhold repository. Revalidate them on the chosen branch.

Area Starting files Required outcome
Dependencies and image containers/assistant/tools/package.json, packages/guardian/package.json, containers/assistant/Dockerfile New native packages, platform binaries and plugin dependency cache are pinned and installed at build time.
Startup and health containers/assistant/entrypoint.sh, containers/assistant/opencode-run.sh, containers/assistant/healthcheck.sh, containers/assistant/fhold-recovery.mjs Foreground launch, authentication and readiness work through the selected V2 contracts.
Guardian adapter packages/guardian/src/assistant-client.ts, packages/guardian/src/gateway-service.ts, packages/guardian/src/conversation.ts, packages/guardian/src/mcp-agent.ts Native API changes stay behind the existing domain boundary; MCP ownership and policy remain enforceable.
Provider/Admin operations packages/lib/src/control-plane/opencode.ts, packages/electron/src/ Native sign-in, discovery, configuration and model verification remain usable.
AKM and memory packages/skeleton/system/assistant/plugins/akm.js, packages/skeleton/system/assistant/lib/memory.js Released V2 AKM integration plus trusted-only, redacted memory behavior.
Native activity plugins/fhold/opencode.js, plugins/fhold/scripts/activity.mjs, packages/skeleton/system/assistant/plugins/fhold.js Actual turn/tool/subagent activity still drives the existing keep-alive mechanism.
Recurring work packages/skeleton/config/akm/config.json, containers/assistant/fhold-task.mjs Native invocation and the scheduled profile still produce durable results.
History and recovery packages/lib/src/control-plane/history.ts, packages/lib/src/control-plane/instance-backup.ts, packages/lib/src/control-plane/restore.ts, containers/assistant/recovery/catalog.mjs Native history conversion and database snapshots preserve user state.
Managed installation packages/lib/src/control-plane/seed-manifest.ts CLI/Admin and standalone image receive the same supported assets.

Implementation order

1. Establish a reproducible native baseline

Record the selected binary/client/plugin versions and upstream commit. Inspect the candidate CLI help, generated client types, authentication and event contracts. Start an isolated native server and capture redacted contract fixtures before adapting callers. Track unresolved differences explicitly rather than catching errors and falling back to old endpoints.

OpenCode's foreground serve command remains available; qualify it in the shipped image rather than inventing a supervisor replacement. Verify native package selection on Linux x64 and ARM64, executable links, read-only managed directories, configuration isolation and first boot without dependency downloads.

2. Integrate the released AKM port and fhold hooks

Obtain the exact compatible CLI/plugin artifacts and test receipt from the AKM handoff. Update immutable pins and lockfiles using normal package tooling. Remove assumptions about old platform-package names and the old plugin SDK cache.

Port fhold's AKM wrapper, memory helper and activity plugin using the native plugin migration contract. Adapt their registrations to actual V2 lifecycle semantics, not only hook names. Preserve trusted build/plan recall and memory restrictions; guarded and scheduled requests must not gain implicit memory writes. Subscriptions must clean up on reload, with no duplicate recall, memory capture or activity records.

3. Adapt native API consumers

Use the released @opencode/client and generated API reference to map each operation. Health probing changes from /global/health to the candidate's /api/info contract; verify its response rather than accepting any HTTP 200.

Cover session lifecycle and ownership metadata, asynchronous prompts, message and status reads, forks, aborts, diffs/todos, permissions, questions/forms and workspace search. Preserve public MCP operations where feasible; validate the new native representations before trusting identity or interaction handles. Prove that per-request chat/read/full and scheduled restrictions still take effect in the native engine, including changed permission actions and agent selection. Server acceptance of old-looking input is not proof of enforcement.

V2 does not provide LSP functionality. fhold currently exposes symbol search through client.find.symbols. Resolve that capability explicitly: demonstrate a supported native replacement, or obtain approval for an honest unsupported response/capability change. Never return fabricated empty results or add a new language-server service to conceal the gap.

For Admin, adapt the existing shared control-plane functions, not the page design. Cover provider/integration/credential boundaries, OAuth binding, endpoint model discovery, targeted native config writes, reload and effective readback. A response test stays on the same page and does not change the chosen model; only explicit Use does. Filter by native text/tool capabilities rather than model-name guesses. Account listings must not imply that imported credentials work.

4. Qualify recurring work and persistence

Check the selected CLI's server-attachment arguments before updating the current run --attach ... --agent scheduled definition. Verify permissions, task results, failure history, future-only restart behavior and independent keep-alive/recovery timers with scheduling disabled.

Determine the candidate database location with native opencode debug paths db; do not guess a new filename. Inspect its schema and upstream V1 migration on copies. Adapt fhold's offline history reader/importer and recovery catalog only where their current V1 database/export assumptions fail. Keep consistent SQLite-native snapshots including WAL content; never copy live database files or put active SQLite databases on network mounts.

Keep these contracts distinct:

Preserve original homes and verified cold exports. Compare identifiers and content, not only session counts: messages, parts, tool results, timestamps, attachments, parent/fork relationships and project/workspace association. An unfinished historical tool call must not be rerun or silently omitted. Any required conversion to interrupted history needs explicit review and a receipt. Rollback means restoring the untouched V1 home/export with its matching image, not pointing an old binary at the converted database.

Acceptance gates

Required delivery

Deliver reviewed commits, updated user/architecture/release documentation, exact dependency pins, redacted native test evidence and a history-preservation report. List any unverified capability as a release blocker. Use harness verification and the release checklist for the final receipt. Do not claim readiness from mock hooks, a running process or a successful build alone.

A live upgrade or release is a separate, explicitly approved step after these gates pass. Do not change the current runtime documentation to say V2 is supported before implementation and qualification are complete.