> ## Documentation Index
> Fetch the complete documentation index at: https://ahvn.top/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompt

> Callable prompt encoders, Markdown helpers, one-shot layout, workspace storage, translation, and CLI.

<Note>
  *Language is not text, but a mapping from information to expression.*
</Note>

A prompt in HeavenBase is not a string you paste into an LLM call. It is a callable that turns arbitrary input into the text or messages the model actually sees. This page explains that encoder model, the Markdown helpers that format prompt text, the one-shot layout convention, and how `hb.Prompt` persists prompts as Capsule-backed workspace rows with first-class translation.

<br />

## 1. Why Prompt Utilities Exist

Without a prompt system, every LLM call site assembles its own prompt text from raw f-strings. The result is prompt drift: one endpoint formats instructions one way, another endpoint uses different phrasing, and there is no single source of truth for what the prompt should say.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Anti-pattern: prompt text scattered as ad-hoc f-strings
system_prompt = f"You are a helpful assistant. Task: {task}. Use these tools: {tools}"
user_prompt = f"Context: {context}\n\nQuestion: {question}"

# Another file, different style:
instructions = "## Task\n" + task + "\n## Tools\n" + tools
```

This approach treats language as finished text. In practice, a prompt is an **encoder**: it maps structured information — task context, examples, the current instance — into an expression the model can act on. When prompts live as strings, they are hard to test, hard to version, and impossible to localize without duplicating entire templates.

HeavenBase models a prompt as a function that returns rendered text or messages:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

@hb.Prompt(name="demo.greet")
def greet(name: str, *, tr=str) -> str:
    return f"{tr('Hello')}, {name}!"

greet.register()
assert greet("Ada") == "Hello, Ada!"
```

The callable is the prompt. Arguments are the payload. The return value is what the LLM reads. That separation keeps logic in code, data in arguments, and the rendered surface stable enough to test and translate.

A callable encoder is also more flexible than a format-string template. The function body can branch on payload shape, assemble instance-specific sections, call workspace helpers, or even invoke a meta-prompter LLM that drafts the system text from the actual inputs. String templates cover the simple fill-in-the-blanks case; function prompts cover everything else.

<br />

## 2. Prompt as an Encoder

Think of `hb.Prompt` as a named encoder — a callable you register, version, and reload. Format-string prompts are one encoding strategy; Python functions are another. Both compile into Capsule-backed callables and share one runtime path.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

# Function encoder — arbitrary logic in the body
@hb.Prompt(name="demo.greet")
def greet(name: str, *, tr=str) -> str:
    return f"{tr('Hello')}, {name}!"

# Format-string encoder — same Capsule-backed callable underneath
welcome = hb.Prompt("Hello, {name}!", name="demo.welcome")
```

`Prompt` is a special case of [Capsule](/features/capsules). The prompt definition — source code or compiled format string — is captured as a manifest and can be stored as a `sys-prompt` workspace row. At call time, **prompt + payload** produces the serialized text the LLM sees:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
payload = {"name": "Ada", "place": "Tokyo"}
text = welcome(**payload)  # "Hello, Ada!" — the model's input, not the stored encoder
```

That split gives you maximum flexibility. The encoder can assemble Markdown sections, pull workspace context, apply translations, branch on input shape, or chain other prompts — whatever the task needs — while the stored definition stays a versioned, loadable object. Because the underlay is Capsule, prompts are persistable, restorable, and auditable like any other HeavenBase entity.

<Note>
  Construction does not write to a workspace. Call `prompt.register(...)` explicitly, or pass `register=True` when you want decorator-time registration. Scope register and load with `ws=...` when prompts belong to a task workspace.
</Note>

<br />

## 3. Markdown Helpers

Before you reach for `hb.Prompt`, you often need stable Markdown blocks: headings, lists, code fences, structured examples. HeavenBase keeps these in `heavenbase.utils` so generated prompt text stays deterministic across runs, reports, and tests.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import (
    bullet_dict,
    bullet_list,
    code_block,
    example_block,
    file_block,
    json_block,
    md_block,
    md_section,
    numbered_list,
    omission_list,
)

