Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

opencode-workplan

opencode-workplan gives OpenCode a durable execution plan that can move between sessions in the same worktree. The current snapshot, append-only event ledger, and human-readable Markdown mirror live outside the repository by default. Server tools mutate the plan; the TUI sidebar and /current-tasks command read the snapshot directly without sending a prompt, adding a message, or invoking a model.

This is version 1.2.2. It targets OpenCode >=1.18.15 <2.0.0 and has live compatibility coverage for OpenCode 1.18.15 on Linux with Bun. See the exact API contract.

Features

  • Stable session-local task IDs (T-001, T-002, ...).
  • Seven granular tools: create, read, add, update, complete, list, and resume.
  • Stable plan IDs and a recoverable catalog for continuing an active plan in a new root session.
  • One current task, dependency/cycle enforcement, blockers, cancellation, reopen/restore reasons, optimistic revisions, and exact verification gates.
  • Cross-process per-session locks and write-ahead transactions.
  • Replayable JSONL events, atomic snapshots, Markdown mirrors, and corruption recovery that preserves damaged originals.
  • Bounded every-turn and compaction context derived from persisted state.
  • Task-aware subagents bind to an explicit [T-NNN], must read that task before other tools, and retain read-only access while Main owns every plan mutation.
  • Read-only sidebar progress with current work and blocker count; clicking it opens /current-tasks, which also has /tasks and /workplan aliases.

Build and install

Prerequisites are Bun and OpenCode 1.18.15 or a compatible v1 release.

cd /absolute/path/to/opencode-workplan
bun install --frozen-lockfile
bun run check

Install into the current project without changing global configuration:

cd /absolute/path/to/your-project
opencode plugin /absolute/path/to/opencode-workplan

OpenCode 1.18.15 detects both package exports and patches the project-scoped server and TUI configuration in .opencode. To install globally instead:

opencode plugin --global /absolute/path/to/opencode-workplan

For a distributable local artifact, run bun pm pack, inspect the generated archive, extract it to a stable absolute path, run bun install --production --ignore-scripts in that directory, and install the directory. This project is intentionally not published to npm.

Restart OpenCode after installation. Server and TUI are separate, target-exclusive modules:

opencode-workplan/server  -> dist/server.js
opencode-workplan/tui     -> dist/tui.js

Configuration

The install command writes the same package spec into project server and TUI configuration. Options are supplied as the second tuple item. Use the same storage settings for both targets.

Project server configuration (.opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    [
      "/absolute/path/to/opencode-workplan",
      {
        "autoStartFirstTask": true,
        "injectSystemContext": true,
        "injectCompactionContext": true,
        "systemContextMaxChars": 8000,
        "compactionContextMaxChars": 24000,
        "recentCompletedLimit": 5,
        "recentHistoryLimit": 20,
        "lockTimeoutMs": 5000,
        "staleLockMs": 30000,
        "generateMarkdownMirror": true
      }
    ]
  ],
  "permission": {
    "todowrite": "deny",
    "workplan_*": "allow"
  }
}

Project TUI configuration (.opencode/tui.json):

{
  "$schema": "https://opencode.ai/tui.json",
  "plugin": [
    [
      "/absolute/path/to/opencode-workplan",
      {
        "recentCompletedLimit": 5
      }
    ]
  ]
}

Global configuration uses the corresponding OpenCode global config directory. Prefer opencode plugin --global ... to select it correctly.

Storage defaults to:

${XDG_STATE_HOME:-$HOME/.local/state}/opencode/workplan

OPENCODE_WORKPLAN_DIR overrides both the default and storageDir and must be absolute. This is useful for tests and isolated installations:

export OPENCODE_WORKPLAN_DIR="/absolute/private/path/opencode-workplan-state"

All options are validated strictly. Unknown keys, relative storage paths, and out-of-range limits stop plugin initialization instead of silently changing behavior.

Usage

The main agent should create its authoritative plan before work begins. Task-created child and nested subagent sessions resolve their OpenCode parentID chain to the root. Every delegated short description should begin with the assigned task ID, for example [T-003] Implement cache invalidation. The plugin validates that task against the attached plan and injects the stable plan ID, task ID, assignment revision, and required first call into the child prompt:

workplan_read({ view: "task", taskID: "T-003" })

