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.

Heypi’s scope system controls who shares what. A scope determines whether two conversations in different threads, channels, or even adapters look at the same runtime workspace and the same long-lived memory file. Getting this right lets you build agents that share project files across a whole team channel, give each user a private sandbox, or maintain a single global knowledge base — without any special plumbing.

The Four Scopes

channel

Default. One workspace per chat channel (Slack channel, Telegram chat, Discord channel, or webhook channel). Threads within the same channel share files and memory.

user

One workspace per chat actor. Each user gets their own isolated workspace and memory, even in the same channel.

adapter

One workspace for an entire adapter instance. Every accepted chat on that adapter shares files and memory.

agent

One workspace shared across all adapters for this configured agent. The broadest possible sharing.
adapter and agent scopes let one conversation affect another. Use them only when cross-chat sharing is intentional.

What Scope Controls

The top-level scope setting affects:
  • Runtime workspace — the directory where bash, read, write, edit, grep, find, and ls operate.
  • Attachments — inbound files are stored in a scoped attachment tree; a file uploaded in one channel cannot be referenced by another channel under the default channel scope.
Pi sessions and chat history always stay per thread, regardless of scope. That keeps the conversation model predictable while still giving channels or users a shared working area.

Independent Overrides

runtime.scope and memory.scope can each be set independently from the top-level scope:
createHeypi({
  state: { root: "./state" },
  // ...adapters, agent
  scope: "channel",         // top-level: workspace and attachments
  runtime: {
    root: workspace("./workspace"),
    scope: "user",          // override: runtime workspace is per-user
  },
  memory: {
    enabled: true,
    scope: "channel",       // override: memory is per-channel
  },
});

Common Configurations

Everyone in the same channel shares both the workspace and memory. Good for team-shared project state.
createHeypi({
  state: { root: "./state" },
  // ...adapters, agent, runtime
  scope: "channel",
  memory: true,
});

Workspace Layout on Disk

Scoped runtime roots and attachment roots both live under the configured runtime.root, but they are separate trees:
workspace/
  scopes/
    channel/<agent>/<provider>/<team>/<channel>/
    user/<agent>/<provider>/<team>/<actor>/
    adapter/<agent>/<provider>/
    agent/<agent>/
  attachments/
    scopes/
      channel/<agent>/<provider>/<team>/<channel>/
Path segments are percent-encoded before being written to disk (using ~ instead of % for readability). Runtime workspaces follow runtime.scope ?? scope. Memory follows memory.scope ?? scope. Attachments always follow the top-level scope; there is no separate attachments.scope.

Memory

Memory is optional small durable background context — not a transcript database, not a config file, and not a security boundary.

What Belongs in Memory

Short, stable facts and standing rules:
- This channel is for production incidents.
- Deploy approvals require Alice or Bob.
- The staging API lives at https://staging.example.com.
These should never go in memory:
- Full chat logs.
- Temporary task state.
- Secrets or tokens.
- Untrusted instructions copied from random users.

How It Works

When memory is enabled, heypi automatically:
1

Read

Reads the scoped MEMORY.md file from the state directory.
2

Inject

Injects the contents as background context before the model turn.
3

Expose tools

Exposes memory_read, memory_write, memory_replace, and memory_delete to the agent.
4

Validate writes

Validates memory mutations for size, obvious secrets/private keys, and prompt-injection-shaped text.
Validation is a hygiene check, not a security boundary. Do not store secrets, credentials, private data, or policy rules that must be trusted.

writePolicy

writePolicy controls who can mutate memory:
PolicyBehavior
autoThe agent can write, replace, and delete memory freely.
approversOnly turns initiated by approval.approvers can mutate memory.
offMemory is read and injected, but cannot be changed.
Defaults:
ScopeWith approvers configuredWithout approvers
channelapproversauto
userapproversauto
adapterapproversoff
agentapproversoff

Full Memory Configuration

createHeypi({
  state: { root: "./state" },
  // ...adapters, agent, runtime
  scope: "channel",
  memory: {
    enabled: true,
    scope: "user",
    writePolicy: "approvers",
    maxChars: 4000,
  },
});

Approvals and Memory Writes

Approvals do not elevate actor identity. If a non-approver starts a turn and an approver later approves one of its tool calls, the continued turn still belongs to the original requester for writePolicy checks. For team memory where only leads should teach the bot, configure approval.approvers and leave writePolicy unset — it will default to approvers.

Concurrent Writes

Concurrent writes use the filesystem as the source of truth. If two writes race within the same scope, the later write wins.
When memory is enabled, heypi logs the scope and write policy at startup. adapter and agent scopes are logged as warnings because they let one chat affect future answers in other chats. Treat memory like a shared bot-maintained note, not a security boundary.

Build docs developers (and LLMs) love