content = md_section(
    title="Task",
    content="Inspect the workspace and report the next action.",
    sections=[
        {"title": "Rules", "content": bullet_list(["Read files first", "Use HeavenBase utilities"])},
        {"title": "Example", "content": code_block("result = hb.HeavenBase.load('demo')", lang="python")},
    ],
)
```

| Helper                                    | Use when                                                   |
| ----------------------------------------- | ---------------------------------------------------------- |
| `md_section(...)`                         | Nested headings with optional body text                    |
| `md_block(...)` / `code_block(...)`       | Fenced blocks with optional language tag                   |
| `bullet_list(...)` / `numbered_list(...)` | Plain or ordered lists                                     |
| `bullet_dict(...)`                        | Key-value pairs as a bullet list                           |
| `json_block(...)` / `file_block(...)`     | Structured or file-attributed payloads                     |
| `example_block(...)`                      | One few-shot example with inputs, output, hints, and notes |
| `omission_list(...)`                      | Long lists truncated with head/tail ellipsis               |

Use these helpers inside function prompts when you want full control over layout. They are composable building blocks, not tied to any single task shape.

<br />

## 4. One-Shot Prompt Layout

For the common case — a single-turn task with system context, a few examples, and a new instance to solve — HeavenBase provides `fast_prompt_section(...)`. It is a convenience wrapper that turns a conventional section layout into OpenAI-style messages using the Markdown helpers above.

The layout follows one principle:

**system + descriptions + examples + instructions + instance**

Each example carries **inputs**, **hints**, **output**, **expected**, and **notes**. The new instance reuses the same shape but marks its output as `TODO`, signaling the model what to produce.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

messages = hb.fast_prompt_section(
    system="You are a concise worker.",
    descriptions={"Task": ["Read the files.", "Write the result."]},
    examples=[{"inputs": {"numbers": [1, 2]}, "output": 3, "hints": "Sum the list."}],
    instructions=["Use tools for filesystem access.", "Return one line."],
    instance={"inputs": {"numbers": [5, 8]}},
)

user_message = messages[-1]["content"]
```

This layout works well for one-shot tasks: classification, extraction, structured generation, and similar patterns where you show a few solved examples and hand the model a fresh input. It is less suited to multi-turn dialogue or open-ended agents that assemble context dynamically across turns — those flows are better served by a custom function prompt.

Pass `separate_system=True` when the target LLM path should receive a dedicated system message instead of one user message containing all sections.

<br />

## 5. Function Prompts

Decorate a Python function when the encoder logic should stay in code and persist as a Capsule-backed callable. The function body is your encoder; call arguments are the payload.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb


@hb.Prompt(name="demo.greet")
def greet(name: str, *, tr=str) -> str:
    return f"{tr('Hello')}, {name}!"


greet.register()
greet.tr.set("Hello", "zz", "HEY")

assert greet("Ada", lang="zz") == "HEY, Ada!"
assert hb.Prompt.load("demo.greet", lang="zz")("Bob") == "HEY, Bob!"
```

Accept `*, tr=str` in the signature when the prompt contains user-facing phrases. HeavenBase injects a bound translation function at call time so localized text flows through the same encoder without forking the function.

### 5.1. Compose Encoders

Function prompts can call other prompts, layout helpers, and LLMs in one encoder. A toy meta-prompter pattern: a one-line format-string prompt drafts the system section; `fast_prompt_section(...)` assembles the one-shot body from examples and the new instance.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

meta_system = hb.Prompt(
    "Write one concise system paragraph for this one-shot task: {task}",
    name="demo.meta_system",
)


@hb.Prompt(name="demo.adaptive_extraction")
def adaptive_extraction(task: str, examples: list, instance: dict, *, tr=str) -> str:
    system = meta_system(task=tr(task))
    messages = hb.fast_prompt_section(
        system=system,
        descriptions={"Task": [tr(f"Extract fields from: {task}")]},
        examples=examples,
        instructions=[tr("Match the example format exactly.")],
        instance=instance,
        tr=tr,
    )
    return messages[-1]["content"]


def adaptive_extraction_with_llm_meta(task: str, examples: list, instance: dict, *, tr=str) -> str:
    meta_llm = hb.LLM(preset="chat")
    system = meta_llm.chat(
        tr(f"Task={task}; instance={instance}"),
        system=tr("Write one system paragraph for the one-shot task in the user message."),
    )
    messages = hb.fast_prompt_section(
        system=system,
        descriptions={"Task": [tr(task)]},
        examples=examples,
        instance=instance,
        tr=tr,
    )
    return messages[-1]["content"]
```

The first variant keeps meta-generation inside HeavenBase prompts. The second delegates system drafting to another LLM while the outer encoder still owns the final layout. Both return the user message content that the downstream task LLM should see.

<br />

## 6. Format-String Prompts

Passing a string to `hb.Prompt(...)` creates the simplest encoder: a compiled format string with placeholder substitution. It uses the same Capsule-backed callable path as function prompts, but the body cannot run arbitrary logic. Use it for short, stable patterns; reach for a function prompt when the encoder needs branching, composition, or meta-generation.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

welcome = hb.Prompt(
    "Hello, {name}! Welcome to {place}",
    name="demo.welcome",
    tr_keys=["place"],
)
welcome.register()
welcome.tr.set("Hello, {name}! Welcome to {place}", "zz", "HEY, {name}! GO {place}")
welcome.tr.set("Tokyo", "zz", "TOKIO")

assert welcome(name="Ada", place="Tokyo", lang="zz") == "HEY, Ada! GO TOKIO"
```

Use a short format string without `tr_keys` when only the full string needs translation:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

welcome = hb.Prompt("Hello, {name}", name="demo.welcome")
text = welcome(name="Ada")
```

<br />

## 7. Load, List, and Version Prompts

Prompts are loaded by dotted name, compact version ref, or row id:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

