- 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.
12 KiB
Phase 17 — FamiliarOS CLI Project Setup
Goal
Add a real npm-distributed FamiliarOS CLI that lets users configure the current project to use a selected familiar with Claude, using one simple command.
Primary command:
npx @familiaros/cli configure --familiar fixer
This should configure both Claude MCP and Claude hooks for the current project. No extra MCP/hooks questions.
Non-goals
- App-installed
familiarosshim / Settings “Install CLI” button. Defer to a later phase. - Shared/team project config by default.
- Supporting agents other than Claude.
- Remote/custom catalog flags.
familiaros install <familiar-id>; defer familiar installation CLI to a later phase.- Exposing familiar install/remove/default controls through MCP tools.
- Building a complex TUI. Keep interaction simple.
User-visible/manual outcome
From a project directory, users can run:
npx @familiaros/cli configure --familiar fixer
Expected result:
- Claude MCP is configured locally for the current project with FamiliarOS
--familiar fixer. - Claude project-local hooks are configured with
--project-local --familiar fixer. - Starting Claude from that project makes MCP tools and hook speech/reactions target fixer.
Users can also run:
npx @familiaros/cli configure --agent claude --familiar fixer --cwd /path/to/project --yes
If --familiar is omitted, the CLI lists installed familiars and prompts for one.
Acceptance criteria
packages/cliexposes a real executable bin,familiaros.familiaros configure --familiar <id>runs non-interactively for Claude using current working directory.--agent claudeis accepted; unsupported agents fail clearly.--cwd <path>targets another project directory; default isprocess.cwd().--yesis accepted as a compatibility/no-op flag; there is no final confirmation prompt in Phase 17.- If
--familiaris missing, CLI queries installed familiars from the running FamiliarOS desktop app and prompts the user to choose. - CLI configures Claude MCP using local project scope, private to the current user.
- CLI configures Claude hooks in
<project>/.claude/settings.local.json, private to the project/user. - Claude MCP command is installed while spawning
claudewithcwdset to the resolved target project. - Long-lived generated Claude MCP/hook commands use a stable package command, not a temporary
npx @familiaros/cliinstall path. - Hook commands include
--familiar <id>. - Existing non-FamiliarOS hooks in
.claude/settings.local.jsonare preserved. - Existing FamiliarOS-managed hooks are replaced safely.
- CLI fails with clear instructions if FamiliarOS desktop app is not running.
- CLI fails clearly if Claude Code is unavailable on
PATH. - CLI validates selected familiar ids and rejects unsafe values.
Proposed files/directories
packages/cli/package.jsonpackages/cli/src/index.tspackages/cli/src/check-cli-contract.tspackages/client/src/index.tsapps/desktop/src/local-ipc.tsapps/desktop/src/local-ipc-protocol.tsapps/desktop/src/check-local-ipc-protocol.tspackages/claude/src/hook-settings.ts(reuse project-local hook writer by passing settings path)
Technical approach
CLI command shape
familiaros configure [--agent claude] [--familiar <id>] [--cwd <path>] [--yes]
Defaults:
--agent claude--cwd process.cwd()- configure both MCP and hooks
- local/private project config
Installed familiar discovery
Add a narrow local IPC/client method for the user-run CLI:
familiars.list
Return only safe display data:
{
ok: true,
familiars: [
{ id, displayName, installed: true, builtIn, broken }
],
defaultPetId
}
The CLI uses this to validate --familiar and power the picker.
Stable generated commands
Do not write temp/cache paths from npx @familiaros/cli into Claude config. Instead make the CLI package self-contained and expose wrapper subcommands:
familiaros mcp --familiar fixer
familiaros hook --familiaros-managed --project-local --familiar fixer
Generated long-lived commands should use the package version being configured:
npx -y @familiaros/cli@0.0.0 mcp --familiar fixer
npx -y @familiaros/cli@0.0.0 hook --familiaros-managed --project-local --familiar fixer
The mcp wrapper starts the existing FamiliarOS MCP server implementation. The hook wrapper delegates to the existing Claude hook handler.
This avoids storing an absolute path into npm's temporary npx cache.
Claude MCP configuration
Use Claude’s own CLI for local project MCP setup when available:
claude mcp add-json familiaros '<json>' --scope local
JSON shape:
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@familiaros/cli@0.0.0", "mcp", "--familiar", "fixer"],
"env": {}
}
Spawn claude mcp add-json with cwd set to the resolved target project directory so Claude's local MCP scope attaches to the intended project.
Do not directly mutate ~/.claude.json in this phase; delegate that to claude mcp add-json.
Claude project-local hooks
Write hooks directly to:
<project>/.claude/settings.local.json
Use existing installClaudeHooks(settingsPath, commandMode, selectedPetId) with a CLI-appropriate command mode/path if possible. If needed, add a small command builder option so the npm CLI writes hook commands that call the installed npm Claude CLI:
npx -y @familiaros/cli@0.0.0 hook --familiaros-managed --project-local --familiar fixer
Project-local hooks are private and should not require committing repo files.
Before writing hooks:
- resolve and validate the target project directory;
- reject symlinked
<project>/.claudedirectories; - ensure
<project>/.claude/settings.local.jsonresolves inside the target project; - preserve existing non-FamiliarOS settings and hooks.
Interactive picker
If --familiar is missing:
- list usable installed non-broken familiars, including built-in unless explicitly disallowed later
- use a simple stdin/stdout numbered picker
- no extra MCP/hooks questions
Preflight and idempotency
Before writing anything:
- verify FamiliarOS desktop is reachable and supports
familiars.list; - verify the selected familiar is installed and usable;
- verify Claude Code is available on PATH;
- verify target project path and hook path safety;
- build the version-pinned wrapper commands.
If any preflight fails, do not write MCP or hooks.
If a local Claude MCP entry named familiaros already exists, configure should replace it by invoking Claude's add/update flow for the same server name when supported by claude mcp add-json; if Claude refuses, fail clearly before writing hooks.
Risks and tradeoffs
- Adding public local IPC familiar listing is a new surface. Keep it read-only and minimal.
- Invoking
claudeCLI can fail if Claude Code is unavailable on PATH. CLI should print the exact failure and next step. - Project-local hooks and Claude local MCP scope are stored in different places by Claude design.
- Npm
npxhook commands may run package resolution at hook time. This is acceptable for npm-first CLI but may be slower than future app-installed shim. - Generated commands are version-pinned for stability; users may need to rerun configure after upgrading FamiliarOS CLI.
Security/privacy notes
- Do not expose filesystem install/remove/default mutation over MCP.
- Validate project path and familiar id before writes.
- Only write inside
<project>/.claude/settings.local.jsonfor hooks. - Reject unsafe project-local hook paths, including symlinked
.claudedirectories. - Preserve non-FamiliarOS settings/hooks.
- Do not log prompt/hook payloads or secrets.
Test/check plan
- Unit/contract check for CLI arg parsing and generated Claude config.
- Contract check that existing hooks are preserved and FamiliarOS-managed hooks are replaced.
- Mocked
claudebinary check for exactadd-jsonargv,--scope local, JSON shape, and spawned cwd. - Noninteractive
--familiarcheck; missing--familiarnon-TTY failure/picker behavior. - Generated command version pinning check.
- Project hook writer rejects symlinked
.claude/ unsafe cwd. - IPC protocol check for
familiars.listvalidation/result shape. - MCP public tool list remains exactly
familiaros_status,familiaros_say,familiaros_react. - Package build/test:
pnpm --filter @familiaros/cli build
pnpm --filter @familiaros/cli test
pnpm --filter @familiaros/client test
pnpm --filter @familiaros/desktop build
pnpm --filter @familiaros/desktop test
pnpm --filter @familiaros/claude test
Manual verification guide
-
Run FamiliarOS desktop.
-
In a test project, run:
npx @familiaros/cli configure --familiar fixer -
Confirm command succeeds without MCP/hooks prompts.
-
Confirm Claude local MCP entry for the project targets
--familiar fixer. -
Confirm
<project>/.claude/settings.local.jsoncontains FamiliarOS hooks with--familiar fixer. -
Start Claude in that project.
-
Confirm
/mcpshows FamiliarOS connected. -
Submit a prompt and confirm hook bubble appears on fixer.
-
Call
familiaros_statusand confirm actual target is fixer.
Oracle plan review
Oracle reviewed the Phase 17 plan and recommended revision before implementation.
Oracle feedback disposition
- Fixed: Changed long-lived generated commands from temporary absolute package paths to self-contained, version-pinned
npx -y @familiaros/cli@<version> mcp/hook ...wrappers. - Fixed: Removed final confirmation prompt from Phase 17;
--yesis accepted as no-op compatibility only. - Fixed: Spec now requires spawning
claude mcp add-jsonwithcwdset to the target project. - Fixed: Added project-local hook path safety requirements for symlinked
.claudeand inside-project resolution. - Fixed: Deferred
familiaros install <familiar-id>out of Phase 17 to avoid expanding mutation/security scope. - Fixed: Added preflight/idempotency requirements before writing MCP/hooks.
- Fixed: Added version pinning, mocked Claude CLI tests, project hook safety tests, noninteractive CLI tests, and MCP public tool-list regression to test plan.
Implementation notes
- Added
familiarosbin in@familiaros/cli. - Added
configure,mcp, andhookCLI command paths. - Added read-only
familiars.listlocal IPC/client method. configure --familiar <id>writes config without requiring the desktop app to be running; omitting--familiarstill queries the running desktop app for interactive familiar selection.- Claude MCP config is written through
claude mcp add-json familiaros <json> --scope localwithcwdset to the target project. - Project-local hooks are prepared before MCP mutation and written only after MCP configuration succeeds.
- Generated MCP/hook commands use version-pinned
npx -y @familiaros/cli@<version>wrappers. - CLI-generated npm hook timeout is
10seconds to toleratenpxstartup. - Project-local hooks include the internal
--project-localmarker so global FamiliarOS hooks can detect project-specific FamiliarOS hooks and skip themselves, preventing duplicate default/project familiar reactions. --force/--replaceremoves any existing local Claude MCPfamiliarosentry before adding the new one.- Hidden maintainer flag
--local-devwrites localnode <repo>/packages/cli/dist/index.js ...commands for pre-release testing; it is intentionally omitted from user help.
Oracle implementation review
Oracle approved the implementation after one revision pass.
- Fixed: Avoid partial config by parsing/merging hook settings before MCP mutation and writing hooks only after MCP succeeds.
- Fixed: Reject symlinked
.claude, non-filesettings.local.json, malformed hook event arrays, and unsafe project-local hook paths. - Fixed: Added
publishConfig.access = publicfor npm-distributed packages. - Fixed: Added
familiars.listresponse shape validation. - Fixed: Added mocked Claude CLI cwd/argv/JSON test.
- Fixed: Increased CLI-generated hook timeout and added MCP wrapper signal forwarding.
- Fixed: Added global-hook duplicate prevention using explicit project-local hook marker detection.
- Fixed: Hardened project-local hook detection to reject symlinks/non-files, cap settings size, and ensure the settings path stays under the Claude project dir.
- Fixed: Hook CLI boundaries reject
--familiarwith a missing value. - Accepted: Generated commands are pinned to the package version; release must publish
@familiaros/cli,@familiaros/client,@familiaros/claude, and@familiaros/mcpat the same version.