openpetswithchatandmcp/docs/phases/phase-19-opencode-integration.md
OpenPets Dev 6ab3bb64d8 feat(rebrand): rename OpenPets to FamiliarOS and pets to familiars
- Rename all user-facing and technical identifiers from OpenPets/Pet to FamiliarOS/Familiar.
- Rename packages from @open-pets/* to @familiaros/*; rename install-pet/pet-format packages.
- Rename plugin IDs and directories from openpets.* to familiaros.*.
- Rename IPC namespace from openpets:* to familiaros:* and state filenames from openpets-* to familiaros-* with legacy migration.
- Rename source files (pet-window, built-in-pet, default-pet-controller, etc.) to familiar equivalents.
- Update locales (en, es-419, ja, ko, pt-BR, zh-Hans, zh-Hant) and tray/pet context menu strings.
- Add Familiar naming feature: preference, settings input, tray menu display.
- Update assets and packaging config; all desktop tests pass.
2026-06-17 01:42:08 +00:00

14 KiB
Raw Permalink Blame History

Phase 19 — OpenCode Integration Plan

Goal

Add full FamiliarOS support for OpenCode with parity to the current Claude Code integration, without over-splitting implementation work.

Target parity means:

  • FamiliarOS MCP tools available in OpenCode.
  • FamiliarOS instructions installed into OpenCode instructions.
  • OpenCode activity drives familiar reactions and short safe speech.
  • CLI project setup can route a selected familiar to a project.
  • Desktop Integrations can detect/configure/remove/doctor OpenCode setup.

Current Claude integration to mirror

Claude support has four layers:

  1. MCP tools

    • Public tools stay exactly familiaros_status, familiaros_say, familiaros_react.
    • MCP server: packages/mcp/src/server.ts.
    • CLI wrapper: packages/cli/src/index.tsfamiliaros mcp --familiar <id>.
    • Claude command/config helpers: packages/claude/src/claude-code.ts.
    • Desktop setup: apps/desktop/src/agent-setup.ts.
  2. Instructions/memory

    • Claude writes ~/.claude/familiaros.md and imports it from ~/.claude/CLAUDE.md.
    • Implementation: apps/desktop/src/claude-memory.ts.
    • Safety pattern: managed markers, preserve user content, private file modes, no symlink writes, max file size.
  3. Hooks/events

    • Claude hooks write managed command entries to ~/.claude/settings.json or project-local .claude/settings.local.json.
    • Implementation: packages/claude/src/hook-settings.ts, packages/claude/src/hooks.ts, packages/claude/src/hook-messages.ts.
    • Current mapping:
      • UserPromptSubmitthinking + throttled speech.
      • PreToolUse Edit/Write/MultiEditediting.
      • PreToolUse Bash test command → testing, otherwise running.
      • other PreToolUseworking.
      • PermissionRequestwaiting + forced short speech.
      • Notificationwaving.
      • Stopsuccess + throttled speech.
      • StopFailureerror + throttled speech.
  4. CLI project setup

    • familiaros configure --agent claude --familiar <id> --cwd <project> configures project-local Claude MCP and hooks.
    • Explicit --familiar works without desktop app; omitted --familiar uses local IPC familiars.list.

OpenCode source findings

OpenCode has enough native extension surface for parity, but OpenCode support should use config + plugin, not Claude-style hooks.

  • MCP config

    • OpenCode config has mcp at v1/opencode/packages/opencode/src/config/config.ts lines 220-229.
    • Local MCP shape is in v1/opencode/packages/opencode/src/config/mcp.ts lines 5-19:
      • { type: "local", command: string[], environment?, enabled?, timeout? }.
    • opencode mcp add is interactive, so automated FamiliarOS setup should directly edit JSON/JSONC config with the same shape.
  • Config locations

    • Global config uses OpenCode global config dir, with OPENCODE_CONFIG_DIR override support.
    • Project configs include opencode.json, opencode.jsonc, .opencode/opencode.json, .opencode/opencode.jsonc.
    • OpenCode's own MCP add path resolution checks opencode.json before opencode.jsonc, then .opencode/*: v1/opencode/packages/opencode/src/cli/cmd/mcp.ts lines 399-415.
    • OpenCode writes config with jsonc-parser: v1/opencode/packages/opencode/src/cli/cmd/mcp.ts lines 417-431.
  • Instructions

    • OpenCode config supports instructions: string[]: v1/opencode/packages/opencode/src/config/config.ts lines 238-240.
    • OpenCode config merge concatenates instruction arrays without duplicates: lines 54-59.
  • Plugins/events

    • OpenCode plugin hook surface: v1/opencode/packages/plugin/src/index.ts lines 222-333.
    • Useful hooks include event, chat.message, tool.execute.before, tool.execute.after, command.execute.before.
    • Do not rely on permission.ask; permissions should be handled through plugin event for bus event permission.asked.
    • OpenCode awaits plugin hooks directly, so plugin hooks must return immediately and run FamiliarOS calls fire-and-forget.

Non-goals

  • Do not fork or modify v1/opencode/.
  • Do not add new public MCP tools.
  • Do not expose familiar install/remove/default controls through MCP or OpenCode plugin tools.
  • Do not add a network listener or external SSE watcher unless plugin-based events prove insufficient.
  • Do not send prompts, raw commands, code, logs, tool output, URLs, secrets, or file paths to familiar speech.
  • Do not write project-local absolute local/bundled paths by default.

This should be 4 subphases, not 6. That keeps risk separated without making the project feel fragmented.

Phase 19A — OpenCode Foundation

Goal: Add OpenCode config helpers, previews, safe write primitives, and shared speech/event safety. No plugin runtime or UI yet.

Scope:

  • Add packages/opencode or equivalent module.
  • Build helpers for:
    • best-effort OpenCode detection;
    • global/project config path discovery;
    • JSON/JSONC read/write;
    • MCP/instructions/plugin previews;
    • installed/missing/stale/error status classification.
  • Extract shared speech categories, message picking, speech validation, and throttling from Claude into a neutral reusable module.
  • Keep Claude behavior unchanged.
  • Define exact config target behavior:
    • follow OpenCode's own existing file order: opencode.json, opencode.jsonc, .opencode/opencode.json, .opencode/opencode.jsonc;
    • if no project config exists, create .opencode/opencode.jsonc;
    • published mode is default for project config;
    • local/bundled absolute paths are explicit dev/global-only, never default project config.
  • Add safety primitives:
    • max config size;
    • reject symlinked file and parent dirs;
    • no writes on invalid JSON/JSONC;
    • backup before update/replace/remove;
    • temp-file + rename atomic writes.

Acceptance criteria:

  • OpenCode MCP preview shape is:
{
  "mcp": {
    "familiaros": {
      "type": "local",
      "command": ["npx", "-y", "@familiaros/cli@0.0.0", "mcp", "--familiar", "fixer"],
      "enabled": true
    }
  }
}
  • Tests cover JSON/JSONC parsing, candidate ordering, idempotency, stale entries, invalid config, backups, max size, symlink rejection, and speech safety.
  • Claude checks still pass unchanged.

Checks:

  • pnpm --filter @familiaros/opencode check
  • pnpm --filter @familiaros/claude check

Phase 19B — OpenCode Plugin Runtime

Goal: Add the OpenCode plugin that reacts to OpenCode activity. No desktop UI yet.

Scope:

  • Implement a valid OpenCode server plugin package/entry.
  • Package contract must satisfy OpenCode loader expectations:
    • npm package export/main compatible with OpenCode;
    • default export exposes the OpenCode plugin shape;
    • file/local plugin has a stable id;
    • local/bundled dynamic import smoke test exists.
  • Plugin hooks must return immediately.
  • FamiliarOS calls run fire-and-forget with internal .catch() and debug-only logging.
  • Use short client timeouts, but do not await them in OpenCode hooks.
  • Lease strategy:
    • acquire a lease when configured with familiar;
    • pass leaseId to say/react;
    • prefer cached lease with safe fallback, or per-event acquisition if simpler and non-blocking.
  • Event mapping:
    • chat.messagethinking + throttled speech.
    • tool.execute.before edit/write/patch tool names → editing.
    • tool.execute.before shell/bash tool with test-like category → testing.
    • tool.execute.before shell/bash tool otherwise → running.
    • other tools → working.
    • plugin event with permission.askedwaiting + approval-needed speech.
    • stable session completion/error events, if verified during implementation → success / error.
    • avoid raw prompt/command/output text in speech.

Acceptance criteria:

  • Plugin can be imported from built output.
  • Plugin hook functions return without awaiting FamiliarOS IPC.
  • Unit tests cover event classification and fire-and-forget failure swallowing.
  • Manual OpenCode config can load the plugin and trigger reactions.

Checks:

  • pnpm --filter @familiaros/opencode check
  • Manual plugin load smoke test.

Phase 19C — CLI Project Setup for OpenCode

Goal: Extend familiaros configure to support project-local OpenCode setup.

Scope:

  • Add --agent opencode alongside existing --agent claude.
  • Keep Claude CLI behavior unchanged.
  • With explicit --familiar, configuration can run without desktop app.
  • Without --familiar, use local IPC familiar picker as Claude does.
  • Write project config entries for:
    • mcp.familiaros;
    • FamiliarOS instructions file, e.g. .opencode/familiaros.md;
    • FamiliarOS plugin spec/options.
  • Print exact files changed and restart guidance.
  • Warn that .opencode/opencode.jsonc can be committed and may contain the selected familiar id.
  • Do not require opencode binary on PATH to write project config; warn if not found.

Acceptance criteria:

  • familiaros configure --agent opencode --familiar fixer --local-dev --cwd <tmp> writes expected project config offline.
  • Re-running is idempotent.
  • --force replaces only FamiliarOS-managed entries.
  • Unknown agents still fail clearly.
  • Claude project setup tests still pass.

Checks:

  • pnpm --filter @familiaros/cli check
  • pnpm --filter @familiaros/opencode check
  • pnpm --filter @familiaros/claude check

Phase 19D — Desktop Integration, Packaging, Docs, Hardening

Goal: Add OpenCode to Desktop Integrations and close out docs/packaging/cross-platform hardening.

Scope:

  • Add OpenCode card next to Claude Code.
  • Desktop OpenCode setup target is explicitly global OpenCode config, not project config.
  • If project setup is desired from desktop, defer to a later phase with a project directory selector.
  • Global setup can:
    • detect OpenCode best-effort;
    • install/replace/remove global MCP entry;
    • install/update global FamiliarOS instructions;
    • install/update/remove global FamiliarOS plugin;
    • show previews and copy manual snippets;
    • show clear status and backups.
  • Preserve Claude UI/actions.
  • Package bundled OpenCode plugin/CLI resources safely:
    • no true app.asar paths;
    • no symlinked bundled entry;
    • dynamic-import smoke test for bundled plugin path.
  • Update README and mapping docs.
  • Manual verification covers:
    • invalid config;
    • custom OPENCODE_CONFIG_DIR;
    • OpenCode absent;
    • removal safety;
    • packaged bundled plugin;
    • project/global precedence;
    • macOS/Windows/Linux path differences where available.

Acceptance criteria:

  • Desktop UI clearly says OpenCode desktop setup is global.
  • No global config write occurs without explicit user action.
  • Remove only removes FamiliarOS-managed entries.
  • OpenCode absent on PATH does not prevent showing config status/previews.
  • Packaged app can locate bundled OpenCode plugin and CLI resources.
  • Docs explain exact files touched and CLI project setup vs desktop global setup.
  • pnpm check passes.

Checks:

  • pnpm --filter @familiaros/desktop check
  • pnpm --filter @familiaros/opencode check
  • pnpm check

Security/privacy requirements for every subphase

  • Never include prompt text, command text, file paths, tool output, code, logs, URLs, or secrets in familiar speech.
  • Classify tools using tool names and coarse categories only.
  • Validate familiar ids with the same strict regex as Claude.
  • Reject symlinked config/instruction/plugin write targets.
  • Keep writes inside the selected project or OpenCode config dir.
  • Back up before update/replace/remove once writes are implemented.
  • No new TCP/HTTP surface.
  • Plugin failures must never break or delay OpenCode; hooks must return immediately.

Oracle plan review

Oracle reviewed the first all-in-one Phase 19 plan and found the architecture viable but too broad and not implementation-ready.

Blockers found

  • Desktop target scope was ambiguous: global vs project setup.
  • permission.ask assumption was wrong; use event hook for permission.asked.
  • Plugin hooks are awaited by OpenCode; FamiliarOS work must be fire-and-forget, not merely timeout-bounded.
  • Plugin package/path contract was underspecified.
  • Config precedence and write targets needed tightening.
  • Data-loss protections needed hard requirements.
  • .opencode is not private; project config can be committed.
  • Manual verification was too happy-path-only.

Oracle feedback disposition

  • Fixed: Split one large phase into 4 subphases, not 6.
  • Fixed: Desktop setup is global-only unless a later project picker is added.
  • Fixed: Permission mapping uses event/permission.asked, not permission.ask.
  • Fixed: Plugin hooks must return immediately and run FamiliarOS calls fire-and-forget.
  • Fixed: Added plugin package/path contract and bundled import smoke requirement.
  • Fixed: Aligned existing config candidate order with OpenCode's own mcp add order.
  • Fixed: Added invalid JSONC, max size, symlink, backup, and atomic write requirements.
  • Fixed: Removed “private-ish” wording for .opencode and added commit warning.
  • Fixed: Combined desktop, packaging, docs, and hardening into one closeout phase to avoid oversplitting.

Implementation closeout

Phase 19A19D are implemented in the v2 workspace:

  • packages/opencode provides OpenCode config helpers, strict managed-entry classification, safe global/project writes, and the OpenCode plugin runtime.
  • packages/cli supports familiaros configure --agent opencode for project-local setup.
  • Desktop Integrations supports global OpenCode setup/removal/preview/copy, with packaged CLI resource checks and published plugin configuration.
  • README and mapping docs explain OpenCode project-local vs desktop-global setup and safe speech constraints.

Validation completed with pnpm check after @oracle implementation review.