MCP tools
These are the tools your agent calls after Flock is wired; they are not user-facing commands or prompt keywords. flk mcp serves MCP over stdio; flk profile wire registers it as server flock in each profile home. Claude registration is written to the profile's Claude state file; Codex registration is written under mcp_servers.flock in config.toml. Gemini CLI registration uses gemini mcp add with user scope under the profile's home. Native tools load at session start. An agent must inspect the tools exposed to its own session before promising to call one; another profile's wiring does not prove this session has loaded the server.
flock_roster
- Arguments
(none)- Returns
- {live: [...], dead: [...], lead: {...}}
flock_delegate
- Arguments
to_profile*, brief*, mode (wait default | async), cross_owner ('true' confirms a cross-owner dispatch), isolation (worktree), thread, model, effort, keep_model (borrow a model and effort for the task; restored after the turn unless 'true')- Returns
- wait: {task_id, routing, state, result, error} · async: {task_id, routing, state, note}. Async runs inside the MCP server process, which must stay alive until collection; unlike CLI --wait=false, it does not detach
flock_msg_send
- Arguments
to*, text*- Returns
- mailbox write + turn-boundary delivery attempt
flock_msg_ls
- Arguments
(none)- Returns
- this session's mailbox, unread first
flock_msg_read
- Arguments
(none)- Returns
- unread messages, marked read on return
flock_task_review
- Arguments
task_id*, to*, focus- Returns
- dispatches the review; returns {task_id, thread, state, verdict, note, result}
flock_thread
- Arguments
name*- Returns
- the thread's tasks in order, briefs and results trimmed to first lines
flock_task_clarify
- Arguments
task_id*, answers*, mode- Returns
- answers a needs-clarification task and redispatches it (same record, same worker, three-round cap)
flock_task_status
- Arguments
task_id*- Returns
- task record, result omitted
flock_task_brief
- Arguments
task_id*- Returns
- the framed brief the task's target session must receive (what the wake-up line points at); records the delivery
flock_model
- Arguments
session*, model, effort, default- Returns
- with only
session: the model and effort the agent last reported. Withmodeland/oreffort: model selection (seeflk model); returns the previous model and effort
flock_task_result
- Arguments
task_id*- Returns
- full task record
flock_handoff
- Arguments
to_profile*, context*- Returns
- {session, brief, hint}; appends a HANDOFF note and spawns a session pointed at it
flock_note
- Arguments
text*- Returns
- appends to .flock/brief.md with author and timestamp
flock_recall
- Arguments
query*- Returns
- matches with resume commands
flock_lead
- Arguments
(none)- Returns
- {lead, session_id, profile, granted_by, granted_at, alive, chain_len}
flock_lead_recuse
- Arguments
successor*, reason- Returns
- the new assignment; the caller must be the current lead
flock_usage
- Arguments
session, live (bool)- Returns
- transcript stats, or authoritative quota per profile with per-profile cache fallback
flock_capabilities
- Arguments
(none)- Returns
- per-profile capability map
Operator and diagnostic CLI
flk provides CLI commands for agents and operators. State defaults to ~/.flock, with FLOCK_HOME as an override. Requested operations can also write provider homes, project files, the executable and a macOS LaunchAgent plist. The quota LaunchAgent records its FLOCK_HOME in the plist.
Inspect before you dispatch
Illustrative example, not captured output
This sequence checks identity and fleet state, then assigns one bounded task and waits for its recorded result.
flk whoami
flk ls
flk delegate --to claude:auto "Inspect the failing test, propose the smallest fix, and return the file path plus evidence."Automatic routing prints the profile chosen. A refusal, failure, or clarification request stays visible as task state.
Identity & configuration
flk init [--profile p] [--agent a] [--account n] [--owner o] [--email e] [--no-wire]
one-shot onboarding: account + profile + default + wire. Prompts on a TTY. Idempotent. Does not perform the login (human, TTY)
flk init --discover [--owner o] [--yes] [--only names] [--no-wire]
adopt existing logged-in agent homes from four sources: the top level of ~ (.claude, .claude-*, .codex, .codex-*), the environment of running agent processes, a sweep under ~, and profiles' own isolated homes. A home with no login is not proposed; a home already attached to a profile is skipped. Each proposed home is bound in one of four ways: a new account and profile (named from the identity's local part, deduped); 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 and whose current home holds no login; or re-attachment of a profile to its own isolated home, which clears the profile's external home pointer. --only <names> narrows adoption to the named candidates (names are the first column of the proposal). On confirmation each candidate is bound as listed and wired, and the conversation migration is applied; --no-wire skips both. Adoption does not copy tokens; flk profile rm detaches an adopted home and leaves its directory and login. Owner: --owner, else inherited when exactly one owner is on record across your accounts, else prompted on a TTY; a non-TTY run that would create an account with no owner to inherit errors. --yes skips the confirmation for non-interactive runs
flk upgrade [--check]
download a platform binary, verify its checksum, write and execute a temporary candidate with --version, then replace the executable atomically. --check still downloads, writes and executes the candidate, but removes it without replacing the installed binary
flk install <path> [--repo checkout] [--target path] [--wait duration] [--force]
install a local Flock build. Stages a private copy, reads build metadata without executing the candidate, checks ancestry, backs up the existing binary and atomically replaces it. A known non-descendant is refused unless --force permits an intentional rollback; missing Git history or commit ancestry metadata emits an unverified-ancestry warning and does not block installation. A candidate whose Go build metadata cannot be read is refused. Compatible MCP processes using that executable re-exec after active requests finish, preserving their PID and stdio connection. The default eight-second adoption wait can report pending processes; pending is not success. Legacy servers need one reconnect to start reporting. Check flk ls and flk doctor for per-server provenance, drift and failures. Hot adoption executes the replacement at each MCP server's executable path without a new approval prompt, with that process's existing permissions. Protect write access to the installed file and its directory: another writer bypasses flk install's ancestry guard
flk account add <name> --provider <p> --owner <declared-owner> [--email <e>]
register a named account. Provider and owner are required; the optional email enables the identity consistency check
flk profile add <name> --agent claude|codex|gemini [--account n] [--owner o] [--model m]
create a profile: agent + account + isolated home. With --account omitted, an account named <name> is declared and printed
flk profile login <name> [--agent a] [--owner o] [--email e]
human-only TTY login into the profile's home; --email declares the address on the profile's account when the account has none. For claude, when claude auth login --help succeeds and no arguments follow --, the login is claude auth login, with --email <address> added when the account declares an address; otherwise Claude Code opens for /login. Checks the result (per claude auth status, else the state file) against the declared account (when the account declares an email and the home exposes a logged-in identity). Requires a TTY on both stdin and stdout and refuses when either is missing. With --agent, a missing profile is created first (account declared, home created, events wired). When no default profile exists, the created profile becomes the default
flk profile ls
list profiles with agent, account, and default marker
flk profile rm <name> --yes
delete the profile configuration and its isolated home directory, including that home's login state. An adopted external home and the wiring inside it remain on disk; detach does not mean unwire
flk profile set-home <name> <path> [--force]
point a profile at an existing external agent home (e.g. ~/.claude). Both arguments are required; a path of - or "" restores the isolated home. When the profile's account declares an address and the home's login (per claude auth status, else the state file) is a different address, the command refuses and names the profile whose account declares that address when one exists; --force binds it anyway
flk profile wire
configure provider lifecycle hooks and Flock MCP registration in profile homes. Provider-specific context, commands and statuslines differ. Codex wiring replaces notify; isolated Codex homes also auto-approve Flock MCP tools
flk use <profile> [--pin]
set the default profile, or pin via .flock.toml in the repo
flk whoami
machine-wide identity report. Flags a mismatch between a profile's declared account and its logged-in identity (when the account declares an email and the home exposes one)
flk capabilities
per profile: identity, model, MCP servers, wiring state
flk welcome
print each logged-in profile's capacity and the live session count
Commands shown here are an operator reference. Provider-specific settings and write scopes differ; inspect the installation guide before wiring.
Sessions & workers
flk new [--profile p] [--name n]
launch an agent session under a profile, as a tmux window (name <account>-main-<seq> by default)
flk ls
roster with current state. Rendered states: accepting working paused blocked(input). paused means the profile's worker capacity is determinately exhausted, the same test claude:auto uses to skip a worker. When a pane is gone, flk renders the retained record as resumable (transcript on file) or stale record. Hook statuses map onto these: idle and started render as accepting; needs-attention as blocked(input). The roster also shows reported MCP builds and flags stale or unverified provenance. MODEL is the model and effort the agent last reported (claude through its statusline input, codex through its rollout's turn_context), - until it reports
flk attach <name|lead>
jump to a session's pane. lead resolves to the current lead
flk model <session> [<model>] [--effort e] [--default]
model selection. With no model, prints what the agent last reported. With a model and/or --effort (low, medium, high, xhigh), drives the agent's own /model picker from the composer at a turn boundary, reading each picker screen and the agent's confirmation, and fails closed (Escape) on any step it cannot read. Claude: default, opus, fable, sonnet, haiku, applied to the session only unless --default (the picker's Enter, which saves the pick for new sessions); a model without an effort selector (Haiku) takes the model and ignores the effort. Codex: a model slug such as gpt-6-astra; codex writes the pick to its config.toml as well, so it becomes the profile's default. Neither agent's /model <name> argument form is used: on claude it saves a default
flk switch
picker popup
flk ui
dashboard
flk status [--tmux]
one-line summary
flk worker ensure <profile>
spawn or reuse an account's worker (<account>-worker-<seq>) in a detached tmux session. Profiles sharing an account share its worker seat. Fresh workers use the profile workspace or current directory. Reuse outside the existing workspace can require recycling; attached clients prevent that restart. Delegation itself selects a profile's live member, which may be a worker-role session, and can spawn a member if none exists. Gemini API-key mode does not attest a person's identity. Gemini auto_approve_tools defaults off; enabling it passes --approval-mode yolo to new sessions, bypassing tool prompts without adding a filesystem sandbox. With it off, a detached worker can wait for human approval. Claude worker creation requires spawnable credentials
flk adopt <tmux-target> [--name n] [--home dir] [--profile p]
register a pre-flock session into the roster. Identity is read from the agent's own state; status is liveness-only (no hooks)
flk restart <session> | flk restart --all
restart live Claude conversations in place only after verified idle or hookless quiescence. The conversation id must be known, the pane must be live, and the composer must be positively recognized as empty (an agent's dim placeholder or prompt suggestion counts as empty). The command enters /exit, verifies the composer changed, exits gracefully, and resumes the same conversation in the preserved pane. Recognition and graceful-exit failures fail closed
flk resume <profile> <conversation-id> [--name n] [--dir d]
start a recorded conversation as a managed tmux session under the profile: the agent's first-boot prompts for the directory are pre-answered, the session is registered on the roster, named --name or <account>-<first 8 characters of the conversation id>, in --dir or the current directory. Refused when the profile's home holds no transcript for the id (claude: projects/*/<id>.jsonl; codex: sessions/**/rollout-*-<id>.jsonl), when the home holds no spawnable login (claude credentials; codex auth.json), when a tmux session of that name exists, or when the conversation is already live in a roster session
flk migrate [--dry-run] [--allow-signal]
converge attested pre-Flock Claude processes into resumed managed sessions. --dry-run prints the plan without stopping or spawning and is the required first pass before a standalone flk migrate in the install runbook (discovery applies migration under its own consent). The current process is skipped for last restart. Tmux candidates require verified idle or quiescence and fail-closed empty-composer recognition before graceful exit. Plain-terminal candidates are skipped by default; --allow-signal additionally requires process-tree quiescence, 120 seconds of transcript quiescence, and no non-shell children before SIGTERM. A resume failure after stop records migrate-stranded with the old pid, exact resume command, and error
flk doctor [--prune] [--deep]
check environment, wiring, identity, task state and MCP provenance. The base command can repair Claude lifecycle hooks and inherited tmux flags and refresh quota state; it is not read-only. --deep probes live contracts and requires network access and access to the credential store. --prune removes proven-dead roster pins even when tasks reference them; otherwise unreferenced ended or aged unattested rows can be removed. --heal enables additional repair paths
A new session uses an account-based name unless explicitly named. Claude sessions can be renamed from transcript slugs. Delegation prefers a live non-desktop session named after the profile, otherwise the most recently updated eligible member. It excludes the caller; if that caller is the only live member, dispatch is refused. With no member it can spawn one, unless a session is awaiting rehome. Worker-role sessions participate in member selection. Leadership does not rename sessions.
Delegation & memory
The lead assignment is stored as a lease file, state/lead.json, recording holder, pane, pid, and the grant chain (rendered publicly as the lead history). 'Lease' in the rest of this reference names that file.
flk delegate --to <profile|<agent>:auto> "brief" [--wait] [--cross-owner] [--timeout d] [--isolation worktree] [--thread name] [--model m] [--effort e] [--keep-model]
dispatch a framed brief to a profile's live member. Selection prefers the profile-named session, otherwise the most recently updated eligible session, excluding the caller and desktop sessions. With no member it can spawn one; self-only and rehome-pending targets are refused. Dispatch checks login, event wiring, declared-owner boundaries and recorded capacity. A cross-owner task needs --cross-owner when both owners are known. Non-worker members wait for a recognized empty composer at a turn boundary; a busy member can leave the task accepted with parked_at for later idle-hook or explicit redispatch. Parking has no delivery deadline. Worker-role targets may have composer residue cleared once. Flock pastes a task-id wake-up; the worker obtains the framed brief from its hook or task-brief tool. Results must match the dispatch input; missing or mismatched results are not success. Codex collection checks rollout completion and can use a fresh notify fallback. --timeout defaults to 15 minutes for the result wait; boot, boundary and reconciliation phases have separate bounds, so it is not an end-to-end deadline. --wait=false uses a detached CLI child. --isolation worktree creates a separate checkout and records branch/base; merge and cleanup remain the sender's responsibility. A worker-role target rejects an explicitly assigned worktree outside its root; an implicit sender-directory default outside that root yields to the root. This routing check is not a filesystem sandbox. --thread groups task records. --model and --effort request a borrowed provider model; restoration is attempted unless --keep-model, with outcomes recorded on the task
flk task ls
the delegation ledger: list tasks
flk task status <id>
one task's record. A worker that hits blocking ambiguity ends its turn with a message beginning CLARIFY: (stating the exact ambiguity, why it decides the deliverable, the smallest question set, safe work done, and its declined-to-decide default), and the task settles as needs-clarification with the questions as its result
flk task result <id>
the task result and any recorded worktree metadata
flk task brief <id>
the framed brief a task's target session must receive, as the wake-up line points at it
flk msg send <session|lead> "text" / flk msg ls / flk msg read
turn-boundary fleet messages. A successful send stores the message in the target session's mailbox, a typed message event joins the events stream, and an automated worker or the persistent helper session (the attendant) gets a one-line notice pasted (queued input if it is mid-turn); A human-driven session with a live pane can receive a typed wake-up line at a verified turn boundary. Where hook delivery is available, the waker first allows three minutes for it to deliver the notice; the wake attempt gives up after 45 minutes. Paneless sessions rely on their configured notification surface. The line is submitted in that session's composer as its next turn; if the read-back finds other input beside it, it is left in the composer unsent, and a composer that already holds a draft refuses it. lead resolves through the lease at send time; with no valid lease the message waits in a pending-lead box the next holder claims on read. Use messages for coordination; task briefs go on the delegation ledger. doctor --prune clears read messages older than seven days; unread mail is never pruned
flk task clarify <id> "answers"
answer a needs-clarification task and redispatch it: the round is appended to the one task record (question, answer, timestamps, and a worktree snapshot when isolated), the full brief plus history replays to the same worker as the canonical authority, and the timeout restarts. Three rounds per task; past that, re-scope the brief
flk task review <id> --to <profile> ["focus"]
builder-to-reviewer on the ledger: dispatches a review of a completed --isolation worktree task, with the handoff package assembled from artifacts: the original brief, branch, base and HEAD pinned as commit SHAs, git diff --stat, and the builder's result verbatim. The reviewer works read-only in the builder's worktree (contractual; the worktree HEAD is checked after review and a move warns) and ends with one line, REVIEW: approve|revise — <sentence>, settled typed on the review task (approve, revise, or unknown when malformed — completion never fails on it). The review joins the builder's thread, minting t-<task-id> when it has none. Merge stays the sender's step, now with a verdict beside it
flk thread <name>
the thread's tasks in order — id, state, reviewer verdicts, first line of brief and result: the durable cross-task narrative that survives session recycles
flk brief [--note "text"]
show or append the project brief .flock/brief.md. Notes carry author and timestamp
flk recall <query>
search all profiles' transcripts; returns matches with resume commands
Lead protocol
The lead lease identifies the coordinating session. The operator policy assigns it dispatch, verification and reporting responsibilities; use Flock commands for session operations so outcomes are recorded.
flk lead grant <session>
designate the lead. Owner-run by policy; the CLI does not authenticate its caller. Claude and Codex sessions are eligible, subject to admission checks; Gemini sessions are refused. The lease records pane and pid and is verified against the live process. Claude leads are expected to run Fable; a Claude lead on another model gets a statusline warning
flk lead show
current lease, holder liveness, grant chain
flk lead recuse --successor <session|<agent>:auto> [--reason r]
recusal; the caller must hold the lease. Claude and Codex successors are eligible, subject to admission checks. <agent>:auto requires a live candidate with lead capacity, and returns an error otherwise
flk lead check
prints a retirement order when the lead's reading is determinate and any quota window is at or above 98%. On an indeterminate reading (unknown, stale, drift) it prints the reason and no order
flk lead enforce
check the recorded lease, upgrade legacy pins when verifiable, and allow a down holder's same identity to retake the lease. Quota-driven succession requires a live, determinately exhausted lead and an already-live successor with determinate lead capacity. Unknown capacity does not trigger quota succession
Quota
flk usage [--live]
consumption computed from transcripts; --live fetches authoritative quota instead
flk quota fetch [--quiet]
refresh per-profile quota records: Claude uses its credential file or macOS Keychain for the usage endpoint; Codex reads local rollout quota and refusal signals. Gemini has no numerical quota reader. Writes the cache, records capacity changes and runs lead enforcement
flk quota show [--json]
render quota as text or JSON. A cold cache can trigger an inline fetch and cache write; this command is not guaranteed to be read-only
flk quota install-agent
install and start the optional macOS quota watcher after operator consent. The persistent process runs at a 15-minute cadence, known reset deadlines and requested refreshes, using the FLOCK_HOME recorded in its plist
flk quota uninstall-agent
remove the macOS LaunchAgent
Worker capacity excludes model-scoped windows from the 98% refusal threshold; lead capacity includes them. Readings must be determinate. Unknown, stale, schema-drift and passed-reset states do not establish exhaustion and remain dispatch-eligible. Codex model buckets and observed provider refusals are reflected in the cached reading. Claude can read credentials from a file or the macOS Keychain; only the latter requires Keychain access.
Rules for agents using these tools
- The worker cannot see your session. A brief must carry the goal, all needed context, the deliverable format, and acceptance criteria. Include executable file paths and commands in the brief.
claude:autoreports the profile chosen; repeat that to the user.- Dispatch to a determinately exhausted profile is refused; do not work around the refusal. If any of your own windows reaches 98% while you hold the lead, recuse (see the runbook's capacity section). A worker whose only window at 98% is model-scoped may still accept work on other models.
- On task failure, report the state, error, and log path verbatim.
- Preserve a
flock_msg_senddeaf-mail warning. The mailbox write succeeds, but a target without a hook or statusline surface can wait silently; do not describe that warning as delivered coordination.
Hook & event contract
flk profile wire installs these. They call flk event … (hidden command; errors go to stderr with exit 0, so a hook failure never fails the agent).
Claude Code: every hook posts its stdin JSON to flk event claude:
| Claude hook | Roster state |
|---|---|
SessionStart | started |
UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, SubagentStart, SubagentStop | working (repeated status updates throttled to 3s) |
Notification | needs-attention |
Stop | idle |
SessionEnd | ended |
Payload fields used: hook_event_name, session_id, transcript_path, cwd, tool_name, message, prompt. Session resolution order: tmux pane → FLOCK_ID env → session_id. Unknown sessions register as external with deterministic id ext-<session_id[:8]>: one record per agent session. On UserPromptSubmit, prompt is recorded as the turn's input for dispatch integrity, and when it carries a delegation wake-up line the hook prints that task's framed brief to stdout, which Claude Code adds to the turn's context: this is how a delegated brief reaches a claude session.
The first Claude SessionStart or UserPromptSubmit event consumes a durable first-contact flag and writes one context notice into Claude's conversation. It names the roster identity and profile, states whether lifecycle surfaces are wired, and, when wired, says that native tools load after restart. It tells the agent to operate Flock on the user's behalf without exposing commands. Silent hook events never consume the flag. Codex receives its context through managed AGENTS.md and MCP; there is no codex hook context channel. A delegated brief reaches a codex session through flock_task_brief or flk task brief <id>, named in the wake-up line. The statusline input (model.id, model.display_name) is recorded on the session whenever it changes; it is what flk ls and model selection read for a claude session.
Codex: notify in the flock-owned config.toml calls flk event codex-notify <json>. Only agent-turn-complete is ingested; it sets idle and records the turn's final message and input for result collection, and the model and effort of the turn from the rollout's turn_context. Codex has no start or working hooks: boot is discovered from the profile home's session files, and death from pane liveness.
State on disk
Flock keeps state as local files under FLOCK_HOME (default ~/.flock). MCP servers and the optional macOS quota watcher can remain running. Requested operations may also write provider homes, project notes/pins/worktrees, the installed executable and installer backups.
~/.flock/
accounts.toml # named accounts: provider, owner, email
profiles/<name>/
profile.toml # agent, account, model, workspace, env
home/ # the agent's isolated home (CLAUDE_CONFIG_DIR / CODEX_HOME / GEMINI_CLI_HOME)
state/
sessions/<id>.json # roster records (atomic writes)
events.jsonl # append-only log: lifecycle, capacity-transition, succession, message
lead.json # the lease: holder, pane, pid, granted_by, chain
quota.json # quota cache (per profile, timestamped)
tasks/ # delegation ledger + per-task logs
messages/ # mailboxes, one box per session + lead-pendingSpawned sessions receive FLOCK_ID and FLOCK_PROFILE. The provider home variable is CLAUDE_CONFIG_DIR, CODEX_HOME or GEMINI_CLI_HOME; Flock omits CLAUDE_CONFIG_DIR for Claude's default home to preserve its native identity behavior. Profile environment settings can override defaults. TMUX_PANE is supplied by tmux.
Invariants
- Discovery attaches provider homes without importing credentials. Quota checks read stored credentials; isolated homes and task content can still contain secrets.
- MCP uses stdio. The checked Flock source contains no network listener; the optional macOS quota watcher is a persistent background process.
- Wiring preserves unrelated MCP entries and custom Claude statuslines, but claims the Codex notify setting. Isolated Codex homes auto-approve Flock MCP tools. Profile removal deletes an isolated home; an adopted external home is detached and retained.
- The lease records process identity and checks liveness. Account consistency can be checked when an account declares an email and the provider exposes an identity; API-key authentication mode alone does not identify an owner.