Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.murmur.dev/llms.txt

Use this file to discover all available pages before exploring further.

This page is the comprehensive reference for configuring and operating Murmur entirely from the CLI. It is designed primarily for AI agents acting on a user’s behalf — the structure, hard rules, and decision tree below let an agent provision and operate a tenant end-to-end without consulting other docs. Humans can read it too; skip the first section.

For AI agents reading this page

You are likely reading this because a user asked you to set up, modify, or operate Murmur from the CLI. This page is self-contained — every command, every required field, every enum literal, and every common error is in here. Do not invent values; everything you need is documented.

Operating rules

These rules supersede any pattern you may have seen elsewhere. Follow them in order.
  1. Verify before you act. Before any state change, run murmur version (confirms server reachability) and gh auth status (confirms GitHub identity). Read .murmur/murmur.yaml to see the active tenant + workspace. If .murmur/murmur.yaml does not exist in the user’s repo, they have not run murmur setup — start at Step 1 of the walkthrough.
  2. Discover, do not guess. Before referencing a platform builtin (machine-type, disk-type, image, placement), run murmur get <kind> to see what actually exists in this tenant. Builtin names are stable across tenants but new substrates and regions are added over time.
  3. Names follow strict patterns. [a-z][a-z0-9-]{0,62} for all kinds except secret and user-secret, which use [A-Z][A-Z0-9_]*. If you guess and it’s wrong, the API rejects. Lowercase with hyphens for most things; SCREAMING_SNAKE_CASE for secrets.
  4. Enums use the full prefix form. SUBSTRATE_GCP, SUBSTRATE_AWS, ARCHITECTURE_AMD64, ARCHITECTURE_ARM64. Never write gcp or amd64 alone — the API rejects.
  5. murmur set body must include name: <same-as-positional-arg>. The body and positional argument are validated against each other.
  6. Required-field validation is one-at-a-time. If you send a body missing required fields, the API returns the first missing one. Each retry surfaces the next. The minimum YAMLs in this doc are pre-validated to pass — start from them rather than iterating from empty.
  7. murmur setup is interactive and opens a browser. There is no flag to pre-select tenant or workspace. If you must script it, either pipe answers on stdin (Y for token confirm, the numeric tenant index, then defaults) or use --non-interactive which requires ANTHROPIC_API_KEY in env (won’t work for users on Claude subscription OAuth).
  8. Cost-aware actions need user confirmation. See the table below.
  9. Stop and report on terminal failures. If an action fails with PermissionDenied, FailedPrecondition, or Unauthenticated, report the exact error to the user and ask before retrying. Do not loop.

Action risk reference

You may run without confirmingConfirm with user firstNever do without explicit ask
murmur version, murmur get *, murmur describe *, murmur status, murmur ls, murmur pool status, murmur check-permissions, murmur watch, murmur session watch, murmur task ls/get, murmur subscriptions lsmurmur spawn (each agent is 0.100.10–25), murmur set workspace with min_idle > 0 (warm VMs are billable), murmur bake (5–30 min VM build), murmur secret set (write-only, you cannot read it back to verify), murmur each (fans out, multiplies cost), batch operationsmurmur rm (irreversible; cascades blocked by ref integrity), murmur kill -A style mass kills, murmur pool flush (drops warm VMs), murmur secret rm, murmur queue clear, anything with --force-new
For cost-aware actions: state the cost estimate, name the action, ask once.

Decision tree — which section do you need?

The user asked you to…Read
”Set up Murmur in this repo”A well-set-up workspace, top to bottom
”Spawn an agent that does X”murmur spawn
”Why is my agent stuck / failing?”murmur status, then Common errors
”Create / modify a workspace, environment, recipe, persona, flight”Catalog resource reference
”Add a secret” / “give workspace X access to secret Y”secret, workspace.secret_refs, Secret hygiene
”Make agent startup faster”Pool sizing
”Why does the CLI reject my YAML?”Common errors
”What model should I use?”Model selection
”Bake a custom image with Go / Python / Node / etc.”Step 4 of the walkthrough, recipe
”Set up CI / scheduled / event-driven agents”flight, then Flights guide
”Give Bob workspace-admin access”role + group + tenant-binding
”Audit who can do what”murmur check-permissions

Vocabulary you must use precisely

  • Tenant — a GitHub org or personal account registered in Murmur. Identified as github_app/<org> or github_oauth/<user>.
  • Workspace — a launchable preset composing image + environment + placement + repos + secrets. Every murmur spawn targets one.
  • Environment — pure compute shape (machine type + disk + disk size). Placement-agnostic.
  • Placement — where VMs physically run (cloud + region + project + network).
  • Recipe — a shell script that builds a custom image via murmur bake.
  • Image — a runnable VM/container artifact, either a platform builtin or a bake output.
  • Agent — a spawned task. Has a slug, a VM, a phase, a session, a cost, and (usually) opens a PR.
  • Persona — a reusable bundle of system prompt + model + tool policy + default tasks.
  • Flight — a Markdown-defined orchestration plan with optional event triggers.
  • Pool — the set of warm VMs awaiting spawn requests. Sized tenant-wide by pool-config.max_vms and per-workspace by workspace.min_idle.
Do not coin alternative terms (“project” for workspace, “VM template” for image, “deployment” for spawn). The API rejects unknown vocabulary and the user will be confused.

When the user says “just set it up for me”

  1. Identify the GitHub org of the repo (gh api repos/:owner/:repo --jq .owner.login).
  2. Run murmur setup from inside the repo.
  3. Pick the most appropriate tenant from the setup prompt (matches the repo org).
  4. Confirm the workspace name choice with the user once (default to the repo name).
  5. Run the walkthrough steps 2–7. Use platform builtins for image/environment/placement unless the user has stated a specific toolchain need.
  6. Verify by spawning a small hello-world agent and reporting the resulting PR URL.

What this page does not cover

  • The gRPC wire protocol — see API Reference.
  • Detailed dashboard usage — see Dashboard.
  • Customer placements (running VMs in your own cloud account) — see Customer Placements.
  • Flight DSL semantics (event matchers, scheduling syntax) — see Flights.

For humans: how to use this page

Cross-references use anchor links so you can paste sections into other contexts.

Mental model

Murmur is a control plane for autonomous coding agents. To use it, you provision a small set of catalog resources, then ask the CLI to spawn agents against them. The layers, from top to bottom:
┌─ tenant ─────────────────────────────────────────────────────────────┐
│  (one per GitHub org or personal account)                            │
│                                                                      │
│  ┌─ identity & access ──────────────────────────────────────────┐    │
│  │ user, group, role, tenant-binding, service-profile           │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ secrets ────────────────────────────────────────────────────┐    │
│  │ secret, user-secret  →  injected as env vars on agent VMs    │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ pool-config (singleton: max_vms, reap_stranded_agents) ─────┐    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ compute primitives (platform-provided builtins) ────────────┐    │
│  │ machine-type, disk-type, image, placement                    │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ compute composition ────────────────────────────────────────┐    │
│  │ recipe (→ bake → image), environment, repo-config            │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ launch surfaces ────────────────────────────────────────────┐    │
│  │ workspace ─────────────────►  agent (spawned via CLI/MCP)    │    │
│  │   (image + env + placement   alias  (subdomain → agent port) │    │
│  │    + repos + secrets)                                        │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─ agent behavior ─────────────────────────────────────────────┐    │
│  │ agent-persona, flight (markdown DSL with triggers)           │    │
│  └──────────────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────────────┘
Key invariants:
  1. A workspace is the unit of “what an agent runs on.” Every murmur spawn targets a workspace. A workspace composes an image, environment, placement, and one or more repos.
  2. The catalog enforces referential integrity. You cannot delete an environment referenced by a workspace, an image referenced by an environment, etc.
  3. Every resource has a name matching [a-z][a-z0-9-]{0,62} (lowercase, starts with a letter, hyphens allowed, max 63 chars). Secrets are the exception — secret names match [A-Z][A-Z0-9_]* because they become env var names on VMs.
  4. Enums use the full prefix form in YAML: SUBSTRATE_GCP, SUBSTRATE_AWS, ARCHITECTURE_AMD64, ARCHITECTURE_ARM64.

A well-set-up workspace

This walkthrough produces a workspace that is not just valid — it is configured the way Murmur teams configure them in practice. Annotated choices explain why each field has the value it does, so you can adapt rather than copy. The example provisions a small Go service. Adapt machine sizes, regions, and language runtimes to your stack.

1. Configure the developer profile

From inside any repo:
brew tap prassoai/tap && brew install prassoai/tap/murmur
gh auth status                       # confirm you are authenticated
murmur setup                         # interactive — see CLI reference
This writes .murmur/murmur.yaml (commit) and .murmur/murmur.local.yaml (gitignored, KMS-encrypted). Verify connectivity:
murmur version                       # Client + Server versions
murmur describe                      # lists all 20 catalog kinds — confirms tenant is reachable

2. Set the pool ceiling

echo 'max_vms: 50
reap_stranded_agents: enabled' | murmur set pool-config default
Why these values: max_vms: 50 is a sensible early ceiling — high enough that you almost never queue, low enough that a runaway flight cannot bankrupt you. reap_stranded_agents: enabled auto-cleans orphaned agents whose VMs vanished (vs the default dry_run which only logs). Move to enabled once you have observed dry_run for a few days and trust the reaper.

3. Load tenant secrets

Anything you do not want hard-coded in repos goes here. Secrets surface as MURMUR_SECRET_{NAME} env vars on every agent VM.
echo "npm_abc123def456" | murmur secret set NPM_TOKEN
echo "ghp_yyyyy" | murmur secret set GH_BOT_TOKEN
echo "postgres://..." | murmur secret set DATABASE_URL
Naming: Use SCREAMING_SNAKE_CASE. The MURMUR_SECRET_ prefix is added by the platform — if you need a runtime env var named DATABASE_URL, create the secret as DATABASE_URL and reference it as $MURMUR_SECRET_DATABASE_URL (or symlink with an .envrc). Rotation: Secrets are write-only. To rotate, murmur secret set again with the new value. The previous value becomes unreadable.

4. (Optional) Bake a custom image with your toolchain

Skip this if your repo’s bootstrap script can install everything you need at agent boot. Bake when the install is expensive enough to be worth pre-doing once. The platform ships murmur-debian12-gce and murmur-debian12-aws with git, jq, curl, GitHub CLI, Claude Code, Codex CLI, yq, and a hardened murmur user. Language runtimes (Go, Python, Node, Ruby, Rust) are not included on purpose — they go in your recipe.
cat <<'EOF' | murmur set recipe go-stack
name: go-stack
base_image_gce_ref: murmur-debian12-gce
base_image_aws_ref: murmur-debian12-aws
provisioning_timeout: 25m
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  export DEBIAN_FRONTEND=noninteractive

  # Go
  curl -fsSL https://go.dev/dl/go1.22.0.linux-amd64.tar.gz | tar -C /usr/local -xz
  echo 'PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/go/bin:/home/murmur/go/bin' >> /etc/environment

  # Node.js for the frontend in the same repo
  curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
  apt-get install -y -qq nodejs
  npm install -g pnpm

  # Build tooling
  apt-get install -y -qq build-essential make jq postgresql-client

  # gcloud CLI (handy for inspecting cloud state from inside the agent)
  curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
  echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \
    > /etc/apt/sources.list.d/google-cloud-sdk.list
  apt-get update -qq
  apt-get install -y -qq google-cloud-cli

secret_allowlist:
  - GH_BOT_TOKEN     # available to the bake script for warming private deps
EOF

# Build the image. Pick a placement & environment that match where the image will run.
murmur bake go-stack go-medium murmur-gcp-us-west1
murmur bakes ls                       # watch status
murmur bake creates an image resource named like go-stack@<hash>. Reference it from a workspace via image_ref: go-stack@<hash> or pin to the latest via image_ref: go-stack (the platform resolves to the most recent successful bake). Provisioning script rules of thumb: pin every version explicitly, set -euo pipefail always, use apt-get non-interactively, gate slow steps behind if, and end with wait to flush background processes. unset GH_TOKEN at the end if you used it.

5. Define a compute environment

The environment resource is pure compute shape — placement-agnostic.
echo 'name: go-medium
substrate: SUBSTRATE_GCP
machine_type_ref: murmur-n2-standard-4
disk_type_ref: murmur-pd-balanced
disk_size_gb: 100
description: "4 vCPU / 16 GB / 100 GB pd-balanced — go-stack default"' | \
  murmur set environment go-medium
Sizing heuristic: start with murmur-n2-standard-4 (4 vCPU / 16 GB). If your build is dominated by linking large binaries, c3-standard-44 is the right escape valve. If your tests are I/O-bound and not parallel, smaller is fine. The disk is fast (pd-balanced is 240 IOPS/GB up to 80k); 100 GB is enough headroom for a Go monorepo with a Docker layer cache.

6. Create the workspace

The workspace is what murmur spawn targets. It composes everything above plus the repo list.
cat <<EOF | murmur set workspace acme-api
name: acme-api
description: "Backend API service. Agents land on go-stack VMs in us-west1."
image_ref: go-stack
environment_ref: go-medium
placement: murmur-gcp-us-west1
min_idle: 2
repos:
  - clone_url: https://github.com/acme/api.git
    base_branch: main
  - clone_url: https://github.com/acme/shared-libs.git
    base_branch: main
secret_refs:
  - NPM_TOKEN
  - GH_BOT_TOKEN
  - DATABASE_URL
ports:
  - label: api
    port: 8080
  - label: pprof
    port: 6060
EOF
min_idle: 2 keeps two warm VMs ready so the first spawn of the day is ~5 seconds, not ~90. Increase to 5–10 when active developer count > 5; keep at 0–1 for solo or low-volume workspaces. secret_refs decides what the workspace sees. The full secret list lives at tenant scope; only the names you list here become env vars on VMs spawned in this workspace. Principle of least privilege: a marketing-site workspace should not have access to DATABASE_URL. ports declares which TCP ports the dashboard and murmur url should know about. The platform tunnels these through the port-proxy with subdomain routing. Without an entry here, the port is reachable via murmur port-forward but not via a stable URL.

7. Pin the workspace in your repo’s config

cd ~/code/acme-api
cat > .murmur/murmur.yaml <<EOF
tenant:
  provider: github_app
  org: acme
workspace: acme-api
model: claude-opus-4-6
fast_mode: false
EOF
The model field becomes the default for every murmur spawn from this repo. Override per-spawn with --model.

8. (Optional) Author reusable personas and flights

Personas factor out system-prompt + model + tool-policy bundles you want to reuse:
cat <<'EOF' | murmur set agent-persona reviewer
---
description: "PR reviewer focused on correctness and tests."
model: claude-sonnet-4-6
disallowed_tools:
  - "Bash(rm *)"
  - "Bash(git push --force*)"
max_turns: 40
---
You are a thorough but fast PR reviewer. You always:
1. Read every diff hunk end-to-end before commenting.
2. Run the tests that touch the changed files.
3. Distinguish "must fix" from "nice to have" in your review.
4. End with a single APPROVE / REQUEST_CHANGES / COMMENT verdict.
EOF
Flights orchestrate one or more agents on triggers:
cat <<'EOF' | murmur set flight pr-reviewer
---
workspace: acme-api
persona: reviewer
on:
  pr_opened:
    repos: [https://github.com/acme/api]
    base_branches: [main]
  pr_synchronize:
    repos: [https://github.com/acme/api]
    base_branches: [main]
max_concurrent: 5
expected_output: respond
---
# PR Reviewer

Review the PR. Run failing tests locally. Post a single review summary
with inline comments for any blocking issues.
EOF

9. Spawn

murmur spawn fix-auth-bug "Fix the null pointer in user.go line 42" --out pr
murmur status fix-auth-bug
The first spawn warms the pool, so subsequent spawns start in seconds rather than minutes.

CLI command reference

Every command Murmur exposes. Flags are listed in the order they appear in --help. Examples are deliberately small and copy-pasteable.

Setup & authentication

murmur setup

Gathers your credentials (GitHub token, Claude OAuth or API key, SSH signing key), encrypts them, and writes the per-developer profile to .murmur/murmur.local.yaml. Run once per repo.
murmur setup [flags]
FlagTypeDescription
--outstringOutput path. Default .murmur/murmur.local.yaml. Use - for stdout.
--non-interactiveboolSkip OAuth flow and prompts; reads GH_TOKEN, ANTHROPIC_API_KEY, OPENAI_API_KEY from env.
--skip-ssh-keysboolSkip SSH signing key generation. Useful in CI.
--commit-signingboolUpload the SSH signing key to GitHub so VM commits show as Verified.
--uploadboolUpload the encrypted profile to the platform (required when --non-interactive).
Interactive flow: discovers gh token → prompts for tenant → prompts for workspace (if tenant has any) → Claude OAuth or API key → SSH key generation → writes both YAMLs. Programmatic gotcha: there is currently no flag to pre-answer the tenant or workspace prompts. To script setup, either expect-feed numeric answers on stdin or run --non-interactive with ANTHROPIC_API_KEY set.

murmur auth

Run the Claude OAuth flow standalone. Useful when only the Claude token needs refreshing.
murmur auth              # print refreshed token to stdout
murmur auth upload       # store as tenant secrets CLAUDE_OAUTH_TOKEN + CLAUDE_OAUTH_REFRESH_TOKEN
murmur auth upload --name-prefix MY_   # custom prefix → MY_OAUTH_TOKEN + MY_OAUTH_REFRESH_TOKEN

murmur version

murmur version           # Client + Server versions
murmur version --client  # Skip API call; client version only

murmur check-permissions

Evaluate permissions against the caller’s effective grants. Useful when debugging “permission denied” errors.
murmur check-permissions <kind.verb> [kind.verb ...] [--resource <kind>/<name>]
murmur check-permissions agent.read agent.list agent.delete
murmur check-permissions agent.edit --resource agent/fix-auth-bug
Output is one line per permission, marking each allowed or denied with the matching grant (if any).

Spawn

murmur spawn

Create an agent task, claim a VM from the pool, and start a session.
murmur spawn [flags] <slug> [description]
<slug> is the agent’s identifier within the workspace. Must match [a-z][a-z0-9-]{0,62}. The Git branch is murmur/w/<workspace>/u/<account>/<slug> (or .../s/... for service agents).

Core flags

FlagTypeDescription
--workspace -wstringWorkspace override. Defaults to .murmur/murmur.yaml.
--purposestringHuman-readable goal (max 240 chars). Shown in the dashboard sidebar.
--agentstringPersona name (loads agent-persona from catalog).
--modelstringModel override (e.g. claude-opus-4-6, claude-sonnet-4-6, gpt-5-4). Implies backend.
--backendstringBackend override: claude or codex. Auto-detected from model.
--outstringExpected output: pr, push, respond, or freeform text.
--append-system-promptstringAppended to the agent’s system prompt.

Session mode flags

FlagDescription
-iInteractive — Claude runs in tmux. Attach with murmur ssh --attach <slug>.
--streamStreaming backend — long-lived bidirectional channel.

Lifecycle flags

FlagTypeDescription
--on-idleenumsleep (default), terminate, terminate-when-prs-resolved, keep-alive.
--pilotboolMark as a pilot task — runs a completion assessor loop before allowing idle.
--waitboolBlock until the task reaches a terminal phase before returning.
--dequeue-strategyenumall (default), one, five — how queued follow-ups are delivered.

Repo & task flags

FlagDescription
--repoRepo to clone. Repeatable. Format: URL, URL=base, or URL=base:working.
--taskPre-populate the agent’s task checklist. Repeatable.
--input key=valueFlight input variable (only with --flight). Repeatable.
-e VAR / -e VAR=valForward an env var. Repeatable.

Resurrection & forking

FlagDescription
--resurrectResume a completed/failed/killed agent with full conversation history.
--force-newStart fresh even if a prior session exists for this slug.
--fork-from <slug>Branch off another agent’s session into a new independent agent.
--flight <path>Execute the flight at .murmur/flights/<path> via a pilot agent.

Examples

# Basic autonomous agent producing a PR
murmur spawn fix-bug "Fix the null pointer in user.go:42" --out pr

# Interactive session
murmur spawn -i explore "Walk me through the auth flow"

# Pinned model and persona
murmur spawn --model claude-opus-4-6 --agent architect design-review "Review the new event bus design"

# Pre-populated checklist
murmur spawn impl-feature "Implement the feature" \
  --task "Update the data model" \
  --task "Add API endpoints" \
  --task "Write integration tests" \
  --out pr

# Multi-repo
murmur spawn cross-refactor "Refactor shared types" \
  --repo https://github.com/acme/api \
  --repo https://github.com/acme/sdk

# Resurrect after the agent terminated
murmur spawn --resurrect fix-bug "The tests are still red — try the edge case where user is nil"

# Long-lived watcher
murmur spawn pr-shepherd "Iterate on PRs until merged" \
  --on-idle terminate-when-prs-resolved \
  --out pr

murmur each

Fan out: spawn one agent per line of stdin. Both the slug and description are templates with {} replacement.
murmur each [flags] <slug-template> <description-template>
FlagDescription
-dInput delimiter. Default \n. Use \0 for null-delimited (paired with find -print0).
--dry-runPrint the planned slug/description pairs without spawning.
--agent, --model, --backend, --repo, --workspaceSame as spawn.
# One agent per failing test file
grep -l 'FAIL' tests/ | murmur each "fix-{}" "Fix the failing tests in {}"

# Dry-run first
cat modules.txt | murmur each "audit-{}" "Audit security on {}" --dry-run

Agent lifecycle

murmur status

Query an agent’s state — phase, VM, progress, cost, opened PRs, and (optionally) timeline events.
murmur status [flags] [slug]
FlagDescription
--childrenInclude child-agent statuses recursively.
--timelineInclude the full lifecycle event timeline.
--serviceQuery a service (flight) workflow instead of a developer workflow.
--workspace -wWorkspace override.
Phase values: PHASE_STARTING, PHASE_RUNNING, PHASE_CHECKS_PENDING, PHASE_SLEEPING, PHASE_TASK_COMPLETE, PHASE_FAILED, PHASE_KILLED.

murmur ls

List agents in the current workspace.
murmur ls [flags]
FlagDescription
-aInclude completed and failed agents (default hides them).
-AInclude all developers’ agents (default scoped to caller).
--developer <name>Scope to a specific developer.
--jsonJSON array output.
-qQuiet — slugs only, one per line. Composable with xargs.
--workspace -wWorkspace override.
murmur ls -A                          # everyone's active agents
murmur ls -a --json | jq '.[] | .cost' # cost of every agent that ever ran
murmur ls -q | xargs -n1 murmur kill  # nuke everything (yours, active)

murmur kill

Cancel a running agent.
murmur kill [flags] [slug]
FlagDescription
--serviceKill a service (flight) workflow instead of a developer workflow.
--workspace -wWorkspace override.

murmur watch

Stream the local event log for an agent. Each event is one line.
murmur watch [flags] [slug]
FlagDescription
--from <stream-id>Resume from a Redis stream ID. Default 0 (from start).
--jsonRaw JSON, one event per line. Useful for jq pipelines.
--workspace -wWorkspace override.

murmur notify

Publish an event to the agent’s Pub/Sub topic. Useful for nudging an agent or simulating external events in tests.
murmur notify [flags] <slug> <message>
FlagDescription
--workspace -wWorkspace override.

Session interaction

murmur session watch

Stream live session events from a running agent. On the VM you can omit [slug] to attach to self.
murmur session watch [slug]

murmur session send

Send a follow-up message to an active agent. The message is delivered to Claude’s input stream.
murmur session send <slug> <message>

murmur session interrupt

Interrupt the agent’s current turn (graceful — Claude finishes its current tool call, then stops).
murmur session interrupt [slug]

murmur session stop

Request a graceful session shutdown. Persists session state for later --resurrect.
murmur session stop [slug]

Queue (follow-ups)

murmur queue add

Append a follow-up message to the agent’s queue. Delivered according to the dequeue strategy.
murmur queue add [flags] <slug> <description>
FlagDescription
--agentPersona override (e.g. programmer, architect).
--taskAdd a checklist item alongside the message. Repeatable.
--workspace -wWorkspace override.

murmur queue clear

Discard all queued follow-ups without delivering them.
murmur queue clear [slug]

murmur queue strategy

Change the dequeue strategy for an agent.
murmur queue strategy <slug> <all|one|five>
  • all (default) — drain all queued follow-ups into one batch.
  • one — drain one follow-up per turn.
  • five — drain up to five per turn.

murmur queue conflict-resolution

Set how the agent handles git merge conflicts during rebase. Per-repo — the second positional arg is the repo display name.
murmur queue conflict-resolution <slug> <repo> <merge|rebase|none>
Example: murmur queue conflict-resolution fix-bug acme/api rebase.

Task checklists

Every agent has a task checklist that survives across turns. Tasks support dependencies and activation conditions.

murmur task create

murmur task create [flags] [slug] <subject>
FlagDescription
-dLonger description body.
--activate-whenActivation condition (e.g. files_modified).
--patternGlob pattern for activation (e.g. *.go, **/*_test.go).
--workspace -wWorkspace override.
murmur task create fix-bug "Update the data model"
murmur task create fix-bug "Re-run tests after changes" --activate-when files_modified --pattern "*_test.go"

murmur task update

murmur task update [flags] [slug] <task-id>
FlagDescription
--subjectNew subject.
-dNew description.
-sNew status: pending, in_progress, completed, deleted.
--blocked-byComma-separated task IDs that must complete first (appended).
--blocksComma-separated task IDs this task blocks (appended).
--workspace -wWorkspace override.
murmur task update fix-bug t-123 -s completed
murmur task update fix-bug t-123 --subject "Refined wording"

murmur task ls

murmur task ls [flags] [slug]
FlagDescription
--activeOnly show tasks whose activation conditions are currently met (those that block exit).
--jsonJSON array output.
--workspace -wWorkspace override.

murmur task get

murmur task get [flags] [slug] <task-id>

Catalog operations

The catalog is the typed, versioned registry that backs every Murmur resource. All resources are managed through the same five verbs.

murmur describe

murmur describe                       # list all kinds with format and description
murmur describe <kind>                # show the kind's input format + description
murmur describe <kind> <name>         # show a specific resource with metadata

murmur get

murmur get <kind>                     # list names
murmur get <kind> <name>              # YAML representation

murmur set

Full replace. Reads YAML (or Markdown for agent-persona/flight) from stdin. All required fields must be present in the body — fields not included are reset to defaults.
<stdin> | murmur set <kind> <name> [--file-field field=path ...]
echo 'max_vms: 50' | murmur set pool-config default
murmur set agent-persona reviewer < ./personas/reviewer.md
murmur get environment staging | yq '.machine_type_ref = "murmur-n2-standard-16"' | \
  murmur set environment staging

murmur patch

Partial update. Other fields are preserved.
murmur patch <kind> <name> --set field=value [--set field=value ...] [--file-field field=path]
murmur patch pool-config default --set max_vms=200
murmur patch workspace acme-api --set min_idle=4
murmur patch agent-persona reviewer --file-field content=./personas/reviewer-v2.md

murmur rm

Delete a resource. Blocked by referential integrity — the error message lists what holds the reference.
murmur rm <kind> <name>

murmur bake and murmur bakes ls

Bake produces a new image from a recipe by running the recipe’s provisioning script on a VM derived from the base image, then snapshotting.
murmur bake [flags] <recipe> <environment> <placement>
murmur bakes ls
bake flagDescription
-e VAR / -e VAR=valForward an env var to the bake VM. Repeatable.
--service-profile <name>Run the bake under a named service profile (github_app tenants only).
murmur bake go-stack go-medium murmur-gcp-us-west1
murmur bakes ls                       # status: building / ready / failed

Secrets (shortcut commands)

murmur secret is a convenience wrapper over murmur set secret. The catalog-level commands work too.

murmur secret set

echo "sk-ant-abc123" | murmur secret set ANTHROPIC_API_KEY

murmur secret ls

murmur secret ls

murmur secret rm

murmur secret rm ANTHROPIC_API_KEY
User-scoped secrets (only readable by your agents) use the catalog form: murmur set user-secret ..., murmur get user-secret, murmur rm user-secret ....

Pool management

The platform maintains a warm VM pool for fast agent startup.

murmur pool status

murmur pool status
Shows running VMs, idle count, pending boots, and active configuration (resolved from pool-config default plus per-workspace min_idle).

murmur pool up

murmur pool up
Ensures the pool workflow is running. Idempotent; safe to invoke as part of automation.

murmur pool flush

murmur pool flush
Delete all warm VMs so they replenish from the current base image. Use after a new bake to ensure new agents land on the new image. Has no effect on already-claimed VMs.

murmur pool reconcile-visibility

murmur pool reconcile-visibility
Remove stale visibility entries (ghost sidebar agents). Use if the dashboard shows agents that no longer exist.

Connectivity

murmur ssh

SSH into an agent’s VM through an IAP tunnel. No public IPs are exposed.
murmur ssh [flags] <slug>             # login shell
murmur ssh --attach <slug>            # attach to Claude's tmux session (interactive agents)

murmur port-forward

Tunnel a local port to the agent’s VM through the port-proxy.
murmur port-forward [flags] <slug> [port ...]
FlagDescription
--insecureAllow connecting to the port-proxy without TLS.
--workspace -wWorkspace override.
murmur port-forward fix-bug 8080 6060   # local 8080→VM 8080, local 6060→VM 6060

murmur url

Print URLs for VM ports or the agent dashboard.
murmur url port <port> [port ...]     # port-proxy URLs
murmur url agent [slug]               # dashboard URL for an agent

Subscriptions

Subscribe an agent to GitHub branch/file events so it gets notified when relevant changes land.

murmur subscriptions add

murmur subscriptions add [slug] [--branch <branch>] [--file <path>]... [--repo <clone-url>]
At least one of --branch or --file is required.

murmur subscriptions remove

murmur subscriptions remove [slug] [--branch <branch>] [--file <path>]... [--repo <clone-url>]

murmur subscriptions flush

murmur subscriptions flush [slug]

murmur subscriptions ls

murmur subscriptions ls [slug]

Other

murmur mcp

Run as a stdio MCP server exposing agent tools over JSON-RPC 2.0. Used by Claude Code when it talks to Murmur.
murmur mcp [flags]
FlagDescription
--debugLog all JSON-RPC traffic to ~/.murmur/mcp.log.
--workspace -wWorkspace override.
You generally do not call this directly — claude mcp add murmur murmur mcp registers it once and Claude Code launches it on demand.

murmur upload

Upload one or more files to GCS and print public URLs. Useful for handing artifacts to agents or sharing dashboard screenshots.
murmur upload <file> [file...]

Global flags

These flags work on every command:
FlagDescription
--workspace -wOverride workspace from murmur.yaml.
--configPath to a specific config file (skips walk-up discovery).
--contextNamed context (equivalent to MURMUR_CONTEXT env var).
--verbose -vVerbose output for debugging.
MURMUR_CONTEXT=staging resolves murmur.staging.yaml + murmur.staging.local.yaml. Use for separating prod and non-prod credentials in the same repo.

Catalog resource reference

All 20 catalog kinds. Each entry lists: purpose, permissions required, minimum YAML that passes validation, full field reference, and the CLI commands you would actually use.

Universal validation rules

RuleDetail
Names[a-z][a-z0-9-]{0,62} for everything except secret/user-secret, which use [A-Z][A-Z0-9_]*.
substrate enumSUBSTRATE_GCP or SUBSTRATE_AWS. Full prefix required.
architecture enumARCHITECTURE_AMD64 or ARCHITECTURE_ARM64.
Required-field validationErrors are returned one at a time — fields are checked left-to-right. Iterate until the body passes.
Referential integrityA resource cannot be deleted while another references it. The error names the holder.
Generation numbersmurmur describe shows the current generation, author, and updated_at.
Platform builtinsResources with platform: true are immutable from your tenant.

pool-config

Purpose: Tenant-wide VM pool limits. Singleton — exactly one record per tenant, always named default. Permissions: pool-config.read, pool-config.edit

Minimum YAML

max_vms: 50

Fields

FieldTypeRequiredDefaultDescription
namestringYes (must be default)Singleton name.
max_vmsintegerNoplatform-dependentMaximum total VMs across the tenant.
reap_stranded_agentsenumNodry_runenabled, dry_run, disabled.

CLI

murmur get pool-config default
echo 'max_vms: 100' | murmur set pool-config default
murmur patch pool-config default --set max_vms=200 --set reap_stranded_agents=enabled
Per-workspace warm-pool sizing is on workspace.min_idle, not here.

user

Purpose: User identity record. Created automatically by murmur setup. Permissions: user.read, user.edit

Minimum YAML

name: alice

Fields

FieldTypeRequiredDescription
namestringYesUsername (GitHub login).
git_namestringNoGit commit author name.
git_emailstringNoGit commit author email.
ssh_public_keysarrayNoSSH public keys for VM access.

CLI

murmur get user
murmur get user alice
murmur patch user alice --set git_email=alice@acme.com

group

Purpose: Named principal set for authorization grants. Bound to roles via tenant-binding. Permissions: group.read, group.list, group.create, group.edit, group.delete

Minimum YAML

The source kind is a proto oneof at the top level — set exactly one of static, github_admin, or all_tenant_members.
name: backend-team
static:
  members:
    - alice
    - bob
Or to mirror GitHub org admins:
name: github-admins
github_admin: {}
Or to grant to every tenant member:
name: everyone
all_tenant_members: {}

Fields

FieldTypeRequiredDescription
namestringYesGroup identifier.
staticobjectOne of these three{members: [<username>, ...]}.
github_adminobjectOne of these three{} — membership equals GitHub org admins.
all_tenant_membersobjectOne of these three{} — every user in the tenant.
descriptionstringNoHuman-readable description.

CLI

cat <<EOF | murmur set group backend-team
name: backend-team
static:
  members: [alice, bob]
EOF
murmur get group backend-team

role

Purpose: Named permission bundle. Granted to principals via tenant-binding. Permissions: role.read, role.list, role.create, role.edit, role.delete

Minimum YAML

name: workspace-admin
permissions:
  - workspace.read
  - workspace.list
  - workspace.edit
  - workspace.delete

Fields

FieldTypeRequiredDescription
namestringYesRole identifier.
permissionsarray of stringsYes (non-empty){kind}.{verb} strings. Verbs: read, list, create, edit, delete.
descriptionstringNoHuman-readable description.

CLI

cat <<EOF | murmur set role workspace-admin
name: workspace-admin
permissions: [workspace.read, workspace.list, workspace.edit, workspace.delete]
EOF
murmur get role workspace-admin

tenant-binding

Purpose: Tenant-wide authorization grant. Binds a principal to a role. Permissions: tenant-binding.read, tenant-binding.create, tenant-binding.delete

Minimum YAML

grant.users and grant.groups are arrays; grant.role is the role to grant. At least one of users or groups must be non-empty, and the referenced role must already exist.
name: backend-admins
grant:
  groups: [backend-team]
  role: workspace-admin

Fields

FieldTypeRequiredDescription
namestringYesBinding identifier.
grant.usersarray of stringsOne of these twoUsernames to grant the role to.
grant.groupsarray of stringsOne of these twoGroup names to grant the role to.
grant.rolestringYesRole to grant. Must already exist as a role resource.

CLI

cat <<EOF | murmur set tenant-binding backend-admins
name: backend-admins
grant:
  groups: [backend-team]
  role: workspace-admin
EOF

service-profile

Purpose: Identity for non-human agents (CI bots, scheduled flights). Has its own credentials and grants. Permissions: service-profile.read, service-profile.list, service-profile.create, service-profile.edit, service-profile.delete

Minimum YAML

name: ci-bot

Fields

FieldTypeRequiredDescription
namestringYesProfile identifier.
descriptionstringNoWhat the profile is used for.
grantsarrayNoInline permission grants. Prefer tenant-binding.

CLI

murmur set service-profile ci-bot <<< 'name: ci-bot'
murmur get service-profile ci-bot
murmur rm service-profile ci-bot

secret

Purpose: Tenant-wide secret. KMS-encrypted. Injected as MURMUR_SECRET_{NAME} on agent VMs. Permissions: secret.read (metadata only), secret.create, secret.delete

Minimum YAML

name: NPM_TOKEN
plaintext_value: npm_abc123def456

Fields

FieldTypeRequiredDescription
namestringYesMatches [A-Z][A-Z0-9_]*.
plaintext_valuestringYes (on create/replace)Write-only — never returned by get.

CLI

echo 'name: NPM_TOKEN
plaintext_value: npm_abc123def456' | murmur set secret NPM_TOKEN

# Shortcut form
echo "npm_abc123def456" | murmur secret set NPM_TOKEN

murmur secret ls
murmur secret rm NPM_TOKEN
Reference from a workspace via secret_refs: [NPM_TOKEN].

user-secret

Purpose: Per-developer secret. Same shape as secret, but encrypted with the owning user’s identity in the AAD. Permissions: user-secret.read, user-secret.create, user-secret.delete

Minimum YAML

name: MY_PERSONAL_TOKEN
plaintext_value: sk-personal-xyz

CLI

echo 'name: MY_PERSONAL_TOKEN
plaintext_value: sk-personal-xyz' | murmur set user-secret MY_PERSONAL_TOKEN

machine-type

Purpose: Sanctioned VM shape: vCPUs, memory, architecture, per-region pricing.

Fields

FieldTypeRequiredDescription
namestringYesMachine-type identifier.
vcpusnumberYes (positive)Virtual CPU count.
memory_gbnumberYesMemory in gigabytes.
architectureenumNoARCHITECTURE_AMD64 or ARCHITECTURE_ARM64.
gceobjectNo{machine_type, regions: {<region>: {cost_per_hour}}}.
awsobjectNo{instance_type, regions: {<region>: {cost_per_hour}}}.
platformbooleanNotrue if platform builtin.
descriptionstringNoHuman-readable description.

Platform builtins (typical)

murmur-n2-standard-2, -4, -8, -16, -32; murmur-c3-standard-44; murmur-m5-large, -xlarge, -2xlarge, -4xlarge, -8xlarge; murmur-c5-9xlarge.

CLI

murmur get machine-type
murmur get machine-type murmur-n2-standard-2

disk-type

Purpose: Sanctioned persistent disk type with per-region storage pricing.

Fields

FieldTypeRequiredDescription
namestringYesDisk-type identifier.
substrateenumYesSUBSTRATE_GCP or SUBSTRATE_AWS.
gcpobjectWhen GCP{disk_type, regions: {<region>: {cost_per_gib_month}}}.
awsobjectWhen AWS{volume_type, regions: {<region>: {cost_per_gib_month}}}.
platformbooleanNotrue if platform builtin.
descriptionstringNoHuman-readable description.

Platform builtins (typical)

GCP: murmur-pd-balanced, murmur-pd-ssd, murmur-pd-standard. AWS: murmur-gp3, murmur-io2.

CLI

murmur get disk-type
murmur get disk-type murmur-pd-balanced

image

Purpose: Substrate-bound runnable artifact — AWS AMI, GCE image, or Docker container. Produced by murmur bake.

Fields

FieldTypeRequiredDescription
namestringYesImage identifier.
architectureenumYesARCHITECTURE_AMD64 or ARCHITECTURE_ARM64.
sourceobjectYes (one of){gce: {self_link}}, {aws: {ami_id, region}}, or {docker: {repository, tag}}.
preinstalledstringNoMulti-line description of pre-installed tooling.
descriptionstringNoHuman-readable description.

Platform builtins

murmur-debian12-gce, murmur-debian12-aws. Both ship with git, jq, curl, GitHub CLI, Claude Code, Codex CLI, yq, and a hardened murmur user. Language runtimes (Go, Python, Node, Ruby, Rust) are intentionally not included — add them via a recipe.

CLI

murmur get image
murmur get image murmur-debian12-gce

placement

Purpose: Where VMs run — cloud provider, project, region/zone, network, and credentials.

Fields

FieldTypeRequiredDescription
namestringYesPlacement identifier.
substrateenumYesSUBSTRATE_GCP or SUBSTRATE_AWS.
platformbooleanNotrue if platform-managed. Customer placements set this false.
gcpobjectWhen GCP{project, network_project, subnet, zones[], wif_provider_resource_name, wif_service_account, wif_readonly_service_account}.
awsobjectWhen AWS{account_id, region, subnet, security_groups[], instance_profile}.
service_accountstringNoService account VMs run as.
descriptionstringNoHuman-readable description.

Platform builtins

GCP: murmur-gcp-us-central1, murmur-gcp-us-east1, murmur-gcp-us-west1. AWS: murmur-aws-us-east-1, murmur-aws-us-west-2. For running agents in your own cloud account, see Customer Placements.

CLI

murmur get placement
murmur get placement murmur-gcp-us-west1

recipe

Purpose: Image build script. References a base image per substrate, runs a shell script during murmur bake to install your toolchain, produces an image. Permissions: recipe.read, recipe.create, recipe.edit, recipe.delete

Minimum YAML

At least one of base_image_gce_ref or base_image_aws_ref is required. provisioning_timeout is required.
name: my-recipe
base_image_gce_ref: murmur-debian12-gce
provisioning_timeout: 30m
provisioning_script: |
  #!/bin/bash
  set -e
  echo "build your toolchain here"

Fields

FieldTypeRequiredDescription
namestringYesRecipe identifier.
base_image_gce_refstringOne of these twoGCE base image.
base_image_aws_refstringOne of these twoAWS base AMI.
provisioning_timeoutdurationYesMax build duration (Go duration: 30m, 1h, 90m).
provisioning_scriptstringNoShell script run during bake. Has GH_TOKEN and secret_allowlist secrets in env.
secret_allowlistarrayNoNames of secret resources the script may read.

CLI

cat <<'EOF' | murmur set recipe my-recipe
name: my-recipe
base_image_gce_ref: murmur-debian12-gce
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  curl -fsSL https://go.dev/dl/go1.22.0.linux-amd64.tar.gz | tar -C /usr/local -xz
provisioning_timeout: 25m
EOF

murmur bake my-recipe go-medium murmur-gcp-us-west1
murmur bakes ls

environment

Purpose: Pure compute shape — substrate + machine type + disk type + disk size. Placement-agnostic. Permissions: environment.read, environment.create, environment.edit, environment.delete

Minimum YAML

name: go-medium
substrate: SUBSTRATE_GCP
machine_type_ref: murmur-n2-standard-4
disk_type_ref: murmur-pd-balanced
disk_size_gb: 100

Fields

FieldTypeRequiredDescription
namestringYesEnvironment identifier.
substrateenumYesSUBSTRATE_GCP or SUBSTRATE_AWS.
machine_type_refstringYesReference to a machine-type.
disk_type_refstringYesReference to a disk-type.
disk_size_gbintegerYesBoot disk size in GB.
descriptionstringNoHuman-readable description.

CLI

cat <<EOF | murmur set environment go-medium
name: go-medium
substrate: SUBSTRATE_GCP
machine_type_ref: murmur-n2-standard-4
disk_type_ref: murmur-pd-balanced
disk_size_gb: 100
EOF

repo-config

Purpose: Per-repository overrides for merge behavior. Applied to repos whose clone_url matches. Permissions: Admin-only.

Minimum YAML

The resource name is the clone URL — the positional argument to murmur set is the URL, and the body has the same URL in clone_url.
clone_url: https://github.com/acme/backend

Fields

FieldTypeRequiredDescription
clone_urlstringYesGit clone URL. Also used as the resource name.
conflict_resolutionenumNo (default rebase)rebase or merge.
base_branchstringNoDefault base branch. Overrides the repo’s default.

CLI

cat <<EOF | murmur set repo-config "https://github.com/acme/backend"
clone_url: https://github.com/acme/backend
conflict_resolution: rebase
base_branch: main
EOF

murmur get repo-config "https://github.com/acme/backend"

workspace

Purpose: Launchable preset — composes image, environment, placement, secrets, and repos. Every murmur spawn targets a workspace. Permissions: workspace.read, workspace.list, workspace.create, workspace.edit, workspace.delete

Minimum YAML

name: my-workspace
image_ref: murmur-debian12-gce
environment_ref: murmur-gcp-small
placement: murmur-gcp-us-west1
repos:
  - clone_url: https://github.com/acme/my-repo.git
    base_branch: main
All six fields above are required and validated one at a time — set returns {field} is required until each is present.

Fields

FieldTypeRequiredDescription
namestringYesWorkspace identifier.
image_refstringYesReference to an image.
environment_refstringYesReference to an environment.
placementstringYesReference to a placement.
repos[]arrayYes (at least one)Repositories to clone.
repos[].clone_urlstringYesGit clone URL.
repos[].base_branchstringYesDefault branch.
min_idleintegerNo (default 0)Minimum warm VMs to keep for this workspace.
secret_refsarrayNoNames of secret resources to inject as env vars.
ports[]array of {label, port}NoTCP ports for port-proxy routing.
descriptionstringNoHuman-readable description.

CLI

cat <<EOF | murmur set workspace my-workspace
name: my-workspace
image_ref: murmur-debian12-gce
environment_ref: murmur-gcp-small
placement: murmur-gcp-us-west1
repos:
  - clone_url: https://github.com/acme/my-repo.git
    base_branch: main
min_idle: 2
secret_refs: [NPM_TOKEN, DATABASE_URL]
ports:
  - {label: web, port: 3000}
EOF

murmur get workspace
murmur patch workspace my-workspace --set min_idle=4

alias

Purpose: Port-proxy alias binding a friendly name to an agent’s port for subdomain routing. Permissions: alias.read, alias.create, alias.delete

Fields

FieldTypeRequiredDescription
namestringYesAlias identifier (used as subdomain prefix).
agent_idobjectYesIdentifies the target agent. Encoded as a proto message — see note below.
portintegerYesPort the alias forwards to.
agent_id is a structured proto message with required account and agent fields. The exact YAML/JSON encoding accepted by murmur set alias depends on the proto-to-YAML codec; if your {account, agent} block returns proto: syntax error, copy the shape from an existing alias via murmur get alias <name> and adapt.

CLI

# Inspect an existing alias to see the encoded shape, then adapt
murmur get alias <existing-name>

# Then mirror that shape
murmur set alias my-preview < ./aliases/my-preview.yaml

agent

Purpose: Runtime record created when an agent is spawned. Read-only — managed by the orchestrator. Listed here for completeness.

Fields (read via murmur get)

FieldTypeDescription
namestringSlug.
agent_idstringUnique agent identifier.
grantsarrayEffective permission grants.
created_attimestampSpawn time.
terminated_attimestampTermination time, if terminated.
session_urlstringLive session view URL.
purposestringHuman-readable goal.
service_profilestringIf a service agent, its profile.

CLI

murmur get agent                      # list active agents
murmur get agent fix-auth-bug         # show one agent's catalog record
murmur status fix-auth-bug            # richer view (phase, VM, progress, cost)

agent-persona

Purpose: Reusable agent configuration — system prompt, model, tool policy, default tasks. Referenced from murmur spawn --agent or from flight.persona. Input format: Markdown with YAML front-matter. Permissions: agent-persona.read, agent-persona.create, agent-persona.edit, agent-persona.delete

Minimum input

---
description: One-line summary used in catalog listings.
---
You are a helpful coding assistant. Use the available tools.

Front-matter fields

FieldTypeRequiredDescription
descriptionstringNoCatalog summary.
modelstringNoModel override (opus, sonnet, haiku, or full claude-* ID).
toolsarrayNoAllowlist of tool names. Empty = all tools.
disallowed_toolsarrayNoDenylist (overrides tools).
max_turnsintegerNoMaximum turns before the agent stops.
tasksarrayNoDefault task checklist (string items).
The Markdown body below the front-matter is the system prompt.

CLI

murmur set agent-persona reviewer < ./personas/reviewer.md

cat <<'EOF' | murmur set agent-persona security-auditor
---
description: Security-focused code reviewer.
model: claude-opus-4-6
disallowed_tools: ["Bash(rm *)", "Bash(git push --force*)"]
max_turns: 50
---
You are a security auditor. Look for SQL injection, XSS, authentication
bypasses, IDOR vulnerabilities, and missing authorization checks.
EOF

murmur get agent-persona
murmur get agent-persona reviewer

flight

Purpose: Multi-agent orchestration plan with triggers (events, schedules) and a default workspace. Stored as Markdown with YAML front-matter. Input format: Markdown with YAML front-matter. Permissions: flight.read, flight.create, flight.edit, flight.delete

Minimum input

---
workspace: my-workspace
---
# Flight body — describes what the pilot agent should do.

Front-matter fields

FieldTypeRequiredDescription
workspacestringYesDefault workspace for spawned agents.
daemonbooleanNo (default false)If true, runs continuously, consuming events.
pausedbooleanNo (default false)If true, triggers are disabled.
onobjectNoEvent triggers. Keys are event types (pr_opened, pr_labeled, pr_synchronize, push, schedule); values are filter blocks.
personastringNoReference to an agent-persona.
modelstringNoModel override for the pilot.
service_profilestringNoIdentity the flight runs as.
max_concurrentintegerNoMaximum simultaneous runs.
dequeue_strategyenumNoFor daemons: all, one, five.
expected_outputenumNopr, push, respond.

CLI

murmur set flight pr-review < ./flights/pr-review.md
murmur get flight                     # list flights
murmur get flight pr-review           # show flight content
murmur rm flight pr-review
See Flights for the full event/trigger reference and DSL. To execute a flight ad-hoc (without storing it as a catalog resource), pass it to spawn:
murmur spawn --flight ./flights/pr-review.md my-run --input repo=acme/api

Best practices

Workspace design

PatternUse when
One workspace per repoMost common. Keeps secret scopes narrow and lets each repo pick its own image.
One workspace per serviceMonorepo with services that need different toolchains. Use --repo overrides on spawn to swap subsets.
One workspace per substrate × regionMulti-region resilience. Pair with placement-aware flight routing.
Anti-patterns:
  • A single “shared” workspace that owns every repo. Secrets leak across teams, and image bakes get bloated trying to satisfy everyone.
  • A separate workspace per developer. Personas + user secrets give per-developer isolation without the catalog overhead.
  • Naming workspaces after people or dates (alice-staging-2024). Workspaces outlive their original purposes; pick a name describing what runs there.

Model selection

ModelUse case
claude-opus-4-7[1m] (latest)Architecture decisions, deep refactors, gnarly debugging, design-doc generation. Slowest, most expensive, most capable.
claude-sonnet-4-6Default for most coding tasks. Fast, accurate, cheap enough for parallel fanout.
claude-haiku-4-5-20251001Tight loops where latency matters more than reasoning depth (e.g. PR triage labelers).
gpt-5-4 (via Codex backend)When the codebase is dominated by Python ML or you want Codex’s tool-call style.
The default for the repo lives in .murmur/murmur.yaml’s model: field. Per-spawn override with --model. Per-persona override in the persona’s front-matter.

Pool sizing

SettingEffect
pool-config.max_vmsTenant ceiling. Keep loose enough that you almost never queue. Tight enough that a runaway flight cannot run away.
workspace.min_idlePer-workspace warm count. Sets the floor of how fast first-of-the-day spawns are.
pool-config.reap_stranded_agents: enabledAuto-clean orphans whose VMs vanished. Start in dry_run, promote to enabled once stable.
Rule of thumb: workspace.min_idle should be roughly the count of simultaneous spawns you do during a normal work hour. If you spawn 4 agents at once at 9am, min_idle: 4 makes that batch start instantly. The pool refills behind you.

Secret hygiene

  • Tenant-scope by default, user-scope when truly personal. secret is the common case. Use user-secret only when a value must never be shared with the rest of the team.
  • Reference, do not inline. workspace.secret_refs chooses what each workspace can see. Defaulting to “every workspace sees every secret” is a footgun.
  • Allowlist for bakes separately. Recipes get their own secret_allowlist. A secret needed by the build script does not automatically reach runtime agents.
  • Rotate by setting again. Secrets are write-only; rotation is a secret set with the new value. Old values become unreadable.
  • Audit access via check-permissions. Before sharing a workspace with someone new, murmur check-permissions secret.read --resource secret/PRODUCTION_DB from their context.

Naming conventions

ResourceRecommended patternWhy
workspace<repo-name> or <service-name>One workspace per repo or service. Matches what an agent thinks “where am I” means.
environment<workload>-<size> (e.g. go-medium, frontend-small)Workload + size = obvious sizing intent.
recipe<workload>-stack (e.g. go-stack, python-ml-stack)Stack-flavored toolchains.
agent-personarole/expertise (e.g. reviewer, architect, security-auditor)Reads as a job title.
flightverb-noun (e.g. pr-review, nightly-tests, bug-triage)Reads as what happens when it fires.
secretSCREAMING_SNAKE_CASEMatches the env-var convention.
tenant-binding<group>-<role> (e.g. backend-team-workspace-admin)Self-documenting binding.

Permission model

The shape of every permission is {kind}.{verb} where verbs are read, list, create, edit, delete. Plus a few kind-specific verbs (agent.kill, secret.access, etc.). Recommended starter roles for a small team:
# tenant-admin — everything
name: tenant-admin
permissions: ["*.*"]

# workspace-admin — manage workspaces and their direct deps, no secrets
name: workspace-admin
permissions:
  - workspace.*
  - environment.*
  - recipe.*
  - image.read
  - placement.read
  - agent-persona.*
  - flight.*

# developer — spawn and manage own agents
name: developer
permissions:
  - workspace.read
  - workspace.list
  - agent.*
  - secret.list                       # see names, not values
  - user-secret.*
Bind via tenant-binding.

Observability

SignalWhere
Per-agent cost, phase, PRsmurmur status <slug> or the dashboard.
Pool utilizationmurmur pool status.
Tenant-wide spend trend`murmur ls -A -a —jsonjq ’.[].cost’` aggregated.
Audit log of catalog changesmurmur describe <kind> <name> shows generation, author, updated_at for each resource.
Live event streammurmur watch <slug> for one agent; pair with --json and jq for filtering.

Common errors and validation

ErrorCauseFix
rpc error: code = InvalidArgument desc = name is requiredBody missing name: field.Add name: <same-as-positional-arg> to the YAML body.
rpc error: code = InvalidArgument desc = name must match [a-z][a-z0-9-]{0,62}Name violates the lowercase-letter-start rule.Rename. Underscores and uppercase letters are not allowed (except for secrets).
rpc error: code = InvalidArgument desc = secret name "" must match [A-Z][A-Z0-9_]*Secret name not in screaming snake case.Rename to SCREAMING_SNAKE_CASE.
rpc error: code = InvalidArgument desc = ref name "X" does not match payload name "Y"Positional arg and body name: disagree.Make them match.
rpc error: code = InvalidArgument desc = substrate is requiredsubstrate: field missing or unrecognized value.Use SUBSTRATE_GCP or SUBSTRATE_AWS exactly.
rpc error: code = InvalidArgument desc = at least one repo is requiredWorkspace body has repos: empty or absent.Add at least one {clone_url, base_branch} entry.
rpc error: code = InvalidArgument desc = repo base_branch is requiredA repo entry omitted base_branch.Add base_branch: main (or whatever default applies).
rpc error: code = InvalidArgument desc = at least one of base_image_aws_ref or base_image_gce_ref is requiredRecipe body has neither base image.Add base_image_gce_ref: or base_image_aws_ref: (or both).
rpc error: code = InvalidArgument desc = provisioning_timeout is requiredRecipe body missing provisioning_timeout.Add provisioning_timeout: 30m (or another Go duration).
rpc error: code = InvalidArgument desc = group source is required (static, github_admin, or all_tenant_members)Group body uses source: static instead of the proto oneof.Put the source as a top-level key: static: {members: [...]}, github_admin: {}, or all_tenant_members: {}.
rpc error: code = InvalidArgument desc = grant must specify at least one group or userTenant-binding grant block has no users or groups array.Add grant.users: [...] or grant.groups: [...].
rpc error: code = InvalidArgument desc = role "X" does not existTenant-binding references a role that has not been created yet.Create the role first with murmur set role X.
rpc error: code = InvalidArgument desc = ref name "X" does not match payload name "Y" (on repo-config)The positional name is the clone_url itself, not an arbitrary identifier.murmur set repo-config "https://github.com/org/repo" with body clone_url: https://github.com/org/repo.
Could not list workspaces: rpc error: code = PermissionDenied desc = s2s identity required — skippingWorkspace lookup during murmur setup for a tenant without workspaces yet.Cosmetic; safe to ignore. Setup proceeds.
unknown command "connect" / unknown command "install"Documented commands that the CLI does not implement.Use the catalog-level equivalent or skip; documented in PR review notes.

Required-field cascade pattern

The API validates one missing required field at a time. To create a resource from scratch, you usually send an initial body, parse the error to learn the next required field, append it, and resend until it succeeds. The minimum YAMLs in this doc are the fully-passing bodies — they save you the round trips. When designing new kinds, the same pattern lets an LLM bootstrap valid configs from a single starting field: name. Iterate until the body is accepted.

Reference: dependency order for a brand-new tenant

For an admin onboarding a tenant from zero:
  1. murmur setup — install the CLI, authenticate, and write your encrypted developer profile.
  2. pool-config default — set max_vms to your budget ceiling.
  3. role + group + tenant-binding — bind humans and service profiles to roles.
  4. secret — tenant secrets (npm tokens, database URLs, package-registry credentials).
  5. recipe + murmur bake — only if you need a toolchain beyond the platform debian12 base.
  6. environment — compose machine_type_ref + disk_type_ref + disk_size_gb for the agent VM size.
  7. workspace — wire image + environment + placement + repos + secrets.
  8. agent-persona + flight — reusable agent behaviors and event-triggered orchestrations.
  9. murmur spawn — confirm the loop works end-to-end with a hello-world agent.
Every step is reversible with murmur rm <kind> <name>, blocked only by referential integrity (e.g. you cannot delete an environment referenced by a workspace — delete the workspace first or repoint it).