How to shape agent behavior with a system prompt
A system prompt tells the model who it is and how it should behave — before any task arrives. In Murmur, the system prompt is injected as the system parameter on every inference call, not just the first turn, so the agent's persona and constraints are reinforced throughout a multi-turn session. This guide covers the two ways to set a system prompt and when to choose each.
The relevant manifest options are:
| Option | Controls |
|---|---|
| inference.system_prompt | Inline text injected as the system prompt on every turn |
| inference.system_prompt_file | Path to a file whose content is used as the system prompt |
| inference.system_prompt_artifact | Name of a skill artifact whose skill.md is read at launch and used as the system prompt |
Step 1 — add an inline system prompt
Create a murmur.yaml file with inference.system_prompt set to the text you want the model to receive:
name: my-agent
version: "0.1.0"
artifacts:
- name: murmur-driver-anthropic
version: "1.0.0"
runtime: driver
inference:
transport: http
endpoint: https://api.anthropic.com
model: claude-sonnet-5
api_key: ${ANTHROPIC_API_KEY}
driver:
artifact: murmur-driver-anthropic
system_prompt: |
You are a concise data analyst. Always respond with:
1. A one-sentence summary of what you found.
2. A bullet list of key numbers.
Never include preamble or closing remarks.
name: my-agent
version: "0.1.0"
artifacts:
- name: murmur-driver-openai
version: "1.0.0"
runtime: driver
inference:
transport: http
endpoint: https://api.openai.com
model: o3-mini-high
api_key: ${OPENAI_API_KEY}
driver:
artifact: murmur-driver-openai
system_prompt: |
You are a concise data analyst. Always respond with:
1. A one-sentence summary of what you found.
2. A bullet list of key numbers.
Never include preamble or closing remarks.
name: my-agent
version: "0.1.0"
artifacts:
- name: murmur-driver-deepseek
version: "1.0.0"
runtime: driver
inference:
transport: http
endpoint: https://api.deepseek.com
model: deepseek-r1
api_key: ${DEEPSEEK_API_KEY}
driver:
artifact: murmur-driver-deepseek
system_prompt: |
You are a concise data analyst. Always respond with:
1. A one-sentence summary of what you found.
2. A bullet list of key numbers.
Never include preamble or closing remarks.
The | block scalar preserves newlines. The runtime passes this text verbatim as the system field on every POST to the inference driver — including turn 2, turn 3, and beyond.
Step 2 — install dependencies
mur install
Different ways to install artifacts
mur install needs to know where to fetch artifacts from. You have two options:
Option A — configure a registry source in ~/.murmur/config.yaml:
registry:
default: official
sources:
- name: official
type: github
repo: <owner>/<repo>
token: "${GITHUB_TOKEN}"
Then install by artifact name and version:
mur install <artifact-name@version>
Option B — pass a full GitHub reference and skip configuration entirely:
mur install github:<username>/<repo>@<tag>
See Installing artifacts to learn more.
Step 3 — load the prompt from a file
For longer prompts, or when you want to version the prompt independently from the manifest, use system_prompt_file:
inference:
...
system_prompt_file: conventions.md
The path is relative to the directory containing murmur.yaml, not to the session workdir. A typical layout:
my-capsule/
murmur.yaml
conventions.md ← system prompt lives here
murmur.lock
The runtime reads the file once at launch, before any inference call. If the file is missing or unreadable, mur run exits with error[E-RUN-009] before the session starts — you will never silently run a session with the wrong prompt.
conventions.md:
You are a strict code reviewer operating in a CI pipeline.
Rules:
- Only flag issues that violate the project's style guide.
- Output one finding per line in the format: `FILE:LINE — REASON`.
- If there are no issues, output exactly: `LGTM`.
- Do not explain, justify, or suggest alternatives.
Step 4 — load the prompt from a skill artifact
If your system prompt is already packaged as a skill artifact, you can bind it directly instead of duplicating the content in a separate file. Set inference.system_prompt_artifact to the name of the skill:
artifacts:
- name: code-review-conventions
version: "1.0.0"
runtime: skill
inference:
...
system_prompt_artifact: code-review-conventions
At launch, the runtime reads workdir/tools/code-review-conventions/skill.md and uses that content as the system prompt for every inference turn. The skill is not added to the callable tool inventory — it is already in context and would double-inject if called.
MURMUR.md notes the binding so the agent is aware:
## Installed Skills
- **code-review-conventions** — Project PR review conventions *(bound as system prompt — already in context, not separately callable)*
Validation happens at parse time:
- The named artifact must be declared in
artifacts:— if not,mur runexits with a clear error before starting. - It must declare
prompt_payload: true—runtime: skilldefaults to this, so skills work with no extra declaration; atool,driver, orhookartifact must setprompt_payload: trueexplicitly to be eligible, and one that doesn't is a manifest error. Seeinference.system_prompt_artifact. - The skill's
skill.mdmust be readable at launch — a missing file exits witherror[E-RUN-009].
Step 5 — choose between inline, file, and artifact
Use system_prompt (inline) |
Use system_prompt_file |
Use system_prompt_artifact |
|---|---|---|
| Short prompts (< 10 lines) | Long or structured prompts | Persona already packaged as a skill |
| Single-file manifests | Prompts version-controlled separately | Capsules that want to distribute both the skill and the persona together |
| Prototyping and quick experiments | Personas shared across multiple manifests | Reuse the same skill content both as a persona and (in other capsules) as a callable |
All three options are mutually exclusive — setting more than one in the same manifest is a parse error (error[E-MAN-003]).
Step 6 — verify the system prompt is applied
Create a task.md file with a question designed to reveal the persona:
Who are you and what are your rules?
Run the capsule:
mur run
murmur: url localhost:52222
session: ses_019ed2af53da75c2aefee84ee10c34af
After the session completes, read the agent's output:
cat workdir/<session_id>/out/result.txt
Replace <session_id> with the value printed by mur run. For the data analyst persona above, you would expect exactly one summary sentence and a bullet list — no preamble, no closing remarks.
The session trace records which prompt was in effect. Every session_start line in workdir/<session_id>/trace.jsonl carries system_prompt_source ("manifest", "cli" or "none") and system_prompt_sha256, the hash of the prompt as resolved:
mur trace show
Different ways to identify a session
mur trace show with no argument reads the most recent session:
mur trace show
To name another one, pass an ordinal counting back from the newest (@2), the last 4 or more
characters of its ID (3e4b), the full ID, or a path to its trace.jsonl:
mur trace show @2
mur trace show 3e4b
mur trace show ses_6801f81dd28b4a9daf434e8324c4793e
mur trace show path/to/trace.jsonl
Use --workdir <path> if your session directories are not under ./workdir. Every command
that names a session takes the same addresses — see
Session addresses.
Other trace exploration commands
mur trace has four subcommands for exploring session output:
mur trace show — print the full trace for a session to the terminal.
mur trace steps — show a turn-by-turn summary of what the agent did in a session. Pass --verbose to include a truncated summary of each tool's input.
mur trace diff — compare the traces of two sessions side by side, or with no arguments the two most recent. Useful for spotting behavioural regressions between runs.
mur trace report — generate a structured summary report from a session's trace. Covers token usage, tool calls, latency, and other session-level metrics.
The prompt text is recorded only when you ask for it
system_prompt_source and system_prompt_sha256 are always written, and the hash alone tells you whether two sessions ran with the same prompt. To read the prompt itself, set trace.capture: content in the manifest and cat <session_id>/blobs/<system_prompt_sha256>. See Session trace schema.
If the agent is ignoring your constraints, add a more explicit rule to the system prompt and re-run.
Step 7 — use system_prompt_file for a shared persona
When multiple capsules need the same base persona, factor it into a shared file:
personas/
analyst.md
reviewer.md
capsule-a/
murmur.yaml → system_prompt_file: ../personas/analyst.md
capsule-b/
murmur.yaml → system_prompt_file: ../personas/analyst.md
Both manifests reference the same file. Updating the persona in one place updates all capsules that share it. The path is resolved relative to each manifest's directory, so a relative .. path works as long as the directory layout is consistent.
Step 8 — override the prompt for a single run
To try a different persona without editing murmur.yaml, pass mur run --system-prompt:
mur run --task task.md --system-prompt "You are a terse code reviewer. Reply with numbered findings only."
murmur: url localhost:52222
session: ses_019ed2af53da75c2aefee84ee10c34af
status: ok
The flag replaces whichever of the three manifest fields the capsule declared — inline, file, or artifact — and applies just as well to a manifest that declared none. It never writes to murmur.yaml: the next run without the flag is back to the manifest's own prompt.
Two consequences worth knowing:
- The value is trimmed. An empty or whitespace-only value clears the prompt entirely, so the run sends no
systemparameter beyond the runtime's own identity block — useful for checking how much of the agent's behaviour the persona is responsible for. - Overriding a
system_prompt_artifactreleases that skill back into the callable tool inventory, since it is no longer already in context.MURMUR.mdlists it as callable for that run.
The trace records the override: session_start.system_prompt_source reads "cli", and system_prompt_sha256 is the hash of the trimmed value you passed.
On a capsule with no inference: block there is no prompt to override, and the run fails with error[E-IO-003] before anything is staged.
Summary
| Setting | Behaviour |
|---|---|
inference.system_prompt: \| |
Inline text; injected verbatim on every inference turn |
inference.system_prompt_file: path.md |
File content; read once at launch; path is relative to manifest directory |
inference.system_prompt_artifact: name |
Skill artifact's skill.md read at launch and used as system prompt; skill not separately callable |
| More than one field set simultaneously | Parse error error[E-MAN-003] |
| File or skill.md missing or unreadable | Launch error error[E-RUN-009] — session never starts |
| No field set | No system parameter is sent; model receives no system prompt |
mur run --system-prompt "text" |
Replaces whichever field the manifest set, for that run only; value is trimmed; empty value clears the prompt; murmur.yaml untouched |
mur run --system-prompt on a manifest with no inference: |
CLI error error[E-IO-003] — nothing is staged |
session_start.system_prompt_source in trace.jsonl |
"manifest" | "cli" | "none", alongside system_prompt_sha256; the prompt text itself at blobs/<system_prompt_sha256> only under trace.capture: content |