Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hunvreus/heypi/llms.txt

Use this file to discover all available pages before exploring further.

The agent folder is a plain directory on disk that holds everything shaping your agent’s personality, rules, and capabilities. Heypi reads it at startup via agentFrom() and assembles it into an AgentConfig that Pi uses for every conversation turn. You can start with just two Markdown files and layer in code configuration as your agent grows.

Folder Structure

agent/
├── SOUL.md        ← Identity, role, and voice
├── AGENTS.md      ← Operating rules and standing instructions
├── SYSTEM.md      ← Full runtime-prompt override (rarely needed)
├── skills/        ← Extra Pi skills for this agent
└── extensions/    ← Extra Pi extensions for this agent
File / DirectoryPurposeRequired
SOUL.mdDefines who the agent is—its role, personality, and communication style. Missing file falls back to a concise assistant identity.No
AGENTS.mdStanding operating instructions: what the agent should always or never do. Injected as the agent-level prompt.No
SYSTEM.mdFull runtime-prompt override. Replaces the entire Pi system prompt. Most agents should not need this.No
skills/Directory of extra Pi skill files scoped to this agent only.No
extensions/Directory of extra Pi extension files scoped to this agent only.No

File Examples

SOUL.md

SOUL.md sets the agent’s identity. Keep it focused on role and voice—operating rules belong in AGENTS.md.
agent/SOUL.md
You are a DevOps assistant for the platform engineering team.
You help with infrastructure tasks, incident triage, and deployment workflows.
Communicate concisely. Use plain technical language.
When in doubt, ask a clarifying question rather than making assumptions.
If SOUL.md is missing, Heypi uses this built-in fallback:
You are a concise, practical assistant.
Answer directly and accurately. Say when you are uncertain or blocked.
Use plain language and keep responses focused on the user's goal.

AGENTS.md

AGENTS.md holds standing operating rules—policies the agent follows across every conversation.
agent/AGENTS.md
- Confirm destructive operations (deletes, deploys, restarts) before running them.
- Do not access resources outside the team workspace.
- Prefer idempotent commands. Avoid side-effects unless explicitly asked.
- If a request is ambiguous, ask one focused clarifying question.
- Surface errors with enough context for the user to act on them.

SYSTEM.md

SYSTEM.md replaces the entire Pi system prompt. This is an advanced escape hatch for agents that need complete control over the prompt structure. The vast majority of agents should use SOUL.md and AGENTS.md instead.

Using agentFrom()

agentFrom(folder, options) loads the folder convention and merges any code-level overrides. The folder argument is a path to the agent directory; options lets you supply or override any field programmatically.
import { agentFrom } from "@hunvreus/heypi";

const agent = agentFrom("./agent", {
  model: "openai/gpt-5-mini",
});

Options Reference

OptionTypeDescription
idstringAgent identifier. Defaults to the directory name.
modelstring | ModelConfigModel in provider/name form (e.g. openai/gpt-5-mini) or a ModelConfig object. Required unless HEYPI_MODEL is set.
soulstringInline soul text. Overrides SOUL.md when provided.
promptstringInline agent prompt. Overrides AGENTS.md when provided.
systemPromptstringFull runtime-prompt override. Overrides SYSTEM.md when provided. Bypasses the normal SOUL.md + AGENTS.md composition.
contextAgentContextProvider[]Array of async functions that inject dynamic context blocks into each turn.
skillsstring[]Paths to extra Pi skill directories for this agent. Overrides the skills/ folder when provided.
extensionsstring[]Paths to extra Pi extension directories for this agent. Overrides the extensions/ folder when provided.
toolsAgentToolDefinition[]Custom and core tool definitions for this agent.

Dynamic Context with context

The context option accepts an array of async provider functions. Each provider receives metadata about the current turn and returns a context block that Heypi injects into the Pi session before the user’s message is processed.
import { agentFrom } from "@hunvreus/heypi";

const agent = agentFrom("./agent", {
  id: "devops",
  model: "openai/gpt-5-mini",
  soul: "You are a concise DevOps assistant.",
  prompt: "Prefer safe, auditable actions.",
  context: [
    async ({ provider, channel, actorName }) => ({
      title: "Current chat",
      text: [`Provider: ${provider}`, `Channel: ${channel}`, actorName ? `Sender: ${actorName}` : undefined]
        .filter(Boolean)
        .join("\n"),
    }),
  ],
});
Each provider function receives an AgentContextInput object:
FieldTypeDescription
providerstringAdapter name (e.g. slack, discord, telegram)
channelstringPlatform channel or chat ID
channelNamestring?Human-readable channel name, if available
actorstringUser ID of the message sender
actorNamestring?Display name of the sender, if available
threadstring?Platform thread ID within the channel
threadNamestring?Human-readable thread name, if available
threadIdstringInternal Heypi thread identifier
turnIdstring?Internal identifier for the current turn
inputMessageIdstring?Internal identifier for the triggering message
tracestring?Trace identifier for the current turn, if set
Return a string for a plain text block, or an object with an optional title and required text for a labelled block. Return undefined, null, or false to skip injection for this turn.
Heypi already injects basic provider, channel, thread, and sender context for every turn. You do not need to replicate those. Use context for facts that are specific to your deployment: tenant metadata, current on-call rotation, environment flags, or channel-level policy overrides.

Context vs. Tools

Both context and tools can bring external data into the agent. The right choice depends on what you are providing:

Use context for…

Short, always-relevant facts that every turn should know: current environment name, active feature flags, channel policy, tenant plan, on-call name. Context runs unconditionally on every turn.

Use tools for…

Large datasets, search results, or actions the agent should only fetch when needed. Tools are called on demand by the model and can be gated behind approvals.
If a context provider makes a slow or fallible external call, consider converting it to a tool so the model only incurs the cost when the data is actually needed.

Inline Overrides vs. File Conventions

You can supply everything in code and skip the Markdown files entirely:
agentFrom("./agent", {
  id: "support-bot",
  model: "openai/gpt-4o",
  soul: "You are a friendly customer support agent.",
  prompt: "Always greet the user by name. Escalate unresolved issues after two attempts.",
});
Or you can keep all content in files and pass only model:
agentFrom("./agent", { model: "openai/gpt-5-mini" });
Files and code options are merged, with code values taking precedence over file contents. This means you can store the base identity in SOUL.md and inject a per-deployment override in code without duplicating the file.
SYSTEM.md and the inline systemPrompt option replace the entire Pi system prompt, bypassing the normal SOUL.md + AGENTS.md composition. Use this only if you have a specific reason to control the raw prompt structure.

Build docs developers (and LLMs) love