# Flock uninstall runbook

> This runbook addresses the agent performing the removal. It has two
> halves: the one-command path when `flk` runs, and a manual path for when
> `flk` cannot run. Outside the optional state deletion in step 6 and
> `--purge-state`, neither half deletes credentials, agent homes, or
> conversations. The edits remove entries Flock wrote; step 1 also names
> two keys whose removal is the user's call.

## When flk still runs

Run `flk uninstall` and show the user its plan, then rerun with `--yes`
after they consent. The plan names any `statusLine` matching Flock's
command shape, per home; for each one the user says is user-authored, add
`--keep-statusline <profile>` (repeatable; the reserved selector
`@default` names the default claude home, and profile names may not begin
with `@`) to the `--yes` run, and the rest are removed. `flk uninstall`
leaves `remoteControlAtStartup`; when the user wants it gone, apply step
1's `REMOVE_RC=1` edit after the `--yes` run. Add `--purge-state` only if the user wants the roster,
task ledger, event history, and every isolated profile home deleted,
including in-home credential files and, on macOS, each isolated claude
home's Keychain token, which flk deletes before removing the state. Any
failure to enumerate profiles, read one, or delete its Keychain entry
stops the purge, so a token cannot be orphaned. Add `--binary` to
delete `flk` itself. Then have the
user restart their agent sessions; wiring changes take effect at restart.

Test whether flk runs with a bounded call: `timeout 5 flk --version` on
Linux, or on macOS
`perl -e 'alarm 5; exec @ARGV or die "cannot exec: $!\n"' -- flk --version`.
A timeout or an exec failure means it does not run: use the manual path.

## Manual path: flk cannot run

Flock's wired surfaces carry their own names, so removal is a fixed set of
edits. Work through each agent config home Flock wired: the default
`~/.claude`, every `~/.flock/profiles/<name>/home`, and any external home
listed under `home =` in `~/.flock/profiles/*/profile.toml`.

**1. Hooks and statusline**: in each home's `settings.json`. Before
deleting, judge two keys that cannot be attributed mechanically: a
`statusLine` whose command ends in ` statusline` is normally Flock's, but a
user-authored command can share that shape; and wiring sets
`remoteControlAtStartup: true` only when the key was absent, so its origin
is unknowable after the fact. Name both to the user and follow their call.
Then remove every nested hook whose command ends in ` event claude`
(keeping any other hooks that share its entry), each entry that becomes
empty, and, per the user's two calls, the `statusLine` and
`remoteControlAtStartup` keys: run the script with `REMOVE_STATUSLINE=1`
or `REMOVE_RC=1` in the environment for each key the user wants gone, and
with neither to remove hooks alone. With Python:

```sh
REMOVE_STATUSLINE=1 REMOVE_RC= python3 - "$HOME/.claude/settings.json" <<'EOF'
import json, os, sys
p = sys.argv[1]
doc = json.load(open(p))
changed = False
hooks = doc.get("hooks", {})
for ev in list(hooks):
    entries = []
    for e in hooks[ev]:
        inner = [h for h in e.get("hooks", [])
                 if not h.get("command", "").endswith(" event claude")]
        if len(inner) != len(e.get("hooks", [])):
            changed = True
            if not inner:
                continue
            e = dict(e, hooks=inner)
        entries.append(e)
    if entries: hooks[ev] = entries
    else: del hooks[ev]
if not hooks: doc.pop("hooks", None)
if os.environ.get("REMOVE_STATUSLINE") == "1":
    sl = doc.get("statusLine", {})
    if sl.get("command", "").endswith(" statusline"):
        doc.pop("statusLine", None); changed = True
if os.environ.get("REMOVE_RC") == "1" and "remoteControlAtStartup" in doc:
    doc.pop("remoteControlAtStartup"); changed = True
if changed: json.dump(doc, open(p, "w"), indent=2)
EOF
```

**2. MCP server**: delete the `flock` key under `mcpServers` (and
`mcpServers` itself when it becomes empty). The file location depends on
the home: for the default `~/.claude`, the state file is the sibling path
`~/.claude.json`; for every other home it is `.claude.json` inside it.

**3. Flock-owned files**: in each home, delete the directories
`commands/flock` and `skills/flock-delegation`, and, in isolated profile
homes only, the block in `CLAUDE.md` between `<!-- flock:managed:begin -->`
and `<!-- flock:managed:end -->`.

**4. Codex homes**: in each wired codex home's `config.toml`, delete the
`notify` entry when it has three or more elements and the final two are
`"event", "codex-notify"`, and the `flock`
key under `mcp_servers` (and `mcp_servers` itself when empty). In isolated
codex homes, also delete the managed block in `AGENTS.md`, between the
same markers as step 3.

**5. The quota LaunchAgent (macOS)**: when
`~/Library/LaunchAgents/xyz.tryflock.flk-quota.plist` exists:

```sh
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/xyz.tryflock.flk-quota.plist"
rm "$HOME/Library/LaunchAgents/xyz.tryflock.flk-quota.plist"
```

**6. The binary and the state**: obtain the user's consent before any
deletion in this step; everything in it is irreversible. The state
directory `~/.flock` holds the roster, task ledger, event history, and any
isolated profile homes, whose in-home credential files (`.credentials.json`,
codex `auth.json`) go with them. Order matters: on macOS, delete each
isolated claude home's Keychain entry first, while
`~/.flock/profiles/<name>/profile.toml` still names the home the service
name is derived from:

```sh
home="$HOME/.flock/profiles/<name>/home"   # the expanded absolute profile-home path Flock uses
suffix=$(printf %s "$home" | shasum -a 256 | cut -c1-8)
security delete-generic-password -s "Claude Code-credentials-$suffix"
```

Then delete `~/.flock`, and last the binary `~/.local/bin/flk`. After
deletion, sessions
using an isolated home require login again; no other surface on the
account is affected, and nothing is revoked server-side.

**7. Report**: end by naming what was removed from where, what was kept,
and the behavior change: each agent session stops reporting to Flock at
its next restart. Running tmux sessions may hold live conversations; leave
them to the user.

The removal never requires editing anything Flock did not write, apart
from the two judgment calls step 1 names. If a settings file
does not parse, stop and show the user rather than guessing.
