@zihanw/pi-forge
Pi extension for prompt stack and agent profile management.
Package details
Install @zihanw/pi-forge from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@zihanw/pi-forge- Package
@zihanw/pi-forge- Version
0.1.0- Published
- Jun 13, 2026
- Downloads
- not available
- Author
- zihanw
- License
- MIT
- Types
- extension
- Size
- 80.7 KB
- Dependencies
- 0 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-forge
Pi extension package for prompt stack and agent profile management. This first milestone implements file-backed prompt stacks.
Package setup
This repository is a Pi package. Its package manifest exposes ./src/index.ts as the extension entrypoint.
For local development in this checkout, .pi/settings.json points at the package root:
{
"packages": [".."]
}
After starting Pi in this directory, trust the project and use /reload if needed.
After publishing under your chosen npm package name, install it with:
pi install npm:@zihanw/pi-forge
Prompt stacks
Prompt stacks live in:
.pi/prompt-stacks/*.json
Activation rules:
- A restored
/preset use <id>selection is used first when that stack still exists and has no validation errors. - A restored
/preset use noneselection disables prompt stack replacement. .pi/prompt-stacks/default.jsonauto-activates when present unless the stack sets"autoActivate": false.- Otherwise, the first stack with
"autoActivate": trueis used. /preset use <id>switches stacks for the session and persists that choice./preset use nonedisables prompt stack replacement and persists that choice.
When a stack is active, pi-forge replaces Pi's default system prompt by default and rebuilds the first provider request for each user message around a movable chat-history slot. Tool-result follow-up turns use Pi's natural context so post-history instructions are not repeatedly re-appended after every tool call.
Commands
/preset list
/preset use <id|none>
/preset preview [id]
/preset validate [id]
/preset reload
/preset vars [set <name> <value>|get <name>|clear [name]]
/preset import-silly <path> [character_id]
/intercept
SillyTavern preset import
Import a SillyTavern preset JSON into .pi/prompt-stacks/<id>.json and write a migration report to .pi/forge/import-reports/<id>.md:
/preset import-silly <path> [character_id]
If a preset contains multiple prompt_order entries, pass the desired character_id. Imported stacks are created with autoActivate: false; activate one with /preset use <id> after reviewing the report.
Agent tools
forge_set_var
Sets a persistent session variable. Only variables starting with agent. can be written by the agent; other variables are read-only. Useful for cross-turn state tracking in roleplay (character mood, story progress) or coding (task checkpoints, discovered facts).
When the variables slot is active in a prompt stack, the agent sees its variable state and can update it. Without the slot, variables still work for macro substitution but the agent won't have a structured view of the state.
Stack format
Minimal example:
{
"schemaVersion": 1,
"type": "pi-forge.prompt-stack",
"id": "default",
"autoActivate": true,
"mode": "replace",
"items": [
{
"kind": "block",
"id": "main-role",
"enabled": true,
"role": "system",
"content": "You are a precise coding assistant."
},
{
"kind": "slot",
"id": "tools",
"enabled": true,
"role": "system",
"slot": "tools"
},
{
"kind": "block",
"id": "history-open",
"enabled": true,
"role": "user",
"content": "<conversation_context>"
},
{
"kind": "slot",
"id": "chat-history",
"enabled": true,
"slot": "chat-history"
},
{
"kind": "block",
"id": "history-close",
"enabled": true,
"role": "user",
"content": "</conversation_context>"
}
]
}
Items
Blocks
Static text:
{
"kind": "block",
"id": "post-history-nudge",
"enabled": true,
"role": "user",
"content": "Reason carefully about the latest request before answering."
}
Slots
Live Pi runtime content:
{
"kind": "slot",
"id": "skills",
"enabled": true,
"role": "system",
"slot": "skills"
}
Supported slots:
chat-history— current Pi conversation context from the sessiontools— active tool names and prompt snippetstool-guidelines— active tool guidanceskills— loaded Pi skillsproject-context— project instructions/context filesappend-system-prompt— user-provided append system prompt textvariables— static/session/turn variables rendered as structured XMLdatecwddate-cwdactive-modelpi-docs
Variables slot
Renders variable state as structured XML:
<prompt_variables>
<static>
<char>Agent</char>
</static>
<session>
<agent.mood>happy</agent.mood>
<agent.progress>step 3</agent.progress>
</session>
<turn>
<recent>just happened</recent>
</turn>
</prompt_variables>
Options:
{
"includeStatic": true,
"includeSession": true,
"includeTurn": true
}
Use this slot to give the agent visibility into mutable state that it can also update via forge_set_var.
Roles
systemitems are compiled into the replacement system prompt.useritems are inserted as ephemeral user messages.assistantitems are inserted as ephemeral assistant messages.customitems are inserted as hidden Pi custom messages and converted to user context by Pi.
chat-history expands to the live conversation at its position. By default, only the first enabled chat-history slot is expanded.
To omit the latest user message from a chat history slot, use:
{
"kind": "slot",
"id": "chat-history",
"enabled": true,
"slot": "chat-history",
"options": {
"includeLastUserMessage": false
}
}
This is useful for SillyTavern-style stacks that re-insert {{lastUserMessage}} later as a post-history instruction.
To intentionally duplicate history:
{
"context": {
"allowDuplicateChatHistory": true
}
}
Macros
Supported macros in block content:
{{cwd}}{{date}}{{lastUserMessage}}{{selectedTools}}/{{tools}}{{activeModel}}- custom variables from the stack
variablesobject, e.g.{{char}}
Variables
Static variables come from the stack file:
"variables": {
"char": "Assistant",
"user": "USER"
}
Mutable turn variables are cleared for each user message:
{{setvar::name::value}}
{{setturnvar::name::value}}
{{getvar::name}}
{{getturnvar::name}}
{{var::name}}
{{clearvar::name}}
Mutable session variables persist in the Pi session as extension state:
{{setsessionvar::name::value}}
{{setvar::session::name::value}}
{{getsessionvar::name}}
{{getvar::name}}
{{clearsessionvar::name}}
{{clearvar::session::name}}
Lookup order for {{getvar::name}}, {{var::name}}, and bare {{name}} is:
- turn variables
- session variables
- static stack variables
setvar macros output empty text. Unknown macros warn by default and are kept literally.