The targeted view returns the complete task record, plan objective and constraints, current revision, and dependency readiness even when another task is globally current. Bound children must complete that exact read before using any other tool. The binding and successful read are recovered from persisted session history after plugin or OpenCode restarts, including nested ancestry.

Pending tasks can be bound, so independent assignments may run in parallel. An omitted marker logs and injects a warning but continues unbound; a malformed or nonexistent explicit marker fails closed. A task-splitter invoked before an active plan exists is exempt. Subagents may read the attached plan but cannot create, add, update, complete, list, or resume it. Independent and forked sessions have no parent chain and remain isolated until a root agent explicitly resumes a plan.

To continue earlier work in a new root session:

  1. Call workplan_list with no arguments. It returns only plans whose stored worktree exactly matches the current worktree, sorted by updatedAt newest first. Every result includes its objective, stable plan ID, status, resumability, progress, current task, revision, and timestamps.
  2. Compare the objectives and choose the clearly relevant active plan. Ask the user if more than one objective plausibly matches.
  3. Call workplan_resume with the exact planID, listed expectedRevision, and a concrete reason, then call workplan_read.

Resume transfers ownership; it does not copy or merge plans. It advances the existing revision exactly once and appends plan.transferred to the original ledger. The previous root session is detached and receives PLAN_TRANSFERRED if it tries to read or mutate the plan. Completed and abandoned plans remain visible in the list but are never resumable. A root session that already owns an active plan must finish or transfer it before attaching another one.

Update tasks granularly, record newly discovered scope as new tasks, and complete a task only after all exact verification requirements pass.

Available tools:

Tool Purpose
workplan_create Root/main agents create or explicitly replace a plan; subagents are rejected.
workplan_read Read summary, active, targeted task, full, or history context.
workplan_add Root/main only: atomically append tasks and allocate stable IDs.
workplan_update Root/main only: edit or transition one task; never completes it.
workplan_complete Root/main only: complete one task with exact passing verification results.
workplan_list List plans for the current worktree, most recently updated first; takes no arguments.
workplan_resume Transfer one active listed plan to the current root session with revision validation.

Completion results use this shape:

{
  "requirement": "bun test passes",
  "command": "bun test",
  "result": "all tests passed",
  "passed": true
}

requirement must exactly equal one task verification requirement. Every requirement needs exactly one result; unknown, duplicate, missing, or failed results reject completion.

At any time in an active TUI session, run:

/current-tasks
/tasks
/workplan

The existing OpenCode sidebar shows a 12-column progress bar, exact completed and total counts, percentage, current task, and blocker count. Clicking anywhere on the workplan summary dispatches the same workplan.current command used by the slash aliases below. Directory watchers refresh the summary after atomic snapshot/catalog renames and follow a transferred plan's current binding; all watchers are closed when the slot or plugin is disposed.

The command opens a centered, scrollable overlay sized to 80% of terminal width on wide screens and clamped safely on narrow screens. It shows objective, progress, current task, blockers, pending work, recent completions, revision, and update time. Press Escape or Ctrl+C to close it. It reads state.json through the shared read-only core. It does not use api.client, submit a prompt, append a message, or mutate the plan.

Persistence and transactions

The storage root contains a derived catalog.json and plan directories. The catalog maps stable plan IDs and root-session bindings; it is rebuilt from validated snapshots if missing or corrupt. New plans use an opaque storage ID. Legacy 0.1.1 plans keep their original session-backed storage ID and receive a deterministic stable plan ID on discovery:

<storage>/
├── catalog.json
└── sessions/<prefix>-<hash>/
    ├── state.json
    ├── events.jsonl
    └── tasks.md

state.json is the current snapshot, events.jsonl is the replayable authoritative mutation history, and tasks.md is a generated mirror. A mutation acquires one cross-process mkdir lock for its session, recovers under that lock, validates expectedRevision, stages both mirrors, appends and flushes one event, then atomically renames and flushes the mirrors. Different sessions have different locks.

Directories are forced to 0700 and state files to 0600 on supported platforms. Session IDs cannot traverse paths, and writes reject symbolic-link targets. Command strings in verification results are stored as plain data and are never executed by the plugin.

Inspect Markdown mirrors outside OpenCode:

find "${OPENCODE_WORKPLAN_DIR:-$HOME/.local/state/opencode/workplan}" \
  -name tasks.md \
  -type f \
  -print

No files are created in a repository by normal plugin operation unless the user explicitly points storageDir or OPENCODE_WORKPLAN_DIR there.

Recovery and troubleshooting

On a server read or mutation, the plugin validates both snapshot and ledger. It rebuilds a missing, corrupt, or behind snapshot from valid replayable events and preserves a corrupt snapshot as state.json.corrupt-<timestamp>. Only an unterminated, malformed final JSONL record is treated as an interrupted append; the original ledger is copied to events.jsonl.corrupt-<timestamp> before the valid prefix is repaired.

If both files are unusable, or if a complete malformed JSONL record appears, the plugin returns STATE_CORRUPT and does not overwrite the originals. Copy the entire session directory before manual repair. The TUI sidebar and command intentionally do not recover or write; they show a safe unavailable/corruption state, and the command includes the snapshot path.

Common errors:

  • TASK_INITIAL_READ_REQUIRED: call the exact targeted workplan_read shown in the injected binding before any other tool.
  • TASK_BINDING_INVALID / TASK_BINDING_PLAN_MISMATCH: correct the task marker or ask Main for a fresh delegation against the attached plan.
  • SUBAGENT_MUTATION_FORBIDDEN: return evidence to Main; only Main records plan changes and completion.
  • SUBAGENT_CREATE_FORBIDDEN: ask the main agent to create the plan.
  • SUBAGENT_RESUME_FORBIDDEN: ask the main/root agent to attach the selected plan.
  • PLAN_TRANSFERRED: the plan now belongs to another root session; list or create plans from the current root.
  • PLAN_COMPLETED / PLAN_ABANDONED: choose a resumable active result from workplan_list.
  • SESSION_PLAN_EXISTS: finish or transfer the current session's active plan before attaching another.
  • WORKTREE_MISMATCH: open the plan's stored worktree before resuming it.
  • REVISION_CONFLICT: call workplan_read, reconcile, then retry with the new revision.
  • DEPENDENCY_INCOMPLETE: finish/cancel the dependency or remove the edge.
  • DEPENDENCY_CYCLE: remove an edge from the reported cycle.
  • VERIFICATION_REQUIRED: submit one passing result for each exact requirement.
  • LOCK_TIMEOUT: retry; an abandoned lock is reclaimed after staleLockMs.
  • UNSUPPORTED_SCHEMA_VERSION: upgrade the plugin before reading newer state.

Server diagnostics use OpenCode structured logging and include safe error codes, revisions, task IDs, and hashed session identifiers—not prompts, tokens, environment dumps, source files, secrets, or normal-output stack traces.

Upgrades and migrations

Back up the storage root before upgrading. Version 1.2.2 is state-compatible with 1.2.1 and adds task-bound delegation plus stricter child permissions; it does not change the persisted plan schema. Version 1.2.1 adds the read-only TUI sidebar. Version 1.2.0 discovers existing 0.1.1 plans in place, assigns each a deterministic plan ID, and builds the catalog without rewriting its plan snapshot or ledger. The first successful resume records ownership and its stable ID through a normal one-revision transaction. Version 0 snapshots are migrated in memory to schema version 1 and rewritten only through the normal locked recovery path. Unknown future schema versions are never downgraded. No migration deletes tasks or valid ledger events.

Development and verification

bun test
bun run test:reliability
bun run typecheck
bun run lint
bun run build
bun pm pack

The suite covers pure transitions, path safety, migrations, atomic storage, stale locks, real competing processes, ledger recovery, all seven direct tool paths, targeted current/pending reads, binding validation and restart recovery, nested and parallel assignments, main-only mutation revision safety, catalog rebuilding, legacy discovery, concurrent transfer, repeated compaction, fake-host TUI behavior, the 15-task reliability scenario, and 100-task performance.

MVP boundaries

There is no sidebar task editing, cloud sync, external issue-tracker integration, cross-worktree transfer, task deletion, multi-user plan, native todo synchronization, or /current-tasks full. Cancelled tasks remain in history. Portable path and lock behavior is automated; live installation and TUI smoke coverage is Linux/Bun against OpenCode 1.18.15.

About

Durable, task-aware work plans for OpenCode

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages