From Inline Strings to ctx.prompts: A Developer's Guide to HUMΛN Prompt Management
Incident review, Tuesday morning: an agent summarized a contract wrong. Someone asks which prompt version ran. You grep the repo. The system message is an inline string from three PRs ago — no version, no access check, no telemetry. You cannot prove what the model saw.
That is the pain ctx.prompts exists to end.
Scroll-stopper: An inline system string is not a prompt strategy — it is unversioned liability with perfect grammar.
HUMΛN’s ctx.prompts API turns prompts into governed artifacts: authored as files, validated, composed, published, and threaded into provenance. This guide walks the full developer path with real code.
So that when something goes wrong, you can answer “which prompt, which version, which layers” — not “whatever was in that commit.”
Step 1: Author a Prompt File
Prompts live as markdown with YAML frontmatter:
# prompts/orgs/YOUR_ORG/research/document-summary.md
---
id: document-summary
namespace: research
type: task
scope: org
extends: prompt://core/companion.canon.root-persona
inputSchema:
document: { type: string, required: true, description: "Document text to summarize" }
style: { type: string, required: false, default: "concise bullets" }
max_length: { type: string, required: false, default: "200 words" }
version: '1.0.0'
---
Summarize the following document in {{style}} format.
Keep the summary under {{max_length}}.
Focus on:
- Key findings and conclusions
- Action items if any
- Critical data points
Document:
{{document}}
Key elements:
id: Short key (ctx.prompts.load('document-summary'))namespace: Hierarchical grouping (research,legal.contracts)extends: Parent for inheritance — this task inherits the core personainputSchema: Typed variables with required/optional and defaultsversion: Semver — immutable once published
Step 2: Validate and Preview
# Lint all prompts — schema, inheritance, variable consistency
pnpm prompt:lint
# Render with test variables
pnpm prompt:render document-summary \
--var document="The quarterly report shows 23% revenue growth..." \
--var style="executive brief"
# Estimate token count and cost
pnpm prompt:cost document-summary --model gpt-4o
The linter catches missing required variables, undeclared placeholders, broken inheritance, and schema type mismatches.
Step 3: Load and Render in Agent Code
import { AgentHandler } from '@human/agent-sdk';
export const handler: AgentHandler = async (ctx, input) => {
// Delegation checked: agent must have prompt:read:research.document-summary
const prompt = await ctx.prompts.load('document-summary');
const rendered = prompt.render({
document: input.document,
style: input.style ?? 'concise bullets',
});
const result = await ctx.llm.complete({
system: rendered,
prompt: input.document,
promptMetadata: prompt.toCallMetadata(),
});
return result;
};
Under the hood:
load('document-summary')→prompt://org/{orgId}/research.document-summary@active- Delegation verified against
prompt:read:…scopes render()validates variables, applies defaults, substitutes placeholderstoCallMetadata()carries URI, version, and composition into provenance
Step 4: Compose Multi-Layer Prompts
export const handler: AgentHandler = async (ctx, input) => {
const composed = await ctx.prompts.compose([
'root-persona',
'lens-research',
'document-summary',
], {
variables: {
document: input.document,
style: 'structured analysis',
},
});
const result = await ctx.llm.complete({
system: composed.content,
prompt: input.document,
promptMetadata: composed.metadata,
});
return result;
};
Provenance shows persona + lens + task — not “a system prompt was used.”
Step 5: Wire Feedback Signals
export const handler: AgentHandler = async (ctx, input) => {
const prompt = await ctx.prompts.load('document-summary');
const rendered = prompt.render({ document: input.document });
const result = await ctx.llm.complete({
system: rendered,
prompt: input.document,
promptMetadata: prompt.toCallMetadata(),
});
// Length/quality heuristic — matches reference analyzer patterns (not JSON.parse on prose)
if (result.content && result.content.length > 50) {
await ctx.llm.recordPromptFeedback({
provenanceId: result.provenanceId,
signal: 'positive',
source: 'agent',
detail: 'Produced summary with sufficient detail',
});
} else {
await ctx.llm.recordPromptFeedback({
provenanceId: result.provenanceId,
signal: 'negative',
source: 'agent',
detail: 'Summary too short or empty',
});
}
return result;
};
Signals feed the Prompt Refinement Agent — underperforming prompts surface for human review.
Step 6: Publish and Manage Versions
human prompts publish document-summary
# Published: prompt://org/YOUR_ORG/research.document-summary@1.0.0
human prompts versions document-summary
human prompts rollback document-summary --to 1.0.0
human prompts performance document-summary
In development, file-based prompts take effect immediately. In production, the published registry version wins — instant iteration with versioned stability.
Step 7: Effective Prompts (Inheritance Resolution)
const effective = await ctx.prompts.getEffective('document-summary');
if (effective) {
// effective.content = merged layers
// effective.layers = [{scope: 'core', ...}, {scope: 'org', ...}]
console.log(`Resolved ${effective.layers.length} layers`);
}
Migration: Inline to Managed
Before — inline string, no provenance identity.
After — load → render → toCallMetadata → optional recordPromptFeedback.
You gain version control, delegation-based access, schema validation, token estimates, full provenance, and the telemetry loop — for a few extra lines.
Quick Reference: ctx.prompts API
| Method | Description | Delegation |
|---|---|---|
load(id) |
Load by short key or URI | prompt:read:{key} |
compose(ids, opts) |
Compose a stack | prompt:read for each |
getEffective(key) |
Resolve inheritance | prompt:read for chain |
list(filter?) |
List accessible prompts | Filtered by prompt:read |
estimateTokens(id) |
Estimate tokens | prompt:read:{key} |
| Method on LoadedPrompt | Description |
|---|---|
render(variables) |
Substitute and validate |
toCallMetadata() |
PromptCallMetadata for LLM calls |
Marketplace certification
Marketplace agents declare agent_prompt_contributions; listings show prompt_certification (hashes + trust boundary), not prompt bodies. See Certifying marketplace prompts without exposing IP.
You write the prompt once. The system makes it better over time — with humans still approving what ships.
Go deeper
- Product: Developers, Platform
- Docs: Prompts CLI, Introduction
- Community: Protocol-level prompt management, Self-improving prompt loop, Certifying marketplace prompts
Prompt Management — Part 1 of 5