Skip to main content

Prompt Templates

Last verified against code: 2026-03-01

Summary

Prompt Templates is a Layer 0-1 primitive that defines agent behavior through Go text/template in Markdown. All role-specific behavior is user-supplied configuration — the SDK contains zero hardcoded role names. Templates are rendered at agent startup with a PromptContext that provides city, agent, rig, and git metadata, making every agent prompt dynamically customized to its deployment context.

Key Concepts

  • Prompt Template: A Markdown file with Go template directives (.md.tmpl extension). Each agent’s prompt_template config field points to one. Templates define the agent’s behavioral specification: what it does, how it finds work, how it communicates.
  • PromptContext: The data available to templates during rendering. Includes CityRoot, AgentName (qualified: rig/agent-1), TemplateName (config name: agent for pool template), RigName, WorkDir, IssuePrefix, Branch, DefaultBranch, WorkQuery, SlingQuery, and custom Env vars from agent config.
  • Shared Templates: Reusable template partials in a shared/ directory next to the prompt templates. Automatically loaded and available via {{template "name" .}}. Used for cross-agent conventions like command glossaries and architecture context.
  • Template Functions: Three built-in functions: cmd (binary name), session (compute session name for an agent), basename (extract base name from qualified name).

Architecture

  Agent Config                 Template File
  ┌──────────────┐            ┌──────────────────┐
  │prompt_template│───────────▶│ prompts/agent.md  │
  │  = "prompts/ │            │  .tmpl            │
  │   agent.md   │            └────────┬──────────┘
  │   .tmpl"     │                     │
  └──────────────┘            ┌────────▼──────────┐
                              │ shared/ partials   │
                              │  (auto-loaded)     │
  PromptContext               └────────┬──────────┘
  ┌──────────────┐                     │
  │ CityRoot     │            ┌────────▼──────────┐
  │ AgentName    │───────────▶│  renderPrompt()   │
  │ RigName      │            │  (text/template)  │
  │ WorkDir      │            └────────┬──────────┘
  │ WorkQuery    │                     │
  │ SlingQuery   │                     ▼
  │ Env          │              Rendered Markdown
  └──────────────┘              (agent's prompt)

Data Flow

  1. Controller resolves agent config including prompt_template path
  2. renderPrompt() reads the template file from the city directory
  3. Shared templates from the sibling shared/ directory are loaded first, making them available via {{template "name" .}}
  4. The main template is parsed last (its body becomes the root)
  5. buildTemplateData() merges Env (lower priority) with SDK fields (higher priority) into a single map[string]string
  6. Template executes against the merged data map
  7. On parse/execute error, logs warning to stderr and returns raw text (graceful fallback — never blocks agent startup)

Key Types

  • PromptContext — template data struct. Defined in cmd/gc/prompt.go.
  • renderPrompt() — reads, parses, and renders a template. Returns empty string if template path is empty or file doesn’t exist. Defined in cmd/gc/prompt.go.
  • buildTemplateData() — merges Env with SDK fields. SDK fields override Env keys. Defined in cmd/gc/prompt.go.
  • promptFuncMap() — template function registration. Defined in cmd/gc/prompt.go.

Invariants

  1. No hardcoded role names. Templates define roles. The SDK never references specific role names like “mayor” or “deacon”. If a Go file contains a role name, it’s a bug.
  2. SDK fields override Env. If an agent’s Env map contains a key that collides with an SDK field (e.g., CityRoot), the SDK value wins.
  3. Graceful fallback on error. Parse or execute errors produce the raw template text, not an empty string. Agents always get a prompt.
  4. Missing template returns empty. If prompt_template is empty or the file doesn’t exist, renderPrompt() returns "" without error.
  5. Shared templates load from sibling directory. Only .md.tmpl files in the shared/ subdirectory next to the template are loaded. No recursive traversal.

Interactions

Depends onHow
internal/fsysReads template files from disk
internal/configAgent.PromptTemplate path, Agent.Env vars
internal/gitDefaultBranch for PromptContext
internal/agentSessionNameFor() via session template function
Depended on byHow
cmd/gc/cmd_prime.gogc prime outputs rendered prompt
cmd/gc/providers.goRendered prompt passed to agent on start
Agent hooksHook calls gc prime to get the prompt

Code Map

  • cmd/gc/prompt.go — PromptContext, renderPrompt, buildTemplateData, promptFuncMap (141 LOC)
  • cmd/gc/cmd_prime.gogc prime command (outputs rendered prompt)
Template files are user-supplied, not SDK code. See example templates in examples/gastown/packs/gastown/prompts/.

Configuration

[[agent]]
name = "worker"
prompt_template = "prompts/worker.md.tmpl"
[agent.env]
CUSTOM_VAR = "value"    # available as {{.CUSTOM_VAR}} in template

Template Variables

VariableSourceExample
CityRootCity directory path/home/user/my-city
AgentNameQualified agent namefrontend/worker-1
TemplateNameConfig template nameworker
RigNameRig name (empty for city agents)frontend
WorkDirAgent working directory/projects/frontend
IssuePrefixRig bead ID prefixFE
BranchCurrent git branchfeature-x
DefaultBranchDefault branchmain
WorkQueryWork discovery commandbd ready --assignee=...
SlingQueryWork routing commandgc sling ...

Template Functions

FunctionUsageReturns
cmd{{cmd}}Binary name (gc)
session{{session .AgentName}}Session name for agent
basename{{basename .AgentName}}Base name from qualified name

Testing

  • cmd/gc/prompt_test.go — unit tests for renderPrompt, template function behavior, Env override semantics
  • examples/gastown/gastown_test.go — TestPromptFilesExist, TestAllPromptTemplatesExist (validates all referenced templates exist)

Known Limitations

  • No template inheritance. Templates compose via shared/ partials and {{template}}, but there’s no extends mechanism. Each agent prompt is self-contained.
  • Flat data model. buildTemplateData() merges everything into map[string]string. No nested data, no typed values, no arrays.
  • No runtime re-rendering. Prompts are rendered once at agent startup. Config changes require agent restart to take effect.

See Also

  • Agent Protocol — how rendered prompts are delivered to agents via runtime.Provider
  • Config System — how Agent.PromptTemplate and Agent.Env are resolved through override layers
  • Glossary — authoritative definitions of prompt template, nudge, and related terms
Last modified on March 20, 2026