Running multiple agents-fleet instances on one machine
Operators frequently want to drive several repositories from a single host — one fleet per project — each with its own Telegram bot, its own inbox queue, its own intel database, and zero collisions between them.
As of Phase 1 of T-169 (feat/multi-instance-phase-1-fleet-home) this works via the existing FLEET_HOME environment variable. The Telegram and inbox runtime wiring now route through getHomeForLegacySubsystems() instead of bypassing FLEET_HOME and hardcoding os.homedir().
The contract
Set FLEET_HOME to an absolute path whose basename is exactly .fleet. This single constraint keeps the per-process state fully isolated.
# Project A
export FLEET_HOME="$HOME/project-a/.fleet"
export AGENTS_FLEET_TELEGRAM_TOKEN="<bot-a-token-from-BotFather>"
agents-fleet --telegram --inbox
# Project B (separate terminal, separate repo)
export FLEET_HOME="$HOME/project-b/.fleet"
export AGENTS_FLEET_TELEGRAM_TOKEN="<bot-b-token-from-BotFather>"
agents-fleet --telegram --inboxWhat this gives you, per instance:
| State | Path |
|---|---|
| Telegram pairings | $FLEET_HOME/telegram.json |
| Inbox file queue | $FLEET_HOME/inbox/ |
| Inbound attachments | $FLEET_HOME/attachments/<sessionId>/ |
| Intel SQLite DB | $FLEET_HOME/intel/fleet-intel.db |
| Sessions | $FLEET_HOME/sessions/ |
| Logs | $FLEET_HOME/logs/ |
| Plans / shadows | $FLEET_HOME/plans/, $FLEET_HOME/shadows/ |
Each Telegram bot must use its own token — talk to @BotFather and create a second bot for the second instance. The token is the trust boundary; reusing one token across two agents-fleet --telegram processes would cause both to compete for the same Telegram update stream.
Why the basename must be .fleet
The bot module (src/bot/) and inbox setup (src/cli/inboxSetup.ts) both compute their on-disk root as path.join(home, '.fleet', ...). The Phase 1 fix introduces a thin helper that returns path.dirname(FLEET_HOME) so that this join round-trips back to your configured FLEET_HOME — but only when the configured path ends in /.fleet.
If you set FLEET_HOME=$HOME/project-a/myfleet, the telegram + inbox subsystems will still write to $HOME/project-a/.fleet/..., which is probably not what you wanted. The other subsystems (intel DB, sessions, plans, logs) honor FLEET_HOME verbatim and would write to $HOME/project-a/myfleet/... — a split-brain layout that produces hard- to-debug inconsistencies.
A deeper refactor that renames the pervasive home: string convention inside src/bot/ to fleetHome: string (so any FLEET_HOME basename works) is tracked as Phase 1b of T-169.
Defense in depth: SQLite
Phase 1 also tightens the intel database for the multi-process case (src/intel/SchemaManager.ts):
journal_mode = WAL(already present) — concurrent readers + 1 writerbusy_timeout = 5000— wait 5 s for the lock instead of returningSQLITE_BUSYimmediatelysynchronous = NORMAL— recommended durability tier for WAL
Two agents-fleet instances pointed at the same intel DB will no longer error out; they will queue politely. (Pointing two instances at the same DB is not the intended use case — each instance should have its own FLEET_HOME — but the pragmas harden the path so an accidental collision degrades gracefully.)
Out of scope (Phase 2 / Phase 3)
- Surfacing the instance name in the Telegram message footer so a user who paired multiple bots can tell them apart from a single chat.
- An explicit
--instance <name>flag that infersFLEET_HOMEfrom a per-user catalog (~/.fleet/instances/<name>/...). - Cross-machine N-to-1 operator UX (multiple operators driving one fleet, multiple fleets driven by one operator).
These are tracked in follow-up tickets under T-169.