Skip to main content
Repos often need setup after cloning before an agent can work productively: npm ci, go mod download, code generation, writing local config. Without it, every agent burns its first minutes (and tokens) rediscovering and running your setup commands. A repo hook is a Bash script committed to the repo itself that Murmur runs automatically on the VM after the repo is cloned and before the agent starts. No configuration, no spawn flags — committing the file enables it.

The prepare-workspace hook

Create the hook at this exact path in your repo:
.murmur/hooks/prepare-workspace.sh
# .murmur/hooks/prepare-workspace.sh
set -euo pipefail

npm ci
npm run codegen
cp .env.example .env
The hook runs:
  • Once per prepared workspace — after all repos are cloned on their working branches, git identity and credentials are configured, and workspace plugins are installed; immediately before the agent process starts. It does not re-run when an agent wakes from sleep on the same VM. An agent resurrected onto a fresh VM prepares a fresh workspace and runs the hook again.
  • From the working branch the agent will operate on — the hook version that runs is the one the agent’s code will see, so a branch that changes the build system carries the matching hook change in the same commit.
  • With the repo’s checkout directory as the working directory, so relative paths resolve inside the repo.
  • Under /bin/bash — no executable bit or shebang required. Bash is the contract.
In multi-repo workspaces, each repo’s hook runs sequentially in workspace repo order.

Environment

The hook sees the same environment as the agent itself:
VariableDescription
GH_TOKENGitHub token — git and gh are already authenticated, no setup needed
MURMUR_SECRET_*Your tenant, developer, and spawn-time secrets
MURMUR_HOOKThe hook point name (prepare-workspace), so shared helper scripts can branch on context
MURMUR_WORKFLOW_IDThe agent’s workflow identifier
Model API keys and file-mounted secrets are also available, exactly as the agent receives them.

Failure semantics

Hooks fail loudly. If the hook exits non-zero, the spawn fails with an error naming the repo and the hook — the agent never starts in a workspace whose declared setup failed. There is no retry: fix the hook (or the setup it runs) and spawn again. All hooks in a workspace share a 5-minute total budget. A hook still running when the budget expires is killed and the spawn fails with a timeout error. Heavier setup belongs in a custom image or startup script — bake the toolchain into the image, and use the hook only for the per-branch remainder. Hook output streams to the VM’s system log in real time, and the tail of the output is captured in the failure error so you can see why a hook failed.

Organizing helper scripts

.murmur/hooks/ is free-form. Murmur executes only the hook names it recognizes (prepare-workspace.sh) and ignores everything else, so you can organize sub-scripts however you want:
.murmur/hooks/
  prepare-workspace.sh
  lib/
    install-deps.sh
    seed-db.sh
# .murmur/hooks/prepare-workspace.sh
set -euo pipefail
source "$(dirname "$0")/lib/install-deps.sh"
source "$(dirname "$0")/lib/seed-db.sh"
If a .murmur/hooks/ directory exists but contains no recognized hook (for example, a misspelled file name), Murmur logs a warning rather than silently doing nothing.

Guidelines

Hook output lands in logs, and the failure tail is captured with the error. Never echo secrets, and never set -x around commands that take credentials in arguments.
  • Set up the workspace; don’t mutate remotes. The hook runs before Murmur’s git/gh instrumentation is installed, so pushes or gh calls made from a hook won’t generate PR tracking or timeline events. Save remote operations for the agent.
  • Keep it fast. The hook delays agent start on every spawn. Anything stable across branches (toolchains, system packages, large dependency trees) belongs in a custom image; the hook is for what changes with the code.
  • Make it idempotent-friendly. The hook runs once per prepared workspace, but a resurrected agent gets a fresh VM and runs it again — don’t depend on state from a previous run.

Hooks vs. startup scripts vs. custom images

MechanismRunsBest for
Repo hookAfter clone, on the working branch, before the agentPer-repo, per-branch setup: dependency install, codegen, local config
Startup scriptAt VM boot, before repos existEnvironment-level packages and tools, on every boot
Custom imageAt image bake time, frozen into the imageHeavy, stable toolchains — zero per-spawn cost