# Flock install runbook

Install Flock by asking Claude to install `https://flk.dev/install.md`. Approve the installation and browser login when Claude asks. Claude performs the setup, explains each consent boundary in plain language, and returns one final restart line when the existing conversations are ready to join the fleet.

> 0.7.21-alpha. Binaries are unsigned. Everything below addresses the installing
> agent. Command and state reference: [/api.md](/api.md). Removal:
> [/uninstall.md](/uninstall.md).

## Installation contract

Drive the installation on the user's behalf. Do not instruct the user to type a
Flock command. The user acts only to approve a permission request, complete a
browser OAuth flow, and restart each pre-Flock plain-terminal Claude conversation
once at the end. Describe results and consent requests in plain language.

Flock installs one static `flk` binary in `~/.local/bin`. It installs tmux when
missing and approved. On a fresh macOS install, tmux has prerequisites: it
arrives via Homebrew, Homebrew's installer requires the user's password at an
interactive terminal, and both require the Xcode Command Line Tools (about
850&nbsp;MB). State these prerequisites to the user before starting. When
`xcode-select --install` cannot show its GUI dialog (SSH, no desktop session),
the tools install headlessly without sudo:
`touch /private/tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress`,
list labels with `softwareupdate -l`, then `softwareupdate -i "<label>"`.
Wiring registers the flock MCP server and the agent's lifecycle callbacks in
each profile's config home, the directory the agent keeps its state and login
in: for claude, `~/.claude` or the directory `CLAUDE_CONFIG_DIR` names; for
codex, `~/.codex` or the directory `CODEX_HOME` names. A profile's config home
is either the isolated directory Flock creates for it or
an existing directory attached with `flk profile set-home`. A claude profile
also gets `/flock:*` commands and the flock-delegation skill, plus a statusline
when the config home has none of its own. A profile on its own isolated config
home also gets a managed block in that home's `CLAUDE.md` (`AGENTS.md` for
codex); an adopted config home gets none. Wiring also sets
`remoteControlAtStartup` in a claude config home when the key is absent, so
sessions there connect Remote Control at startup. An optional macOS
LaunchAgent refreshes quota every 15 minutes and performs lead-capacity
enforcement: when the lead (the session holding Flock's coordination lease) is
live, its capacity reading is determinate and exhausted, and another live
session has determinate lead capacity, the lease moves to that session;
otherwise the lead is retained. Flock opens no network listener, and quota reads create no separate token store. A profile's isolated home sits beneath the Flock root and holds that account's own login files; briefs and results are stored on the ledger as given, without secret redaction.

## Install the binary

Detect `uname -sm` and select the matching artifact:

| platform | artifact |
|---|---|
| Darwin arm64 | `flk-darwin-arm64` |
| Darwin x86_64 | `flk-darwin-amd64` |
| Linux aarch64 | `flk-linux-arm64` |
| Linux x86_64 | `flk-linux-amd64` |

On a minimal Linux image, run `apt-get install -y curl ca-certificates` first if
`curl` is absent. Download the artifact and the checksum file named `checksums.txt` from
`https://flk.dev/dl/`. First verify the checksum file's signature:
download the signature to the checksum file's own directory
(`curl -fsSL -o /tmp/checksums.txt.minisig "https://flk.dev/dl/checksums.txt.minisig"`)
and run
`minisign -Vm /tmp/checksums.txt -P RWSyAr20tQVUoGpgA9Zn8hLirHhzlVi7QlP6eR3vUh2Ln2Nt13obiYQx`
(install minisign via brew or apt if absent; the same public key is served
at `/dl/minisign.pub` — this runbook and that file must agree). Then verify
the artifact by comparing its entry in
`checksums.txt` with `shasum -a 256 /tmp/flk` on macOS or `sha256sum /tmp/flk`
on Linux. Stop and report a failed signature, a missing entry, or a mismatch. Before writing the
verified binary to `~/.local/bin/flk` with
`install -m 0755 /tmp/flk ~/.local/bin/flk`, explain that the write installs an
unsigned executable and obtain the user's approval.

```sh
curl -fsSL -o /tmp/flk "https://flk.dev/dl/<artifact>"
curl -fsSL -o /tmp/checksums.txt "https://flk.dev/dl/checksums.txt"
curl -fsSL -o /tmp/checksums.txt.minisig "https://flk.dev/dl/checksums.txt.minisig"
minisign -Vm /tmp/checksums.txt -P RWSyAr20tQVUoGpgA9Zn8hLirHhzlVi7QlP6eR3vUh2Ln2Nt13obiYQx || exit 1
PUB=$(grep "<artifact>" /tmp/checksums.txt | awk '{print $1}')
LOC=$(shasum -a 256 /tmp/flk 2>/dev/null || sha256sum /tmp/flk); LOC=${LOC%% *}
[ -n "$PUB" ] && [ "$PUB" = "$LOC" ] || exit 1
mkdir -p ~/.local/bin && install -m 0755 /tmp/flk ~/.local/bin/flk
```

## Discover accounts and wire profiles

Start with `flk init --discover`. Discovery reads four sources: the top level of
`~` (`.claude`, `.claude-*`, `.codex`, `.codex-*`), the environment of running
claude and codex processes, a sweep under `~` to depth 4 that skips Library,
caches, and package trees (a swept directory must also carry a state or
credential file: `.claude.json` or `.credentials.json`; `auth.json` for
codex), and the isolated config homes of existing profiles. A directory from the first
three sources is proposed when it holds a login. A profile's own isolated
config home is proposed when it holds a login for the profile's account (any
login, when the account declares no address) and the profile points elsewhere.
For claude, the login is read with `claude auth status --json` when the claude
binary is installed and answers, and from the state file otherwise
(`<home>/.claude.json`; for the default install `~/.claude`, root
`~/.claude.json` is read first). For codex, it is read from `codex login
status`.

