8.7 KiB
Implementation plan: OpenCode Toolkit
Objective
Create an independent, small OpenCode V2-native project using selected and reviewed ECC skills, agent prompts, and workflows. The ECC fork remains a source of reference, not a runtime dependency. The new package must be reproducible, installable in a project, testable without a model provider, and explicit about unverified behavior.
Starting assumptions and decisions
- ECC source:
https://github.com/sargatxet/ECC, commitef648e01899ba3e8dc6371642deaaf64b4477775, version 2.2.3, MIT. - Runtime baseline: OpenCode 2.0.24,
@opencode/plugin2.0.24, Node.js 24.21.0 in the development environment; declared minimum Node.js 20. - Scope: OpenCode V2 only for the initial release. No attempt to retain ECC's Claude Code, Codex, or other harness installers.
- Distribution: one ESM package; project-local install first. Global/XDG installation and npm publication are deferred.
- Provider and model selection remains user-owned. No credentials, model defaults, or paid model calls are configured by this package.
- Content is selected and adapted, not copied wholesale. Preserve upstream license text and per-file provenance.
Initial scope
Included
- Skills:
coding-standards,security-review,tdd-workflow. - Agents: planner, code reviewer, security reviewer.
- V2 plugin:
toolkit_project_status, a read-only wrapper over OpenCode's VCS context and status APIs. - Project installer/uninstaller: copy the selected content, register the npm plugin with a JSONC-preserving edit, track file ownership with SHA-256, reject collisions and symlinks, and preserve modified files during uninstall.
- Unit tests, installer integration tests, coverage threshold, provenance, operating documentation, FIXME and TODO tracking.
Explicitly deferred
- ECC's V1 hook runtime, Claude-specific session discovery, continuous-learning storage, instincts, memory vault, shell automation profiles, global installs, multiple OpenCode config-layer reconciliation, npm publication, and provider-backed E2E flows.
- Duplicating native OpenCode file, shell, search, delegation, and VCS tools when a native API already satisfies the use case.
Architecture
src/plugin.ts: stable V2Plugin.defineentry point and namespaced tool.src/installer/config.ts: JSONC-safe plugin registration edits.src/installer/project.ts: project-local file staging, ownership manifest, safe update, and conservative uninstall.src/cli.ts:installanduninstallcommands.content/skills/andcontent/agents/: versioned content distributed with the package.test/: Node test-runner tests for plugin API shape, config edits, install idempotency, collisions, local edits, and symlink protection.docs/PROVENANCE.md: origin, commit, license, adaptations, and hashes.
Work phases and acceptance criteria
Phase 0 — Establish project and contract (complete)
- Create the separate repository without changing the ECC fork.
- Pin OpenCode SDK version 2.0.24 and establish a test/build baseline.
- Record package identity as provisional and document scope.
Acceptance: independent project builds; ECC source remains unchanged.
Phase 1 — Select and import content (initial subset complete)
- Review each workflow for Claude-only paths, unavailable scripts, models, and cross-references.
- Include supporting files, adapt frontmatter to native OpenCode agent format, and record source SHA and file hashes.
- Confirm IDs are unique and are installed under
toolkit-*names.
Acceptance: OpenCode discovers installed skills and agents; resources are present; imported files have provenance and license attribution.
Phase 2 — Prove V2 runtime (complete)
- Use
Plugin.define({ id, setup(ctx) }), V2 transforms and documented VCS APIs. - Avoid the V1 plugin callback, V1 event names, and module-global session state.
- Verify namespaced tool registration and output through contract tests.
- Test loading and tool execution under an actual OpenCode 2.0.24 runtime.
Acceptance: installed package loads and the tool runs in a real OpenCode session. Verified using a local mock OpenAI-compatible endpoint; no external provider call was made.
Phase 3 — Implement project installer (initial behavior complete)
- Preflight all content and paths; reject collisions, non-regular files, and symlinked install paths.
- Refuse simultaneous direct and
.opencode/project config files until their V2 merge behavior is handled safely. - Preserve existing JSONC and unrelated settings.
- Write an ownership manifest with hashes; allow repeat installation only when previously managed files remain unchanged.
- On updates, remove stale package-owned files only when their stored hash still matches; keep locally edited stale files tracked and report them.
- Remove only package-owned, unmodified assets and a plugin entry the installer originally added.
- Test clean install, re-run, collision, user-edited files, malformed config, and symlink cases.
Acceptance: project install is idempotent; user files are not overwritten; uninstall preserves locally modified content.
Phase 4 — Validate distribution artifact (open)
- Build and pack the real package.
- Install its tarball into a clean project outside this repository.
- Check all imports/content/license files and load the plugin with OpenCode.
- Verify behavior in a project with pre-existing config and skills.
Progress: package tarball installs outside the checkout; the CLI is idempotent and OpenCode discovers the three packaged agents. Runtime testing showed that the old npm-name entry caused a registry 404 and that the namespaced tool needed Code Mode enabled. Both were corrected and the packaged plugin and tool were verified in a local mock-provider session.
Acceptance: no checkout symlink or development dependency is needed at runtime; config collisions are handled or reported before writes; the V2 plugin and its custom tool are confirmed active.
Phase 5 — Document and release (documentation baseline complete)
- Document scope, installation, update/uninstall, compatibility, provenance, and known limitations.
- Run deterministic checks and security review before release.
- Confirm package/repository names and get explicit approval before publishing.
Acceptance: another user can install from documented instructions and verify the deterministic behavior without credentials.
Phase 6 — Optional memory and learning features (not started)
- Design persistent memory and session-learning APIs separately.
- Prefer V2 public APIs over assumptions about OpenCode's storage layout.
- Add opt-in, scope controls, retention behavior, and isolation tests.
Acceptance: explicit consent and tests prove project/session/user data cannot be mixed or silently uploaded.
Verification strategy
Deterministic, no-model checks
npm run typecheck,npm test, coverage threshold, package dry-run.- Plugin API contract tests using V2 types and V2-shaped context.
- Installer tests using isolated temporary projects.
- Real OpenCode config parse and plugin load smoke test.
- Tarball install test outside the repository.
Provider-backed checks
- Load the three workflows; delegate to planner/reviewer; invoke skills; verify model-visible permissions and agent behavior.
- These tests need a configured provider and may incur cost. They require an explicit budget and must not be represented by mocks as passed.
Risks and mitigations
- OpenCode config precedence: direct and
.opencode/config files have layered precedence. Test the actual 2.0.24 behavior before supporting complex multi-file layouts; fail safely rather than silently hide user plugins. - Package dependency resolution: tests against the source checkout can hide missing package files. Validate an installed tarball.
- Content drift: selective copying creates manual sync work. Compare source SHAs and hashes during updates; never auto-sync all of ECC.
- Session data leaks: do not use module-global mutable maps for session state; add isolation tests before adding tracking or memory.
- Permission weakening: do not inherit ECC's auto-approval behavior without an explicit V2 permission design and security review.
- Uninstall partial failures: file operations can fail mid-run; preserve the manifest and report recovery instructions. Transactional rollback remains a follow-up.
Change management
For each ECC refresh, compare the pinned upstream revision, select changes component-by-component, inspect dependencies and licensing, update hashes, and run the full deterministic and runtime checks. Maintain a compatibility matrix for OpenCode versions actually tested. Do not publish or push without explicit authorization.