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:
| Variable | Description |
|---|
GH_TOKEN | GitHub token — git and gh are already authenticated, no setup needed |
MURMUR_SECRET_* | Your tenant, developer, and spawn-time secrets |
MURMUR_HOOK | The hook point name (prepare-workspace), so shared helper scripts can branch on context |
MURMUR_WORKFLOW_ID | The 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
| Mechanism | Runs | Best for |
|---|
| Repo hook | After clone, on the working branch, before the agent | Per-repo, per-branch setup: dependency install, codegen, local config |
| Startup script | At VM boot, before repos exist | Environment-level packages and tools, on every boot |
| Custom image | At image bake time, frozen into the image | Heavy, stable toolchains — zero per-spawn cost |