Skip to main content
HUMΛN
Developer
Developer

From Inline Strings to ctx.prompts: A Developer's Guide to HUMΛN Prompt Management

HUMΛN Team··10 min·Technical (Developers)

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 persona
  • inputSchema: Typed variables with required/optional and defaults
  • version: 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:

  1. load('document-summary')prompt://org/{orgId}/research.document-summary@active
  2. Delegation verified against prompt:read:… scopes
  3. render() validates variables, applies defaults, substitutes placeholders
  4. toCallMetadata() 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.
AfterloadrendertoCallMetadata → 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