> ## 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.

# systemPrompt: customizing the platform system prompt

> How an agent persona's systemPrompt frontmatter replaces, removes, or extends the sections of the system prompt Murmur adds to every turn.

Every turn, Murmur adds a system prompt behind the task you give the agent: where the repositories are checked out, how to open pull requests, how structured output and tasks work, and so on. The prompt is an ordered list of **sections**. Each section is a [Go `text/template`](https://pkg.go.dev/text/template). A persona's `systemPrompt` frontmatter field changes that list: inherit, replace, or remove any section Murmur provides, and add sections of your own.

This page is the reference for `systemPrompt`. See [agent-persona](https://docs.murmur.dev/catalog/agent-persona.md) for the rest of the persona's fields, and [Agent personas](https://docs.murmur.dev/concepts/agent-personas.md) for the concept overview.

## How the prompt is built

Murmur renders the system prompt as it prepares each turn, from the persona the agent runs, so a change to Murmur's default templates reaches a running agent on its next turn. It is rendered section by section, in a fixed order, and the non-empty results are joined with a blank line. A section that renders to nothing — because it doesn't apply to this turn, this harness, or this model — simply disappears; it never leaves a blank heading or an empty bullet behind.

When every section renders to nothing, Murmur adds no system prompt at all and the harness runs on its own, exactly as it would outside Murmur. A persona gets there by removing every section, or by replacing every section with an empty template, on a turn where neither the requester nor the spawn supplied a system prompt of their own.

The order is:

1. The **platform sections** below, in the order listed — each inherited from Murmur's default, replaced with your own template, or removed.
2. Your persona's **extensions**, in the order you list them.
3. The requester's own system prompt, then the spawn's appended prompt, including flight prompts. A persona cannot replace or remove either: whatever the persona does, this text reaches the turn and has the last word.

## Platform sections

`systemPrompt.platform` has one key per section, camelCase, in render order. Leave a key unset to inherit Murmur's template for that section. Set `replace` to supply your own template, or `remove: true` to drop the section entirely.

| Key | What it says | When it appears |
| - | - | - |
| `persona` | The persona's own prompt text. | Codex and opencode only. Claude receives the persona as its agent definition instead, so Murmur's template is empty for Claude — overriding this key has no effect on a Claude turn. |
| `workspace` | Where the repositories are checked out, on which branches, and the agent ref to use in pull request titles. Phrasing adapts to no repos, one repo, or several. | Always. |
| `gitPush` | That a plain `git push` publishes a branch and sets up tracking, with no `-u` or refspec needed. | When at least one repository is checked out. |
| `branchCreated` | That a working branch was created locally for the agent and is not on the remote until pushed. | Once per repository whose branch was freshly created for this agent, rather than adopted. |
| `commitSigning` | That Murmur's git wrapper signs commits automatically, and signing must not be bypassed. | Always. |
| `ghGateway` | That `gh` is routed through Murmur's GitHub gateway: use it normally, and report any operation it doesn't support. | When `gh` is routed through the gateway. |
| `gitWrapper` | To commit and push with the `git` on `PATH`, and to report a git wrapper error rather than work around it. | Always. |
| `forkPr` | That a fork checkout's pull request must be opened against, and checked for mergeability on, the base repository rather than the fork. | Once per repository whose pull request targets a base repository. |
| `prDashboardLink` | To include the agent's dashboard link in pull request descriptions. | Always. |
| `prMergeability` | To check that an opened pull request merges cleanly, and to merge the base branch in on conflict. | Always. |
| `waiver` | How to record, under a `## Waivers` heading in the pull request description, a rule the requester explicitly told the agent to relax. | Always. |
| `structuredOutput` | The fields of the end-of-turn structured JSON output: `response`, `needs_input`, one bullet per registered flight-message field, and `result` when the caller supplied an output schema. | Always. |
| `opencodeStructuredOutput` | To deliver the structured output by calling the `StructuredOutput` tool, rather than ending the turn with prose. | opencode only. |
| `knowledge` | How to rate injected knowledge (bump or flag references), and how to author new knowledge when the deployment asks agents to. | When this turn injected knowledge items, when the deployment asks agents to author knowledge, or both. |
| `eventDelivery` | How Murmur delivers events (CI results, PR comments, reviews, and so on) as they happen, and that the agent should never wait for CI instead of ending its turn. | Always. |
| `completion` | To finish the task by producing the structured output, which is delivered automatically to the parent agent. | Always. |
| `expectedOutput` | What the spawn asked for: a pull request, a push, a response, or freeform text. | When the spawn specified an expected output. |
| `tasks` | The agent's mandatory checklist, including which tasks are conditional and how to resolve each one. | When the agent has checklist tasks. |
| `autonomousTurn` | That nothing backgrounded (a Monitor, a background Bash task) survives the end of the turn, so long-running work must be awaited within the same turn or split across turns. | Non-streaming (autonomous) Claude turns only. |

### Inherit, replace, remove

```yaml theme={null}
systemPrompt:
  platform:
    prMergeability:          # replace a platform section
      replace: |
        {{if eq .Harness "claude"}}Check mergeability after opening the PR.{{end}}
    eventDelivery:           # remove a platform section
      remove: true
                             # every other platform section is inherited
```

Every key you omit is inherited unchanged. Set exactly one of `replace` or `remove` on a key you list. An empty `replace` renders the section to nothing, just like `remove: true`. `remove: false` is rejected when the persona is saved; leave the key unset to inherit the section.

## Extensions

`systemPrompt.extensions` is a list of sections you invent. Unlike platform sections, an extension doesn't override anything, so its name never collides with a section Murmur adds later.

```yaml theme={null}
systemPrompt:
  extensions:
    - id: harness_notes
      template: |
        {{if eq .Harness "codex"}}Run the test suite before every commit.{{end}}
        {{if eq .ModelFamily "haiku"}}Keep each edit small.{{end}}
```

* `id` must be unique within the persona and match a lowercase letter followed by up to 62 lowercase letters, digits, or underscores: `[a-z][a-z0-9_]{0,62}`.
* `template` must not be empty.
* Extensions render in list order, after every platform section and before the requester's system prompt and the spawn's appended prompt.

## Variable reference

A section's template renders against a fixed set of variables. A template that names a variable not listed here fails to render, and fails the turn; see [Render errors](#render-errors).

### Top-level

| Variable | Type | Value |
| - | - | - |
| `.Harness` | string | `claude`, `codex`, or `opencode`. Never empty. |
| `.Streaming` | bool | `true` when the turn runs in a persistent streaming session rather than one autonomous process. |
| `.Model` | string | The model the turn runs: the spawn's, else the persona's. Empty when the harness default applies. |
| `.ModelFamily` | string | `opus`, `sonnet`, `haiku`, `gpt`, `gemini`, or empty when unrecognized. |
| `.ReasoningEffort` | string | The requested reasoning effort; empty when unset. |
| `.AgentRef` | string | `<workspace>/<slug>`, the ref pull request titles carry. |
| `.Workspace` | string | The workspace name. |
| `.Slug` | string | The agent's slug. |
| `.WorkspaceDir` | string | The workspace root — the turn's working directory. |
| `.Repos` | list | The checked-out repositories, in input order. See [`.Repos[]`](#repos). |
| `.GitHubGateway` | bool | `true` when `gh` is routed through Murmur's GitHub gateway. |
| `.HasResultSchema` | bool | `true` when the caller supplied an output schema, so the envelope has a `result` field. |
| `.FlightMessages` | list | The registered flight-message fields, sorted by field name. See [`.FlightMessages[]`](#flightmessages). |
| `.Knowledge` | object | The turn's curated-knowledge state. See [`.Knowledge`](#knowledge). |
| `.ExpectedOutput` | string | `pr`, `push`, `respond`, freeform text, or empty. |
| `.Tasks` | list | The agent's checklist tasks. See [`.Tasks[]`](#tasks). |
| `.Persona` | object | The spawned agent's persona. See [`.Persona`](#persona). |
| `.UserSystemPrompt` | string | The requesting user's own system prompt layer. |
| `.AppendSystemPrompt` | string | The spawn's appended prompt, including flight prompts. |

### `.Repos[]`

One entry per checked-out repository.

| Field | Value |
| - | - |
| `.Name` | The `owner/repo` display name. |
| `.CloneURL` | The clone URL. |
| `.Dir` | The absolute checkout path. |
| `.Branch` | The working branch. |
| `.BranchCreated` | `true` when the branch was created for this agent and is not yet on the remote. |
| `.BaseRepo`, `.BaseCloneURL`, `.BaseBranch`, `.ForkOwner` | Set only for a fork checkout whose pull request targets a base repository. |

### `.Tasks[]`

One entry per checklist task.

| Field | Value |
| - | - |
| `.ID`, `.Subject` | The task's ID and subject. |
| `.Status` | `pending`, `in_progress`, `completed`, or `not_applicable`. |
| `.NotApplicableReason` | Set when `.Status` is `not_applicable`. |
| `.Conditional` | `true` when the task has an activation condition. |
| `.ActivationPattern` | The condition's file glob; empty when the task activates on any push. |

### `.FlightMessages[]`

One entry per registered flight-message field of the structured-output envelope.

| Field | Value |
| - | - |
| `.Field` | The envelope field name. |
| `.Flight` | The flight the value is delivered to. |
| `.Description` | The registration's own description of the field. |

### `.Knowledge`

| Field | Value |
| - | - |
| `.Injected` | `true` when this turn injected curated-knowledge items. |
| `.CreationEnabled` | `true` when the deployment asks agents to author knowledge. |

### `.Persona`

| Field | Value |
| - | - |
| `.Name` | The persona's name. |
| `.Prompt` | The persona's markdown body. |

## Function reference

Every [`text/template` builtin](https://pkg.go.dev/text/template#hdr-Functions) is available: `and`, `or`, `not`, `eq`, `ne`, `lt`, `le`, `gt`, `ge`, `len`, `index`, `print`, `printf`, and so on. Murmur adds:

| Function | Signature | Behavior |
| - | - | - |
| `quote` | `quote S` | `S` rendered as a double-quoted, escaped string literal. |
| `lower` | `lower S` | `S` lowercased. |
| `trimSpace` | `trimSpace S` | `S` with leading and trailing whitespace removed. |
| `hasPrefix` | `hasPrefix S PREFIX` | `true` when `S` starts with `PREFIX`. |
| `contains` | `contains S SUBSTR` | `true` when `S` contains `SUBSTR`. |

## Render errors

Templates render with standard `text/template` rules. A template that names a variable not in the [reference](#variable-reference), indexes past the end of a list, or calls a function with the wrong arguments fails to render. The turn then fails before the agent starts, and its error names the persona and the section:

```
the system prompt of persona "bench-lean" does not render for this turn — fix the persona's systemPrompt and send a follow-up: render system prompt section extension.notes: …
```

Fix the persona with `murmur set`, then send the agent a follow-up to run the turn again. To guard against an empty list, test it first: `{{if .Repos}}{{(index .Repos 0).Name}}{{end}}`.

## Validation

Validation runs when the persona is saved. A persona that fails validation is rejected and not written. Validation checks:

* Every section's template (platform `replace` values and extension `template` values) parses as a valid Go template using the function set above.
* A platform section override sets exactly one of `replace` or `remove`; neither set is rejected.
* `remove` is not set to `false`. Leave the key unset to inherit the section instead.
* Every extension `id` matches `[a-z][a-z0-9_]{0,62}` and is unique within the persona.
* Every extension `template` is not an empty string.
* Every key under `systemPrompt`, `systemPrompt.platform`, and each extension is a recognized key — a misspelled key (e.g. `replce` instead of `replace`) fails to save rather than being silently ignored.

Validation cannot see a turn's variables, so a template that parses but names a variable that doesn't exist is saved, and fails the first turn it renders on; see [Render errors](#render-errors).

## Examples

### Replace, remove, and a gated extension

```yaml theme={null}
---
name: bench-lean
model: claude-sonnet-4-6
systemPrompt:
  platform:
    workspace:
      replace: |
        {{if .Repos}}Repos: {{range .Repos}}{{.Name}} at {{.Dir}} ({{.Branch}}); {{end}}{{end}}
    waiver:
      remove: true
  extensions:
    - id: harness_notes
      template: |
        {{if eq .Harness "codex"}}Run the test suite before every commit.{{end}}
---
A lean benchmark persona: a compact workspace summary, no waiver reminder,
and Codex-specific guidance.
```

This persona replaces the `workspace` section with a one-line summary, removes the `waiver` section entirely, and adds an extension that only renders for Codex.

### Minimal persona

```yaml theme={null}
---
name: bare-prompt
systemPrompt:
  platform:
    persona: {remove: true}
    workspace: {remove: true}
    gitPush: {remove: true}
    branchCreated: {remove: true}
    commitSigning: {remove: true}
    ghGateway: {remove: true}
    gitWrapper: {remove: true}
    forkPr: {remove: true}
    prDashboardLink: {remove: true}
    prMergeability: {remove: true}
    waiver: {remove: true}
    structuredOutput: {remove: true}
    opencodeStructuredOutput: {remove: true}
    knowledge: {remove: true}
    eventDelivery: {remove: true}
    completion: {remove: true}
    expectedOutput: {remove: true}
    tasks: {remove: true}
    autonomousTurn: {remove: true}
  extensions:
    - id: instructions
      template: |
        You are a focused code-fixing agent. Make the smallest change that
        resolves the task, then stop.
---
```

This persona removes every platform section, one key each, so the entire platform portion of the prompt is the one extension above; the requester's system prompt and the spawn's appended prompt still follow it if either is set. Without the extension, and on a turn with neither of those, Murmur adds no system prompt at all.

### Extension branching on the model

```yaml theme={null}
---
name: model-aware-reviewer
systemPrompt:
  extensions:
    - id: model_notes
      template: |
        Model family: {{with .ModelFamily}}{{.}}{{else}}unknown{{end}}.
        {{if eq .ModelFamily "haiku"}}Favor small, incremental edits over large rewrites.{{end}}
---
Review the diff for correctness and style.
```

This extension always renders a model-family line ("unknown" when `.ModelFamily` is empty) and adds extra guidance only for the `haiku` family.

## Related

* [agent-persona](https://docs.murmur.dev/catalog/agent-persona.md): the rest of the persona's fields
* [Agent personas](https://docs.murmur.dev/concepts/agent-personas.md): concept overview
* [`murmur set`](https://docs.murmur.dev/cli/set): CLI command for creating and updating catalog resources
* [`murmur get`](https://docs.murmur.dev/cli/get): CLI command for reading catalog resources


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.