For each config home, the proposal prints the proposed name, the agent, the
signed-in identity (an address, or a mode token such as `chatgpt` when codex
exposes none), and the directory; then the binding; then the sessions Claude
Code records for that config home (pid, working directory, session name). The
binding is one of:

- a new account and profile;
- a new profile on an account already on record whose declared address
  matches the login;
- attachment to an existing profile whose account declares the same address,
  when that profile's current config home holds no login;
- re-attachment of an existing profile to its own isolated config home, which
  clears the attachment so the profile uses its own isolated config home again.

Config homes already attached to a profile are skipped. `flk profile rm`
detaches an attached config home; it does not delete the directory or its
login.

Pass `--owner <owner>` when a new account will be created and accounts.toml
records no single owner (on a terminal, discovery prompts for it instead),
`--yes` after consent, and `--only <names>` to adopt a subset (names are the
first column of the proposal). After consent, discovery also wires the
profiles and applies the conversation migration described under Converge
conversations that predate Flock, without a separate dry run: sessions in
tmux panes are moved into Flock sessions, and plain-terminal sessions are
reported and left alone. The consent to discovery covers that migration, so
state both in the consent request; `--no-wire` skips both. Verify each
adopted profile with `flk whoami`, which prints the identity and its source
(`claude auth status` or `state file`) per profile.

