@continuous-agentics/fleetmind
v1.2.1
Published
Deploy and manage OpenClaw multi-agent fleets
Maintainers
Readme
FleetMind
Deploy and operate fleets of OpenClaw agents.
FleetMind turns one fleet.yaml into multiple AI agents: each with its own
OpenClaw gateway, workspace, Slack identity, persona, skills, secrets, and
runtime target. Agents can run locally on one machine or as isolated EC2 hosts
that coordinate through Slack threads, shared context, and an optional durable
task ledger.
Built with TypeScript. The FleetMind CLI requires Node.js 20+; local fleets also install OpenClaw, which currently requires Node.js 24 or Node.js 22.19+.
What FleetMind Does
- Scaffold fleet configs with
fleetmind initand validate them withfleetmind render --check. - Render per-agent workspaces from one declarative
fleet.yaml. - Bring up local fleets with
fleetmind upfor single-machine development. - Provision AWS fleets with FleetMind’s embedded Terraform root at
infra/terraform, or through a compatiblefleetmind-templaterelease. - Push updates to deployed agents with signed manifests, S3 staging, SSM Run Command, and
pull-self. - Manage fleet secrets across local env files and AWS Secrets Manager.
- Generate Slack and GitHub App setup for one identity per agent.
- Coordinate PM-to-worker delegation through a DynamoDB/S3 task ledger and NATS wake events.
Install
npm install -g @continuous-agentics/fleetmindFor local fleets, install OpenClaw too:
npm install -g @continuous-agentics/fleetmind openclawOpenClaw currently requires Node.js 24, or Node.js 22.19+.
Quick Start
Local Fleet
Use this path to run multiple agents on one machine without AWS or Terraform.
fleetmind init
# edit fleet.yaml: add a local target under targets: and point agents at it
fleetmind secrets set CONDUCTOR_BOT_TOKEN xoxb-...
fleetmind upfleetmind up renders ~/.openclaw/openclaw.json, writes resolved secrets to
~/.openclaw/.env with 0600 permissions, provisions each agent workspace,
and delegates daemon setup to openclaw onboard --install-daemon.
AWS Fleet
Use this path when each agent should run on its own EC2 host.
gh repo create my-fleet --template Continuous-Agentics/fleetmind-template --private
cd my-fleet
fleetmind onboardThe template repo owns the Terraform root, workspace tfvars, and operator docs. FleetMind renders the derived tfvars and per-agent workspaces; the Terraform module provisions EC2, IAM, SSM, Secrets Manager, S3, DynamoDB, and optional NATS infrastructure.
AWS workspaces always live at /home/openclaw/.openclaw/workspace — the
fixed, non-configurable standard OpenClaw HOME layout (/home/openclaw is both
the OS account home and the gateway's own HOME, with
.openclaw/openclaw.json alongside the workspace). Each runtime host runs one
agent, so there is no per-agent workspace suffix. There is no workspace_base
setting — every target uses this contract. The runtime gateway and its companion services use
user-systemd under the openclaw account; FleetMind's SSM deploy, rollback,
diagnostics, and dashboard commands set the required XDG/DBus session
environment automatically. For a compatible legacy host, set
targets.<id>.aws.runtime_user: ec2-user explicitly.
An SSM operator should enter the configured runtime account with
sudo -iu openclaw (substitute the runtime-user override when set), then run
ocalias. The module-provided shortcuts include ocstatus, oclog, and
octail for the gateway plus ocnatsstatus, ocnatslog, and ocnatstail for
its NATS subscriber. These are included in FleetMind v1.1.0 and later when the embedded Terraform module uses the matching release tag.
Architecture
One EC2 instance per agent. One OpenClaw gateway per EC2. fleetmind renders per-agent workspaces from fleet.yaml and pushes each to its respective host. Agents coordinate over Slack threads, the optional delegation task ledger, and a shared DynamoDB ContextStore — never via shared process state.
┌──────────────────────────────────────────┐
│ FleetMind (CLI on operator laptop / CI) │
│ fleet.yaml → per-agent workspaces │
│ workspace push, skill lifecycle, ledger │
└────────────────────┬─────────────────────┘
│ render + push workspaces/skills
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ EC2: A │ │ EC2: B │ │ EC2: C │
│ Gateway A │ │ Gateway B │ │ Gateway C │
│ Conductor 🎼 │ │ Pixel 🎨 │ │ Forge ⚙️ │
│ workspace + │ │ workspace + │ │ workspace + │
│ Slack app │ │ Slack app │ │ Slack app │
└───────┬────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
└───────────────────┼───────────────────┘
▼
Slack threads • ContextStore (DDB) • task ledger
• openclaw-terraform (infra) •Each agent is a fully isolated OpenClaw agent: its own EC2, its own gateway, its own workspace, its own Slack app, its own session memory, its own skill catalog. Coordination happens only over external surfaces — primarily Slack threads (each agent posts under its own bot identity) and, when enabled, the delegation task ledger. There is no shared process state, no co-tenancy, no per-fleet super-process.
Fleet-wide shared key/value state is available via the ContextStore — a DynamoDB-backed hive mind. Any agent or external service with IAM access to the table can read or write fleet context.
Why one EC2 per agent?
Isolation over efficiency. A misbehaving worker can't crash the orchestrator; a runaway skill on one bot doesn't starve another; each agent can be redeployed, restarted, or rolled back independently. The cost is more EC2 instances per fleet — deemed acceptable for the durability and blast-radius properties.
Bot EC2 hosts are provisioned from the embedded Terraform root at infra/terraform. Its module "fleetmind" wrapper calls infra/terraform/modules/fleetmind, preserving existing Terraform resource addresses. Operators configure the root’s backend.hcl and workspace tfvars; fleetmind render writes workspaces/<fleet>.derived.tfvars. See docs/terraform/README.md and docs/terraform/MIGRATIONS.md before moving an existing fleet state.
Documentation Map
FleetMind’s runtime and Terraform implementation live in this repository:
fleetmind— CLI, renderer, runtime helpers, bundled OpenClaw templates, and delegation protocolinfra/terraform— operator Terraform root and workspace tfvarsinfra/terraform/modules/fleetmind— embedded AWS infrastructure modulefleetmind-template— optional external operator scaffold; it follows FleetMind release tags
| Looking for... | Start here |
|---|---|
| Bring-up walkthrough | fleetmind-template/docs/QUICKSTART.md |
| Comprehensive fleet setup | fleetmind-template/docs/SETUP-A-FLEET.md |
| Day-to-day operations | fleetmind-template/docs/OPERATING.md |
| Troubleshooting | fleetmind-template/docs/TROUBLESHOOTING.md |
| GitHub Apps per agent | fleetmind-template/docs/GITHUB-APPS.md |
| Compatibility matrix | docs/COMPATIBILITY.md |
| Delegation protocol | docs/protocol.md |
| Enable PM-to-worker delegation | docs/integration/delegation.md |
| Customer AWS access handoff | docs/CUSTOMER-ONBOARDING.md |
| Terraform module docs | docs/terraform/ |
Compatibility
FleetMind’s CLI and Terraform module ship from this repository under the same release tag. Fleet consumers must pin both the npm package and the Terraform module source to that exact tag; fleetmind-template is an optional scaffold that follows FleetMind tags.
| FleetMind tag | Terraform source | Notes |
|---|---|---|
| v1.1.0 | github.com/Continuous-Agentics/fleetmind//infra/terraform/modules/fleetmind?ref=v1.1.0 | Explicit per-agent GitHub App declarations, namespaced credentials, and least-privilege IAM |
Do not mix a FleetMind npm version with a different Terraform module tag or an untagged branch.
See docs/COMPATIBILITY.md for the full contract and upgrade notes.
fleet.yaml Overview
fleet:
name: acme-fleet
client: Acme Corp
skills_repo:
url: https://github.com/your-org/skills-repo
poll_interval: 60s
context:
provider: dynamodb # dynamodb | local (in-memory dev fallback)
region: us-west-2 # required (no silent default since 0.3.0)
ttl_days: 30 # optional default TTL for context entries
agents:
defaults:
model: anthropic/claude-sonnet-4-6
list:
- id: conductor
name: Conductor
emoji: 🎼
role: pm
orchestrator: true
slack:
account_id: conductor # required: Slack account binding key
bot_token: ${CONDUCTOR_BOT_TOKEN}
app_token: ${CONDUCTOR_APP_TOKEN}
channels: ["C…home", "C…delegation"] # PM home + delegation channel
agent_to_agent:
can_send_to: [pixel, forge]
- id: pixel
name: Pixel
emoji: 🎨
role: frontend-worker
skills:
- name: coding
source: client
- name: github
source: client
version: "2.1.0" # pinned
slack:
account_id: pixel
bot_token: ${PIXEL_BOT_TOKEN}
app_token: ${PIXEL_APP_TOKEN}
channels: ["C…delegation"]See fleet.example.yaml for the full annotated schema.
CLI Reference
Workspace + deploy
| Command | Description |
|---|---|
| fleetmind init | Scaffold a new fleet.yaml |
| fleetmind up [fleet] [--no-daemon] [--dry-run] | Local: render → ~/.openclaw, secrets → ~/.openclaw/.env, start the OpenClaw gateway (one gateway hosts all agents on a local target) |
| fleetmind render [fleet] | Render openclaw.json + tfvars locally to ./rendered/ |
| fleetmind deploy [fleet] | Render workspaces locally (./rendered/) — does not push to EC2 |
| fleetmind push fleet [--agent <id>] [--restart] | AWS: render → upload to S3 → trigger pull-self on each bot (main deploy command) |
| fleetmind pull-self [--apply] [--restart] | Bot-side: pull latest workspace from S3 and apply (runs on EC2) |
| fleetmind diff [fleet] | Show what deploy would change without applying |
| fleetmind watch [fleet] | GitOps: auto-push skill updates from the skills repo |
| fleetmind status [fleet] | Show fleet configuration and workspace status |
| fleetmind self-upgrade [--latest\|--version <v>] [--apply] | Upgrade the fleetmind CLI in-place on a bot EC2 (run as root) |
Skills + plugins
| Command | Description |
|---|---|
| fleetmind push skill <name> --agent <id> | Push a skill to a specific agent |
| fleetmind push skill <name> --all | Push a skill to all agents |
| fleetmind push plugin <name> --all | Push a plugin fleet-wide |
Agents + secrets
| Command | Description |
|---|---|
| fleetmind agent list | List all agents |
| fleetmind agent info <id> | Show agent details |
| fleetmind secrets set KEY value | Store a secret locally (resolved in ${VAR} fleet.yaml refs) |
| fleetmind secrets list | List stored secret keys |
| fleetmind secrets export | Export secrets as shell exports |
| fleetmind secrets populate [--interactive] | Push Slack + per-provider API keys into AWS Secrets Manager (one secret per (agent, provider) pair under <fleet>/agents/<id>/providers/<provider>) |
| fleetmind secrets check | Verify every expected (agent, provider) secret exists in AWS Secrets Manager without mutating anything |
Slack
| Command | Description |
|---|---|
| fleetmind slack manifests [--out <dir>] | Generate per-agent Slack app manifest YAMLs from fleet.yaml |
| fleetmind slack discover | Resolve each agent's bot_user_id via auth.test and write back to fleet.yaml |
GitHub Apps
| Command | Description |
|---|---|
| fleetmind github-app status | Report declared App credential status without reading values |
| fleetmind github-app setup --fleet acme --agent worker --app project | Create/install a deliberately selected declared App |
| fleetmind github-app import --fleet acme --agent worker --app project | Import PEM credentials into SSM; store is deprecated |
GitHub Apps are declared explicitly under each agent's github_apps map:
github_apps:
project: {}
customer-app:
owner: acme
org: trueUse project: {} for the existing project namespace. Named Apps take their owner and account type from the declaration; github_app configures permission and event defaults only. Terraform receives names only to derive IAM—never PEMs, App IDs, or installation IDs.
Shared ContextStore
| Command | Description |
|---|---|
| fleetmind context get <key> | Read a value from the shared DynamoDB ContextStore |
| fleetmind context set <key> <value> | Write a value to the ContextStore |
| fleetmind context delete <key> | Delete a key |
| fleetmind context list [prefix] | List keys, optionally filtered by prefix |
Task ledger (delegation)
| Command | Description |
|---|---|
| fleetmind task create | Create a task record (PM bot: initial delegation) |
| fleetmind task ack | Acknowledge a delegation (worker: delegated→accepted) |
| fleetmind task ship | Mark a task shipped (worker: accepted→shipped) |
| fleetmind task block | Mark a task blocked |
| fleetmind task unblock | Unblock a task (blocked→accepted) |
| fleetmind task signoff | Sign off on shipped work (shipped→signed_off) |
| fleetmind task merge | Mark a task merged (shipped\|signed_off→merged) |
| fleetmind task abandon | Abandon a task (any non-terminal status → abandoned) |
| fleetmind task get | Fetch a task record by ID |
| fleetmind task update | Update mutable task metadata (title, DoD, worker, thread) |
| fleetmind task set-nag | Record last nag timestamp (used by PM heartbeat sweeps) |
| fleetmind narrative <get\|put> | Read/write the S3-backed task narrative .md |
| fleetmind query <pending\|shipped\|merged\|stale\|all> | Query the task ledger by status/project |
Shared ContextStore (Hive Mind)
All agents in a fleet share a DynamoDB-backed ContextStore. Keys are namespaced as {fleetName}/{scope}/{key}:
# Write shared context (any agent or external service can read this)
fleetmind context set acme-fleet/shared/last-deploy "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Read it back
fleetmind context get acme-fleet/shared/last-deploy
# List everything under a prefix
fleetmind context list acme-fleet/conductor/In local/dev mode (provider: local), the store is in-memory only — data won't survive restarts. A warning is printed so you know you're not hitting real DynamoDB.
The DynamoDB table ARN is exported as a Terraform output (context_store_table_arn) so external services can be granted IAM access without hardcoding table names.
Delegation (PM bot → worker bot)
FleetMind provides a durable task ledger for orchestrator-to-specialist delegation. When delegation.enabled: true is set in fleet.yaml, the PM bot can record delegations to a DynamoDB-backed task table and workers can ack/ship/block against it. Narratives are written to S3; terminal delivery uses the fleet’s NATS subscriber path rather than an ad-hoc remote-command wake pipeline.
# fleet.yaml — minimal delegation config
delegation:
enabled: true
aws_region: us-west-2
table_name: acme-fleet-tasks
s3_bucket: acme-fleet-ledgerPer-agent: PM bots already use orchestrator: true; add delegation.worker_bots: [...]
to list the worker IDs they can delegate to. Worker agents add
delegation.specialty: <label> for routing. Wake-pipeline targeting (SSM
session key, EC2 tag) is configured at the Terraform layer.
The substrate is provisioned by the embedded task-ledger submodule and activates automatically when delegation_enabled = true in your fleet's tfvars. Add the bot-delegation skill to the PM bot and the bot-reception skill to each worker (both ship in openclaw/skills/). Full walkthrough: docs/integration/delegation.md. Protocol details: docs/protocol.md.
Skills Repo (GitOps)
FleetMind watches a versioned skills repo and automatically pushes updates to each agent's EC2:
your-skills-repo/
versions.json ← {"coding": "1.2.0", "github": "2.1.0"}
coding/
SKILL.md
package.json ← {"name": "coding", "version": "1.2.0"}
github/
SKILL.md
package.json# Start the watcher (runs until Ctrl+C)
fleetmind watch
# Or push a specific skill manually
fleetmind push skill coding --agent forge
fleetmind push skill github --all --version 2.1.0Unpinned skills (- name: coding) auto-update. Pinned skills (version: "2.1.0") are skipped unless --force.
Terraform Integration
The Terraform module ships in this repository at infra/terraform/modules/fleetmind. Operators consume it using the same FleetMind tag as their runtime package, for example github.com/Continuous-Agentics/fleetmind//infra/terraform/modules/fleetmind?ref=v1.1.0. fleetmind render writes derived tfvars (fleet_name, agent_names, agent_orchestrators, agent_providers, agent_github_apps) into workspaces/<fleet>.derived.tfvars; the operator passes that file plus their hand-edited <fleet>.tfvars to terraform apply -var-file=....
CI
GitHub Actions runs on every push to main and every pull request:
| Job | What it does |
|-----|--------------|
| build-and-test | npm ci → npm run build (tsc) → npm test (320+ tests) → npm pack --dry-run (verifies published tarball contains dist/, README.md, LICENSE, and the public docs/*.md set; rejects src/, test/, internal docs/{audits,design,test}/, and unexpected docs/integration/ files) |
| shellcheck | Runs ShellCheck on all infra/scripts/*.sh standalone scripts |
Releases are gated through GitHub Releases. Pushing a v* tag as ggettert creates a draft GitHub Release; publishing that release as ggettert runs publish.yml, builds/tests the package, and publishes to public npm with provenance through trusted publishing. The same workflow can be manually dispatched for an existing tag. See RELEASING.md for publish instructions.
Requirements
- Node.js 20+ for FleetMind; Node.js 24 or 22.19+ for local OpenClaw fleets
- AWS credentials (for DynamoDB ContextStore + delegation in production)
- OpenClaw installed on each agent's target EC2 host
License
MIT. See LICENSE.