hb.Prompt.load("demo.greet")
hb.Prompt.load("demo.greet:2")
hb.Prompt.list(prefix="demo.")
hb.Prompt.versions("demo.greet")
hb.Prompt.delete("demo.greet:2")
```

Latest-version selection considers active rows only. Tombstoned rows are hidden from default loads and lists.

Register in a workspace when you want the prompt stored as a `sys-prompt` row:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

ws = hb.HeavenBase("prompt-docs", preset="debug")
welcome = hb.Prompt("Hello, {name}", name="demo.welcome", ws=ws)
welcome.register(ws=ws)
loaded = hb.Prompt.load("demo.welcome", ws=ws)
```

<Warning>
  Prompt rows can restore executable Capsule manifests. Load persisted prompts only from workspaces you trust.
</Warning>

<br />

## 8. Translation as a First-Class Concern

Localization should not require maintaining parallel prompt files. HeavenBase makes translation a first-class part of the prompt surface through the `tr` argument and `prompt.tr`.

Every prompt call resolves language in this order: explicit `lang=...`, the prompt object's bound `lang`, the current `CM_HVNB` config scope at `heavenbase.prompt.lang`, then `main_lang`. The bound `tr` function applies that language to source phrases inside the encoder:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

@hb.Prompt(name="demo.greet")
def greet(name: str, *, tr=str) -> str:
    return f"{tr('Hello')}, {name}!"
```

Pass `tr=...` to `fast_prompt_section(...)` to translate section titles and list items the same way. Function prompts receive `tr` automatically when the signature declares it.

Translation rows live as queryable `sys-translation` entities in the same workspace. Reach them through `prompt.tr`:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
prompt.tr.bind("shared.agent-ui")
prompt.tr.set("Hello", "zz", "HEY", dict_name="shared.agent-ui")
prompt.tr.unbind("shared.agent-ui")
```

Lookup checks exact rows first, then source patterns with `{placeholder}` captures. If no translation is found, HeavenBase returns the source text for `elicit="none"`. `elicit="llm"` is reserved and raises `NotImplementedError` in this release.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

ws = hb.HeavenBase("prompt-tr-docs", preset="debug")
prompt = hb.Prompt("Hello, {name}", name="demo.hello", ws=ws)
prompt.tr.set("Hello, {name}", "zz", "HEY, {name}")

assert prompt(name="Ada", lang="zz") == "HEY, Ada"

hb.CM_HVNB.set("heavenbase.prompt.lang", "zz", scope="heavenbase.demo-zz")

with hb.CM_HVNB.scoped("demo-zz"):
    assert prompt(name="Ada") == "HEY, Ada"
```

`Translation` is available from `heavenbase.extensions.prompt` for lower-level code, but the root `import heavenbase as hb` surface keeps translation under `Prompt.tr`.

<br />

## 9. Persist Agent Instructions

Combine `fast_prompt_section(...)` with `hb.Prompt` when agent instructions should persist with the task workspace. The function encoder wraps the one-shot layout; registration stores the callable as a versioned row.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import heavenbase as hb

ws = hb.HeavenBase("agent-prompts", preset="debug")


def agent_bootstrap(task_dir: str, workspace_id: str, *, tr=str) -> str:
    messages = hb.fast_prompt_section(
        system=tr("You are a task agent using HeavenBase as memory."),
        descriptions={"Context": [f"Workspace: {workspace_id}", f"Task directory: {task_dir}"]},
        instructions=[
            "Inspect files before running commands.",
            "Write structured results to the workspace.",
            "Return one plain final line.",
        ],
        tr=tr,
    )
    return messages[-1]["content"]


hb.Prompt(agent_bootstrap, name="agent.bootstrap", ws=ws).register(ws=ws)
system = hb.Prompt.load("agent.bootstrap", ws=ws)(task_dir="./task", workspace_id=ws.id)
```

<br />

## 10. CLI

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
hb prompt list --prefix demo. --json
hb prompt show demo.greet --json
hb prompt create demo.hello --template "Hello, {name}" --tr-key name
hb prompt render demo.hello --args '{"name":"Ada"}' --lang zz
hb prompt tr-set demo.hello "Hello, {name}" zz "HEY, {name}"
hb prompt tr-list demo.hello --lang zz --json
hb prompt remove demo.hello
```

Function prompt creation is Python-only. The CLI `create` command creates format-string prompts.

<br />

## Summary

* Model prompts as encoders — callable functions that map input data to LLM-facing text, not as static strings.
* `hb.Prompt` is a Capsule special case: prompt + payload produces the final serialized output, and the encoder itself is persistable.
* Prefer function prompts when the encoder needs logic, composition, or meta-generation; use format-string prompts for simple substitution.
* Use Markdown helpers for stable text blocks; use `fast_prompt_section(...)` for the standard one-shot layout when it fits.
* Pass `tr` through encoders and `fast_prompt_section(...)` so localization stays in the same code path as rendering.

<br />

## Further Exploration

<Tip>
  **Related resources:**

  * [Agents](/features/agents) - how prompts fit agent memory and MCP tools.
  * [Capsules](/features/capsules) - how function prompts are captured and restored.
  * [LLM Overview](/features/llm/overview) - how prompts flow into `hb.LLM`.
  * [Configuration](/features/configuration) - prompt language defaults under `heavenbase.prompt.lang` in `CM_HVNB`
</Tip>

<br />