Claude Code stores one login per config home. Every worker dispatched to the
profile attached to `~/.claude` uses the login that directory holds. A session
already running keeps the login it started with; a later `/login` in another
session on the same config home replaces the stored login and does not change
the running session. A login that exists only in a
running session cannot be adopted; create a config home for that account with
`flk profile login` (next section). When a profile's account declares an
address and `claude auth status` reports a different address for the
profile's config home, `flk delegate` and `flk new` refuse, `flk profile
set-home` refuses (`--force` binds it anyway), and `flk doctor` reports the
disagreement on a `binding` line.

## Browser login

Run `flk profile login <name> --agent claude --email <address> --owner <owner>`
inside tmux so stdin and stdout are TTYs: with a running tmux server, `tmux
new-window -n flock-login 'flk profile login …'`; without one, `tmux
new-session -d -s flock-login 'flk profile login …'`. The command creates the
account with the address declared, the profile, its isolated config home, and
the wiring, then runs the login.

When `claude auth login --help` succeeds and no arguments follow `--`, the
login is `claude auth login --email <address>`: it opens the browser, prints
the login URL with the address pre-filled, and waits for the browser flow.
Otherwise Claude Code itself opens and the user runs `/login` inside it. The
pre-filled address does not bind the account: a browser already signed into
another account completes the flow as that account. Relay what the command
printed to the user, and ask them to complete the flow, and any account
chooser, in a browser window signed into the declared address. Never enter,
read, or relay credentials or a code the browser offers for pasting.

When the flow returns, the address is read with `claude auth status`, or the
state file when the binary cannot answer, and compared with the declared
address. On a mismatch, the stored credential is moved aside
(`.credentials.json` renamed; on macOS the keychain entry for that config home
is also removed) and the command exits with the retry instruction, unless the
config home is `~/.claude`, where the move is refused, the credential stays in
place, and the command still exits with the retry instruction. When the move
does not complete, the command reports the
profile as WRONG-ACCOUNT with the step that failed, and some or all of the
credential remains. An account with no declared address gets a warning and no
comparison.

For codex, use `--agent codex` and omit `--email`. Over SSH, or on Linux with
no display, and with no arguments after `--`, the command adds
`--device-auth`.

If the agent runtime's permission prompt blocks profile wiring, describe the
writes listed under Installation contract for this profile's agent, request
permission, and retry it yourself.

## Verify the installation

Run `flk capabilities`, `flk whoami`, and `flk doctor --deep`. Resolve identity,
credential, hook, MCP, tmux-format, and live usage-contract drift
before declaring the install complete. Deep doctor uses the network and, when Claude's token is in the Keychain rather than a credential file, for
Claude quota on macOS, requires GUI Keychain access.

Explain account virtualization as one interface to isolated accounts, each with
its own login and limits. Claude auto-routing selects the least-consumed eligible
logged-in profile when quota data is fresh. Codex capacity comes from its rollout rather than a usage endpoint. Automatic routing ranks candidates by the lowest worst-window percentage when every candidate has a fresh reading, and by recorded transcript usage otherwise; there is no authoritative capacity
reading, so its automatic routing selects any logged-in Codex profile. Every
dispatch reports the target profile and the routing reason, and recall searches transcripts across
accounts when invoked.

On macOS, explain that automatic Claude quota refresh and lead-capacity
enforcement require a LaunchAgent. After the user consents conversationally,
run `flk quota install-agent` yourself.

## Converge conversations that predate Flock

Before a standalone `flk migrate`, run `flk migrate --dry-run`. It enumerates running pre-Flock Claude
processes and prints the conversations it can attest, the mapped profile, and
the working directory. It skips this installing conversation so it can restart
last. Describe the plan in plain language, including every skip or refusal, and
obtain the user's consent conversationally before running `flk migrate`.

Migration accepts only an attested conversation and matching config home. It
rechecks that the process is idle, that its transcript is quiescent, and, for a
tmux pane, that the composer is positively recognized as empty. It exits the
old Claude process gracefully and resumes the same conversation in a managed
session. Composer recognition fails closed.

A Claude process in a plain terminal is not signaled by default. Tell the user
that each such conversation needs one manual `claude --continue` restart and
leave it running. `--allow-signal` crosses
a separate safety bar: use it only after explicitly narrating that Flock will
wait for transcript quiescence, reject non-shell child processes, send SIGTERM,
and refuse concurrent resume if the process does not exit. The default install
does not use this flag.

If resume fails after an old process exits, Flock records a `migrate-stranded`
event and prints the exact resume command. Preserve that output, report the
failure, and recover the conversation before continuing.

Managed session names are observable roster identities. Human-driven claude
session names converge on `<account>-<slug>`: new claude sessions begin as
`<account>-main-<seq>` and rename when their first transcript slug appears,
while migration can use the known slug immediately. A delegation runs in the
target profile's live session; when none is live, Flock spawns one under the
profile's name, and a dispatch to the sender's own profile with no other live
session is refused. Worktree-isolated dispatches are created under the
configured workspace at `.flock/worktrees/<task-id>`; with no configured
workspace the current directory stands in, and when that path lies inside the
repository the worktree goes to `~/.flock/state/worktrees/<hash>/<task-id>`.

## Finish this installing conversation

You predate the hooks, MCP tools, skill, and statusline you just installed.
Enumerate every other running Claude conversation and summarize which ones the
dry run can migrate. Give the user one consent sentence: "I can now move the
idle Claude conversations into Flock-managed sessions without losing their
conversation history; plain-terminal conversations will be left for manual
restart. May I proceed?"

After consent, run `flk migrate` without `--allow-signal`. Migration restarts
eligible tmux conversations itself. Report any refusal or stranded resume before
proceeding. Then tell the user to enter `/exit` in this installing conversation.
After it exits, this installing conversation requires this command:

```text
claude --continue
```

Explain before that line that Claude resumes this same conversation, so nothing
is lost. List one `claude --continue` command for each pre-Flock plain-terminal
conversation left running, plus this installing conversation. After those
restarts, the native surfaces load and the fleet is complete.

## Completion report

End the install by showing the user their fleet, by name, from current
command output (`flk --version`, `command -v flk`, `flk account ls`,
`flk profile ls`, `flk ls`, `flk doctor`) and this install's own record
of what it did. The report contains:

- the installed version and the path `command -v flk` prints;
- each account and profile created or adopted, labeled as `flk ls`'s
  ACCOUNT column shows them (provider:email where both are on record, the
  account name otherwise), and the default profile (`flk profile ls` marks
  it with `*`);
- each row `flk ls` shows, by its NAME column value (the attach
  target is the name without the "(lead)" mark): what it is (a migrated
  conversation of theirs, or a session Flock spawned under a profile name) and the attach command:
  `flk attach <name>`. A row that is not attachable (`resumable`,
  `stale record`) is reported with its disposition instead. This installing
  conversation is not in the list; its continuation is the
  `claude --continue` line above;
- doctor's remaining findings, each with its fix, or "left as is" with the
  reason;
- any step that did not go as this runbook says it should;
- a sample first task, written as a sentence the user says in this
  conversation. Take the target from the fleet this install just built,
  by name from `flk profile ls`: a different profile of the same declared
  owner when one exists (match each profile's `account=` value in
  `flk profile ls` to the account name in `flk account ls` and compare
  `owner=` values), and the profile this conversation
  runs as otherwise. On a fleet holding a codex profile named `oai` the
  sample reads: "Ask oai to add the first 7 prime numbers and reply with
  the sum." Explain in one line what happens: Flock attempts delegation
  to that profile; if dispatch succeeds, that profile's session runs the
  task when it is next between turns with an empty composer and the result returns in this conversation, and a refusal,
  failure, or clarification request returns the task's state and reason
  instead.

List every session Flock created or migrated during this install, including
any that have since ended.
