foreman-bot
v1.10.0
Published
A durable multi-agent workflow runtime. Author pipelines in FlowSpec, run them on Temporal with per-step OTel, and coordinate Claude/Gemini/GPT agents — with Slack or Mattermost as your human-in-the-loop surface.
Downloads
5,583
Readme
Foreman
A durable multi-agent workflow runtime. Author pipelines in FlowSpec, run them on Temporal with per-step OTel, and coordinate Claude/Gemini/GPT agents — with Slack or Mattermost as your human-in-the-loop surface.
New here? See ONBOARDING.md for a step-by-step setup guide, command reference, and common gotchas.
Prerequisites
- Docker Desktop
- Node.js 18+
- An Anthropic API key (required)
- Google Gemini and/or OpenAI API keys (optional — channels show setup instructions if missing)
Two Ways to Install
Foreman has exactly two install modes. Pick the one that matches what you want to do.
| Mode | Who it's for | How you run Foreman |
|---|---|---|
| Foreman Dev | You want to read and modify Foreman's source code, build locally, and push commits back. | Clone the repo, build from source, run from the checkout. |
| Foreman User | You want to use Foreman (Claude/GPT/Gemini bots + FlowSpec) without touching its source. | Install the published npm package globally, foreman init in a fresh directory. |
Both modes produce the same running system. The only difference is whether Foreman runs from your local git checkout (Dev) or from the published foreman-bot package (User).
Foreman Dev — Install
Clone the repo and build from source. You run Foreman directly from the checkout — the checkout IS your instance directory. Code and runtime state live in one tree.
# 1. Clone and build
git clone https://github.com/myfitnesspal/foreman.git ~/foreman-dev
cd ~/foreman-dev
npm install
npm run build
# 2. Set your API keys (init reads these from the environment)
export ANTHROPIC_API_KEY=sk-ant-...
export GEMINI_API_KEY=AIza... # optional
export OPENAI_API_KEY=sk-... # optional
# 3. First-time setup (starts Docker, creates Mattermost, writes .env)
node dist/index.js init
# 4. Start Foreman
node dist/index.jsRe-run npm run build after editing source. Re-run node dist/index.js (or launchctl kickstart, see below) to restart with the new build.
Why the explicit longhand?
The commands above use node dist/index.js rather than a shell alias or npm link. Reason: you always know exactly which build is running. If you also have a globally-installed foreman-bot, a generic foreman command is ambiguous. Seeing dist/index.js also reinforces the build/run cycle — it's obvious that npm run build (which runs tsc) is what picks up your changes. Shell history (↑) makes the length a non-issue.
Runtime state lives inside the checkout
Because the checkout is the instance directory, runtime artifacts land inside the repo tree:
~/foreman-dev/
.env your secrets (gitignored)
state/ sessions, canvases, roster overrides (gitignored)
logs/ launchd stdout/stderr (gitignored)
config/channel-registry.yaml channel IDs written by bootstrap (machine-specific)git status will show runtime changes to config/channel-registry.yaml. Don't commit your personal channel IDs. The .gitignore already covers .env, state/, and logs/.
Foreman User — Install
The fastest path is npx — no global install, always runs the latest published version:
# 1. Create an instance directory and cd into it
mkdir ~/my-foreman
cd ~/my-foreman
# 2. Set your API keys (init reads these from the environment)
export ANTHROPIC_API_KEY=sk-ant-...
export GEMINI_API_KEY=AIza... # optional
export OPENAI_API_KEY=sk-... # optional
# 3. Run the setup wizard (downloads foreman-bot on first run, then runs it)
npx foreman-bot@latest init
# 4. Start Foreman
npx foreman-bot@latestPrefer a global install? Use this instead:
npm install -g foreman-bot
mkdir ~/my-foreman && cd ~/my-foreman
export ANTHROPIC_API_KEY=sk-ant-...
foreman init
foremanforeman init starts Docker, creates the Mattermost instance with all channels and bot accounts, writes your .env file, and populates config/channel-registry.yaml. Takes about 1–2 minutes.
Open http://localhost:8065 and log in with foreman-admin / F0r3man! (set FOREMAN_ADMIN_PASSWORD before running init to override).
Instance directory
The directory you ran foreman init in (here ~/my-foreman) becomes your instance directory. It holds your .env, runtime state/, logs/, and user-editable content (flows/, docs/, workspaces/). Foreman identifies an instance by the presence of bots.yaml at the directory root; running foreman anywhere else fails with a clear error.
You can have multiple instance directories — each is a fully independent deployment. Only one can run at a time because host ports are shared (8065 Mattermost, 19092 Kafka, 7233 Temporal, 3001 Foreman).
What You Get
Setup creates a fully configured Mattermost instance with 20+ channels, organized into sidebar categories:
| Category | Channels | What they do |
|---|---|---|
| SYSTEM | #Architect, #FlowSpec Engineer, #Foreman Onboarding | Operate and extend Foreman |
| General | #thought-pad, #alice, #bob, #charlie | Everyday AI chat, brainstorming |
| Models | #claude, #gemini, #gpt | Raw model access — one channel per provider |
| FlowSpec Tutorial | #flowbot-01/02/03 | Learn multi-bot workflows |
| TECHOPS-2187 | #claude-worker, #gemini-worker, #gpt-worker, #claude-judge | Real-world workflow example |
| Pythia | #pythia-* | Multi-model research pipeline |
Every channel is an independent AI session. Each has its own model, conversation history, and persona. Type a message and the bot responds.
Commands
Use /f in any channel to control sessions:
| Command | Description |
|---|---|
| /f model <name> | Switch model (opus, sonnet, haiku, or vendor:model like gemini:gemini-2.5-flash) |
| /f session | Show current session info |
| /f new | Reset the session (fresh conversation) |
| /f auto-approve on\|off | Toggle tool approval prompts |
| /f stop | Abort a running query |
| /f run <file.flow> | Run a FlowSpec process |
Tool Approvals
When a bot wants to edit a file or run a shell command, Foreman posts an Approve / Deny button in the channel. Read-only tools (file reads, searches, web fetches) are auto-approved. You can skip all prompts with /f auto-approve on — this is enabled by default for all out-of-the-box bots.
FlowSpec Processes
FlowSpec is a plain-text language for orchestrating multi-bot processes. Bots work in sequence or parallel, with results flowing between them.
process "Quick Review"
ask @alice "Summarize the key risks in this PR"
ask @bob "What would you change about this approach?"
at the same time
ask @alice "Draft a response addressing Bob's feedback"
ask @bob "Rate Alice's summary on a scale of 1-10"
done
endRun it: /f run flows/my-process.flow
See flows/examples/flowspec-tutorial.flow for a hands-on walkthrough with 7 progressive lessons.
Architecture
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Mattermost │────▶│ Foreman │────▶│ Claude / GPT │
│ (Chat UI) │◀────│ (Node.js) │◀────│ / Gemini │
└──────────────┘ └──────┬───────┘ └──────────────┘
│
┌──────┴───────┐
│ Redpanda │ Bot-to-bot messaging
│ (Kafka) │ for FlowSpec processes
└──────┬───────┘
│
┌──────┴───────┐
│ Temporal │ Durable workflow execution
│ │ (retries, state, history)
└──────────────┘All infrastructure runs in Docker via docker compose. Foreman itself runs natively on Node.js.
| Service | URL | Purpose | |---|---|---| | Mattermost | localhost:8065 | Chat with bots | | Redpanda Console | localhost:8080 | Inspect bot message traffic | | Temporal UI | localhost:8233 | Monitor workflow executions |
Adding API Keys Later
If you skipped Gemini or OpenAI during setup, add them anytime by editing the instance .env file:
# Edit <instance>/.env
GEMINI_API_KEY=AIza...
OPENAI_API_KEY=sk-...Restart Foreman after adding keys. Channels that showed "API key not configured" will start working.
Slack (Optional)
Foreman can also connect to Slack in parallel with Mattermost. Add these to the instance .env:
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...See slack-manifest.json for the Slack app manifest. The /f slash command works in both Slack and Mattermost.
Google Workspace (Optional)
Foreman bots can read and write Google Docs, Sheets, Slides, Drive, Gmail, and Calendar through the workspace-mcp integration.
Setup:
- Install
uv(Python package manager):brew install uv - Create a Google Cloud OAuth app with the required scopes (see workspace-mcp docs)
- Download your
client_secret.jsonand run:uvx workspace-mcp --single-userto complete OAuth - Add your credentials to the instance
.envfile:
GOOGLE_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-...Restart Foreman. Claude bots will automatically have access to all Google Workspace tools. OpenAI and Gemini bots do not yet support Google Workspace tools (Phase 2 roadmap).
Running as a Service
Two supported supervisors: macOS launchd (native) and Docker Compose (containerized). Pick one per instance — they coexist on the same machine but only one supervises a given instance at a time.
Option A — macOS launchd (native)
init offers to create a per-instance launchd plist labeled com.foreman.bot.<instance-name> — this lets multiple instances coexist (though only one can run at a time).
The plist is tailored to your install mode — Foreman Dev uses the explicit longhand node <checkout>/dist/index.js; Foreman User uses the global foreman binary.
# Load the plist (first time)
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.foreman.bot.<instance>.plist
# Restart the service (picks up new build — Foreman Dev: run `npm run build` first)
launchctl kickstart -k gui/$(id -u)/com.foreman.bot.<instance>
# Stop and unload
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.foreman.bot.<instance>.plistLogs: <instance>/logs/foreman.out.log and <instance>/logs/foreman.err.log
Option B — Docker Compose (containerized)
foreman init scaffolds a docker-compose.yml in the instance directory alongside bots.yaml and .env. The compose file has two profiles: bare docker compose up -d brings up only the dependency services (Postgres, Redpanda, Mattermost, Temporal); --profile foreman also runs Foreman itself as a container.
cd ~/my-foreman # the instance directory
docker compose --profile foreman up -d # full stack including Foreman
docker compose logs -f foreman # tail Foreman's stdout/stderr
docker compose --profile foreman down # stop everythingMechanics:
- The repo's instance directory is bind-mounted into the container at
/instance, sostate/,logs/,bots.yaml,.env,workspaces/, andflows/all live on the host. Edits tobots.yamlapply on next restart. restart: unless-stoppedplays the supervisor role.SelfRebootandprocess.exit(0)trigger a clean restart automatically.- Logs go to
docker logsinstead of files (no<instance>/logs/foreman.out.login this mode). - Multi-instance still works the same way — one Foreman container per instance directory, host ports collide so only one runs at a time.
The container image is built locally from the included Dockerfile on first up -d. No image registry is required.
The .env File
All configuration lives in the instance .env file, loaded by dotenv at startup. Externally-set environment variables take precedence. There is no global config file; each instance is fully self-contained.
.env is per-installation identity — the things that make this particular Foreman deployment yours, on your machine. It holds three kinds of values:
- Secrets — API keys, tokens, passwords. Never commit.
- Per-user configuration — account emails, project keys, default working directory.
- Per-instance defaults — build scheme, simulator UDID, bundle ID for iOS convenience commands.
If a value would be different for a different user or on a different machine, it belongs in .env. If it's the same for everyone, it belongs in code or in versioned content (bots.yaml, flows/).
| Env var | Description |
|---|---|
| ANTHROPIC_API_KEY | Anthropic API key (required for Claude bots) |
| GEMINI_API_KEY | Google Gemini API key (optional) |
| OPENAI_API_KEY | OpenAI API key (optional) |
| MATTERMOST_URL | Mattermost server URL (default: http://localhost:8065) |
| MM_FOREMAN_TOKEN | Mattermost bot personal access token (written by bootstrap) |
| MM_ADMIN_TOKEN | Mattermost admin personal access token (written by bootstrap) |
| FOREMAN_ADMIN_PASSWORD | Admin password used during foreman init (default: F0r3man!) |
| DEFAULT_CWD | Default working directory for bot sessions |
| SLACK_BOT_TOKEN | Slack bot token (optional, for Slack bridge) |
| SLACK_APP_TOKEN | Slack app token (optional, for Slack bridge) |
| JIRA_HOST / JIRA_EMAIL / JIRA_API_TOKEN / JIRA_PROJECT_KEY | Legacy direct-API path for Jira only. Prefer the Atlassian MCP flow (see ONBOARDING → Enable Atlassian) — one OAuth step covers both Jira and Confluence, no .env keys needed. |
| BITRISE_TOKEN | Bitrise personal access token (optional) |
| BITRISE_APP_SLUG | Bitrise app slug from your app's URL (optional) |
| BUILD_WORKSPACE | Path to .xcworkspace for /f build (optional) |
| BUILD_SCHEME | Xcode scheme name for /f build (optional) |
| BUILD_SIMULATOR_UDID | iOS simulator UDID for /f build (optional) |
| BUILD_BUNDLE_ID | App bundle ID for /f launch-ios (optional) |
| GOOGLE_OAUTH_CLIENT_ID | Google OAuth client ID for Workspace MCP (optional) |
| GOOGLE_OAUTH_CLIENT_SECRET | Google OAuth client secret for Workspace MCP (optional) |
Project Structure
src/ TypeScript source
index.ts Entry point — starts all transports
mattermost.ts Mattermost WebSocket bridge
slack.ts Slack Socket Mode bridge (optional)
mcp-toolbelt.ts In-process MCP server exposing all bot tools
adapters/ Claude, Gemini, OpenAI agent adapters
temporal/ Workflow engine (workflows, activities, worker)
flowspec/ FlowSpec parser and compiler
paths.ts INSTANCE_DIR / STATE_DIR / LOGS_DIR resolution
bots.yaml Bot definitions — models, prompts, providers, tool scoping
config/
channel-registry.yaml Channel ID mappings per transport (populated by bootstrap)
flows/ FlowSpec workflow files (.flow)
scripts/
bootstrap.sh Zero-browser Mattermost setup
docker-compose.yml Redpanda + Mattermost + Temporal + PostgresInstance Directory Layout
A running Foreman deployment lives in an instance directory (identified by bots.yaml at its root):
<instance>/
bots.yaml Bot registry — identity marker for the instance
.env All secrets and configuration
config/channel-registry.yaml Per-transport channel IDs (written by bootstrap)
state/ Runtime state (sessions, canvases, roster overrides)
logs/ launchd stdout/stderr
docs/, flows/, workspaces/ User-editable content scaffolded from the packageCustomizing Bot Tools
By default every bot has access to all tools (Canvas, Jira, Confluence, GitHub, Bitrise, Xcode, etc.). You can restrict a bot to a specific set of tool domains via mcp_servers in bots.yaml:
bots:
alice:
type: sdk
provider: anthropic
model: claude-sonnet-4-6
mcp_servers:
- foreman-slack # Canvas + PostMessage + ReadChannel
- foreman-atlassian # Jira + Confluence
- foreman-github # GitHub PRs + issues
- foreman-bitrise # CI/CD triggers
- foreman-admin # Session control tools
- foreman-xcode # iOS simulator / Android emulatorOmitting mcp_servers (the default) gives the bot all tools.
Roadmap
Planned work and architecture direction live in docs/memory/project_foreman.md. Notable upcoming items:
global/+user/content split — separate shipped content (flows, workspaces, basebots.yaml, base memory) from user-authored content with two physical directory buckets inside the instance. Explicit addressing:/f run global/flows/examples/flowspec-tutorial.flowvs/f run user/flows/my-flow.flow. Enables cleanforeman upgradewithout clobbering user work.foreman start/stop/list/switchsubcommands — one-command switch between instance directories (process + Docker stack together).- Slack bot registry parity — apply
bots.yamlsettings to Slack channels automatically, matching Mattermost.
License
Proprietary — all rights reserved. See LICENSE.
