Skip to content

Chapter 5 · Runtime Layout: FM_HOME and Directory Conventions ​

Chapter goals: Master the FM_HOME mechanism and the responsibility division of the four private directories data/, state/, config/, projects/; understand the boundary between tracked shared materials and gitignored私有 materials; learn to safely run multiple firstmate instances.

5.1 One Instance, One Home: What Is FM_HOME ​

The FirstMate code repository itself is the "distro," but each running firstmate instance needs its own operational home to store私有状态. The FM_HOME environment variable is this home's address:

  • When unset: most scripts直接使用仓库根目录 as home;
  • When set: scripts still run from this repo's bin/, but state/, data/, config/, projects/ all读 from $FM_HOME.

This设计 lets "code" and "state"彻底分离: you can git pull to update the distro anytime without touching any instance's fleet records.

sh
# Unset: repo root is home
cd firstmate && claude

# Set: state all falls under ~/fm-homes/main; code stays原地
FM_HOME=~/fm-homes/main claude

Two配套 variables also exist: FM_ROOT_OVERRIDE replaces the firstmate repo根 used by scripts; FM_STATE_OVERRIDE, FM_DATA_OVERRIDE, FM_PROJECTS_OVERRIDE, FM_CONFIG_OVERRIDE can individually override one operational directory — mainly for testing and特殊 harness environments.

5.2 Responsibility Division of the Four Private Directories ​

configuration.md is the唯一权威定义 for the top-level layout. Four directories各有分工:

text
$FM_HOME/
├── data/       Persistent fleet archives: project & secondmate registries, captain preferences, learnings,
│               backlog, task briefs, scout reports
├── state/      Runtime records: task metadata, append-only state events, endpoint signals,
│               watcher & wake queue coordination, terminal-outcome receipts, away-mode state,
│               Relay-generated artifacts, secondmate pending-reply records etc.
├── config/     Local运营 choices (gitignored): backend selection, harness overrides etc.
└── projects/   Local project clones; firstmate read-only,
                changes only发生 via Hard Rule 1's guarded exceptions

Memory trick: layer by lifecycle. data/ is the long-retention "archive room"; state/ is the ever-changing "duty log"; config/ is your "操作偏好面板"; projects/ is the borrowed "project bookshelf."

Scout任务产出 falls under data — e.g., a recon report at data/<id>/report.md — which explains why scout tasks don't produce PRs yet remain追溯.

5.3 Tracked Shared Materials vs Gitignored Private Materials ​

AGENTS.md划 the repo content into两泾渭分明的 categories. Shared tracked materials are part of the distro,随 git commit and update:

text
AGENTS.md / README.md / CONTRIBUTING.md   Operations contract and docs
.tasks.toml                               Default backlog backend config
.github/workflows/                        Shared CI and PR enforcement
bin/                                      Helper script toolbelt
.agents/skills/                           firstmate internal skills
skills/                                   Standalone skills for public installers

While the following paths属于 captain-private gitignored materials, never entering version control:

text
.env          Optional Relay pairing token (LOCAL)
data/         Persistent fleet档案
state/        Runtime records
config/       Local运营选择
projects/     Local project clones
.no-mistakes/ no-mistakes pipeline local data

firstmate's write权限 differs for these two categories: it可以维护本仓库的私有运营状态; modifications to shared tracked materials must走 the repo's own no-mistakes pipeline and PR path — it obeys the same merge authority even toward itself.

5.4 fails-closed: fm-send.sh's Explicit FM_HOME Requirement ​

In多实例并存 scenarios, the biggest risk is "指令发错了家." To prevent this, bin/fm-send.sh is刻意 stricter than一般 scripts: it requires FM_HOME to be explicitly set before解析 targets; otherwise it fails closed — never silently falls back to the repo root. This guarantees a steer never quietly lands in the wrong home.

sh
# Correct: explicitly specify home before sending steer
FM_HOME=~/fm-homes/main bin/fm-send.sh <id> 'Please add regression tests'

# Wrong示范: FM_HOME unset; fm-send.sh refuses to execute rather than guess
bin/fm-send.sh <id> 'hello'    # fails closed

Another safety detail: fm-brief.sh, fm-spawn.sh, fm-afk-launch.sh resolve relative-form FM_HOME and override dirs to absolute paths before persisting or passing to other processes; unresolvable relative dirs are rejected with报错 naming which variable failed.

5.5 Practice: Building and Verifying an Independent Home ​

Below are the最小步骤 to create an运营之家脱离 the repo root and confirm the directory skeleton:

sh
# 1. Create home directory (子directories生成 on first launch)
mkdir -p ~/fm-homes/main

# 2. Launch primary harness from the firstmate repo root, pointing at that home
cd /path/to/firstmate
FM_HOME=~/fm-homes/main claude

# 3. After让 firstmate执行 a small task, check what appeared in the home
ls ~/fm-homes/main
# data/  state/  config/  projects/

If you need multiple并行 instances (e.g., one personal project, one work project),给各自独立的 FM_HOME:

sh
FM_HOME=~/fm-homes/personal claude   # Terminal A
FM_HOME=~/fm-homes/work claude       # Terminal B

Note: each secondmate also拥有自己持久隔离的 FM_HOME (with独立 state, backlog, projects, and session lock) — this is the物理基础 for the Secondmate mechanism in Chapter 14.

5.6 Chapter Summary ​

  • FM_HOME selects一个 firstmate instance's operational home; when unset, repo root is used; when set, state/data/config/projects all come from $FM_HOME;
  • Four directories layered by lifecycle: data/ persistent档案, state/ runtime记录, config/ local偏好, projects/ read-only project clones;
  • Shared tracked materials随发行版走 git; .env/data/state/config/projects/.no-mistakes/ are captain-private gitignored materials;
  • bin/fm-send.sh requires explicit FM_HOME or fails closed —杜绝 steer落到错误 home; relative paths must resolve to absolute before persisting;
  • Multi-instance = multiple独立 FM_HOME; secondmates同样以独立 home实现隔离.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. When FM_HOME is explicitly set, how do scripts run?

2. Which of the following belongs to data/ rather than state/?

3. Why does bin/fm-send.sh require explicit FM_HOME?

4. Which组全部属于 captain-private gitignored materials?

🛠️ Hands-On Exercises ​

  1. Launch firstmate once with FM_HOME unset and once with FM_HOME=~/fm-homes/lab; dispatch a small task in each;对比 the出现位置 of data/ and state/;画 your machine's actual directory tree.
  2. 故意 call bin/fm-send.sh <id> 'ping' in a shell without FM_HOME; observe the failure behavior; then set FM_HOME and retry;验证 the "fails closed" semantics.
  3. Create independent homes for "personal" and "work" scenarios; dispatch不同项目 tasks to each; then ls the two homes' projects/ to confirm克隆彼此隔离.

Layout understood. Next, session backends: tmux and experimental alternatives.