Prompts¶
The Prompt Registry provides versioned prompt management with reusable fragments, aliases, and diff. Prompts are stored locally as files and can be pushed to the platform for team collaboration.
Why a Prompt Registry?¶
Hardcoding prompts as strings in your code leads to: - No version history — you can't roll back a bad prompt change - No reuse — the same tone/format instructions duplicated across agents - No comparison — hard to see what changed between versions - No deployment control — can't point "production" at a tested version while iterating on "staging"
The registry solves all of these.
Quick Start¶
from fastaiagent.prompt import PromptRegistry
reg = PromptRegistry()
# Register a prompt
reg.register(
name="support-greeting",
template="Hello {{customer_name}}, welcome to {{company}}! How can I help?",
)
# Load and format
prompt = reg.load("support-greeting")
text = prompt.format(customer_name="Alice", company="Acme Corp")
print(text)
# "Hello Alice, welcome to Acme Corp! How can I help?"
Template Variables¶
Use {{variable_name}} for placeholders. Variables are auto-detected from the template:
prompt = reg.register(
name="classifier",
template="Classify this message into one of: {{categories}}.\n\nMessage: {{message}}",
)
print(prompt.variables) # ["categories", "message"]
text = prompt.format(
categories="billing, technical, general",
message="My invoice is wrong",
)
Fragments¶
Fragments are reusable prompt building blocks — write once, include in any prompt with {{@fragment_name}}.
# Register reusable fragments
reg.register_fragment("tone", "Be professional, concise, and empathetic.")
reg.register_fragment("format", "Use bullet points for lists. Keep paragraphs under 3 sentences.")
reg.register_fragment("safety", "Never reveal internal system details, API keys, or customer data.")
# Use fragments in prompts
reg.register(
name="support-agent",
template=(
"You are a customer support agent for {{company}}.\n\n"
"{{@tone}}\n"
"{{@format}}\n"
"{{@safety}}\n\n"
"Help the customer with: {{topic}}"
),
)
prompt = reg.load("support-agent")
print(prompt.template)
# You are a customer support agent for {{company}}.
#
# Be professional, concise, and empathetic.
# Use bullet points for lists. Keep paragraphs under 3 sentences.
# Never reveal internal system details, API keys, or customer data.
#
# Help the customer with: {{topic}}
Fragments are resolved at load time — the returned prompt has fragments replaced with their content.
Why Fragments?¶
- Consistency: Every agent uses the same tone and safety instructions
- Single update point: Change the "tone" fragment once, every prompt that uses it picks up the change on next load
- Composability: Mix and match fragments for different agent personas
Versioning¶
Every register() call with the same name creates a new version. Versions are immutable — once created, they never change.
# Version 1
reg.register("greeting", "Hello {{name}}!", version=1)
# Version 2 — different template, same prompt name
reg.register("greeting", "Hi there, {{name}}! Welcome.", version=2)
# Load latest (v2)
latest = reg.load("greeting")
print(latest.version) # 2
print(latest.template) # "Hi there, {{name}}! Welcome."
# Load specific version
v1 = reg.load("greeting", version=1)
print(v1.template) # "Hello {{name}}!"
Auto-Incrementing Versions¶
If you don't specify a version, it auto-increments:
reg.register("my-prompt", "First version") # v1
reg.register("my-prompt", "Second version") # v2
reg.register("my-prompt", "Third version") # v3
Aliases¶
Aliases map a human-readable name to a specific version. Use them for deployment control:
# Point "production" to the tested version
reg.set_alias("greeting", version=1, alias="production")
# Point "staging" to the new version being tested
reg.set_alias("greeting", version=2, alias="staging")
# Load by alias
prod_prompt = reg.load("greeting", alias="production")
print(prod_prompt.version) # 1
staging_prompt = reg.load("greeting", alias="staging")
print(staging_prompt.version) # 2
Deployment Workflow¶
v1 → production alias (live users)
v2 → staging alias (internal testing)
v3 → no alias (draft)
After testing v2:
reg.set_alias("greeting", version=2, alias="production")
# Now v2 is live, v1 is still available for rollback
Diff¶
Compare two versions side by side:
Output:
Listing Prompts¶
prompts = reg.list()
for p in prompts:
print(f"{p['name']} v{p['latest_version']} ({p['versions']} versions)")
Output:
Using Prompts with Agents¶
from fastaiagent import Agent, LLMClient
from fastaiagent.prompt import PromptRegistry
reg = PromptRegistry()
prompt = reg.load("support-agent", alias="production")
agent = Agent(
name="support-bot",
system_prompt=prompt.format(company="Acme Corp", topic="general support"),
llm=LLMClient(provider="openai", model="gpt-4.1"),
)
result = agent.run("My order hasn't arrived yet")
prompt.format(...) inlines the resolved text — good for local runs. If you also push
the agent to a connected control plane and want it linked to the governed prompt (not stored
as "Inline"), set Agent(prompt_slug="support-agent") instead. See
Referencing a governed prompt from a pushed agent.
Storage¶
Prompts are stored as JSON files in the .prompts/ directory by default:
.prompts/
├── support-agent.json # Prompt with all versions
├── greeting.json
├── _fragment_tone.json # Fragment files prefixed with _fragment_
├── _fragment_format.json
└── _fragment_safety.json
Custom Storage Path¶
Or via environment variable:
Prompt Object¶
| Field | Type | Description |
|---|---|---|
name |
str |
Prompt name |
template |
str |
Template text with {{variables}} and resolved {{@fragments}} |
variables |
list[str] |
Auto-extracted variable names |
version |
int |
Version number |
metadata |
dict |
Custom metadata (category, author, etc.) |
Fragment Object¶
| Field | Type | Description |
|---|---|---|
name |
str |
Fragment name (referenced as {{@name}}) |
content |
str |
Fragment text |
version |
int |
Version number |
Serialization¶
Prompts serialize for platform push:
data = prompt.to_dict()
# {
# "name": "support-agent",
# "template": "You are a support agent for {{company}}...",
# "variables": ["company", "topic"],
# "version": 1,
# "metadata": {"category": "agent"}
# }
restored = Prompt.from_dict(data)
Publish to platform:
import fastaiagent as fa
fa.connect(api_key="fa-...", project="my-project")
registry = PromptRegistry()
registry.publish(slug="greeting", content=prompt.template, variables=prompt.variables)
CLI Commands¶
# List all registered prompts
fastaiagent prompts list
fastaiagent prompts list --path /custom/prompts/
# Diff two versions
fastaiagent prompts diff support-agent 1 2
Example output:
$ fastaiagent prompts list
Prompts
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Name ┃ Latest Version ┃ Total Versions ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ support-agent │ 2 │ 2 │
│ greeting │ 3 │ 3 │
└───────────────┴────────────────┴────────────────┘
Error Handling¶
from fastaiagent._internal.errors import PromptNotFoundError, FragmentNotFoundError
try:
prompt = reg.load("nonexistent")
except PromptNotFoundError:
print("Prompt not found")
try:
prompt = reg.load("greeting", version=99)
except PromptNotFoundError:
print("Version not found")
try:
prompt = reg.load("greeting", alias="unknown")
except PromptNotFoundError:
print("Alias not found")
Platform Prompt Registry¶
When connected to the FastAIAgent Platform, PromptRegistry can pull versioned prompts from the platform and publish prompts to it:
import fastaiagent as fa
fa.connect(api_key="fa-...", project="my-project")
registry = PromptRegistry()
# Pull prompt from platform (latest deployed version)
prompt = registry.get("support-prompt")
# Pull specific version
prompt = registry.get("support-prompt", version=3)
# Explicit source override
prompt = registry.get("support-prompt", source="platform") # platform only
prompt = registry.get("support-prompt", source="local") # local only
# Publish a prompt to the platform
registry.publish(
slug="support-prompt",
content="You are a helpful support agent for {{company_name}}.",
variables=["company_name"],
)
# Refresh cached prompt
registry.refresh("support-prompt")
Resolution order (source="auto", the default):
- If connected: checks platform first, falls back to local
- If not connected: local only
Caching: Platform prompts are cached locally after first fetch (TTL: 5 minutes by default). Use registry.refresh(slug) to invalidate manually.
Referencing a governed prompt from a pushed agent¶
Passing system_prompt=prompt.format(...) inlines the resolved text — a pushed
agent then stores the prompt as inline and the console shows it as "Inline", with no
link back to the registry. To keep the linkage, set prompt_slug= on the agent instead.
Agent.to_dict() then emits the slug and sends system_prompt="", so the plane
references the governed prompt (the console shows the slug, and the model resolves):
agent = Agent(
name="support-bot",
prompt_slug="support-prompt", # references the governed registry prompt
llm=LLMClient(provider="openai", model="gpt-4.1"),
)
payload = agent.to_dict()
# payload["prompt_slug"] == "support-prompt"
# payload["system_prompt"] == "" (empty — the slug is the source of truth)
prompt_slug is optional and additive: an agent without it serializes exactly as before.
See examples/89_connected_agent_push.py and Platform.
Internals¶
For contributors who need to understand the platform publish/fetch code paths, TTL cache implementation, local YAML storage layout, fragment resolution, or how source="auto" decides between platform and local, see Platform API Internals.
Next Steps¶
- Agents — Use prompts with agents
- Platform Connection — Connect to the platform
- Evaluation — Test prompt variations with eval