- 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.
14 KiB
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:
-
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.ts→familiaros mcp --familiar <id>. - Claude command/config helpers:
packages/claude/src/claude-code.ts. - Desktop setup:
apps/desktop/src/agent-setup.ts.
- Public tools stay exactly
-
Instructions/memory
- Claude writes
~/.claude/familiaros.mdand 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.
- Claude writes
-
Hooks/events
- Claude hooks write managed command entries to
~/.claude/settings.jsonor 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:
UserPromptSubmit→thinking+ throttled speech.PreToolUse Edit/Write/MultiEdit→editing.PreToolUse Bashtest command →testing, otherwiserunning.- other
PreToolUse→working. PermissionRequest→waiting+ forced short speech.Notification→waving.Stop→success+ throttled speech.StopFailure→error+ throttled speech.
- Claude hooks write managed command entries to
-
CLI project setup
familiaros configure --agent claude --familiar <id> --cwd <project>configures project-local Claude MCP and hooks.- Explicit
--familiarworks without desktop app; omitted--familiaruses local IPCfamiliars.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
mcpatv1/opencode/packages/opencode/src/config/config.tslines 220-229. - Local MCP shape is in
v1/opencode/packages/opencode/src/config/mcp.tslines 5-19:{ type: "local", command: string[], environment?, enabled?, timeout? }.
opencode mcp addis interactive, so automated FamiliarOS setup should directly edit JSON/JSONC config with the same shape.
- OpenCode config has
-
Config locations
- Global config uses OpenCode global config dir, with
OPENCODE_CONFIG_DIRoverride support. - Project configs include
opencode.json,opencode.jsonc,.opencode/opencode.json,.opencode/opencode.jsonc. - OpenCode's own MCP add path resolution checks
opencode.jsonbeforeopencode.jsonc, then.opencode/*:v1/opencode/packages/opencode/src/cli/cmd/mcp.tslines 399-415. - OpenCode writes config with
jsonc-parser:v1/opencode/packages/opencode/src/cli/cmd/mcp.tslines 417-431.
- Global config uses OpenCode global config dir, with
-
Instructions
- OpenCode config supports
instructions: string[]:v1/opencode/packages/opencode/src/config/config.tslines 238-240. - OpenCode config merge concatenates instruction arrays without duplicates: lines 54-59.
- OpenCode config supports
-
Plugins/events
- OpenCode plugin hook surface:
v1/opencode/packages/plugin/src/index.tslines 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 plugineventfor bus eventpermission.asked. - OpenCode awaits plugin hooks directly, so plugin hooks must return immediately and run FamiliarOS calls fire-and-forget.
- OpenCode plugin hook surface:
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.
Recommended subphase sequence
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/opencodeor 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.
- follow OpenCode's own existing file order:
- 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 checkpnpm --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
leaseIdtosay/react; - prefer cached lease with safe fallback, or per-event acquisition if simpler and non-blocking.
- acquire a lease when configured with
- Event mapping:
chat.message→thinking+ throttled speech.tool.execute.beforeedit/write/patch tool names →editing.tool.execute.beforeshell/bash tool with test-like category →testing.tool.execute.beforeshell/bash tool otherwise →running.- other tools →
working. - plugin
eventwithpermission.asked→waiting+ 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 opencodealongside 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.jsonccan be committed and may contain the selected familiar id. - Do not require
opencodebinary 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.
--forcereplaces only FamiliarOS-managed entries.- Unknown agents still fail clearly.
- Claude project setup tests still pass.
Checks:
pnpm --filter @familiaros/cli checkpnpm --filter @familiaros/opencode checkpnpm --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.asarpaths; - no symlinked bundled entry;
- dynamic-import smoke test for bundled plugin path.
- no true
- 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 checkpasses.
Checks:
pnpm --filter @familiaros/desktop checkpnpm --filter @familiaros/opencode checkpnpm 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.askassumption was wrong; useeventhook forpermission.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.
.opencodeis 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, notpermission.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 addorder. - Fixed: Added invalid JSONC, max size, symlink, backup, and atomic write requirements.
- Fixed: Removed “private-ish” wording for
.opencodeand added commit warning. - Fixed: Combined desktop, packaging, docs, and hardening into one closeout phase to avoid oversplitting.
Implementation closeout
Phase 19A–19D are implemented in the v2 workspace:
packages/opencodeprovides OpenCode config helpers, strict managed-entry classification, safe global/project writes, and the OpenCode plugin runtime.packages/clisupportsfamiliaros configure --agent opencodefor 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.