@zihanw/pi-forge 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +303 -184
- package/README.zh-CN.md +405 -0
- package/examples/default-prompt-stack.json +44 -0
- package/package.json +2 -1
- package/src/compiler.ts +163 -33
- package/src/index.ts +761 -52
- package/src/loader.ts +83 -1
- package/src/sillytavern-importer.ts +83 -34
- package/src/types.ts +41 -2
- package/src/web-editor.ts +1491 -0
package/README.md
CHANGED
|
@@ -1,80 +1,31 @@
|
|
|
1
1
|
# pi-forge
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**pi-forge** lets you customize how Pi thinks and behaves. It gives you prompt stacks — JSON files that can replace, append to, or prepend Pi's default system prompt while controlling the AI's personality, visible tools, conversation history layout, and cross-turn state.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Think of it as a character sheet for your AI agent.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## What you can do with it
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
- **Give Pi a personality** — turn it into a creative writer, a roleplay partner, a strict code reviewer, or anything in between.
|
|
12
|
+
- **Switch contexts instantly** — one command to swap between "coding mode", "writing mode", and "translation mode".
|
|
13
|
+
- **Control what the AI sees** — choose which tools, skills, and project context appear in each prompt.
|
|
14
|
+
- **Remember things across turns** — let the agent track progress, store notes, and recall user preferences throughout a session.
|
|
15
|
+
- **Import SillyTavern presets** — bring your existing ST character presets into Pi with one command.
|
|
16
|
+
- **Debug your prompts** — intercept and inspect exactly what gets sent to the model.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
## Quick start
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
### Install
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
pi install npm:@zihanw/pi-forge
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Prompt stacks live in:
|
|
28
|
-
|
|
29
|
-
```txt
|
|
30
|
-
.pi/prompt-stacks/*.json
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Activation rules:
|
|
34
|
-
|
|
35
|
-
1. A restored `/preset use <id>` selection is used first when that stack still exists and has no validation errors.
|
|
36
|
-
2. A restored `/preset use none` selection disables prompt stack replacement.
|
|
37
|
-
3. `.pi/prompt-stacks/default.json` auto-activates when present unless the stack sets `"autoActivate": false`.
|
|
38
|
-
4. Otherwise, the first stack with `"autoActivate": true` is used.
|
|
39
|
-
5. `/preset use <id>` switches stacks for the session and persists that choice.
|
|
40
|
-
6. `/preset use none` disables prompt stack replacement and persists that choice.
|
|
41
|
-
|
|
42
|
-
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.
|
|
43
|
-
|
|
44
|
-
## Commands
|
|
45
|
-
|
|
46
|
-
```txt
|
|
47
|
-
/preset list
|
|
48
|
-
/preset use <id|none>
|
|
49
|
-
/preset preview [id]
|
|
50
|
-
/preset validate [id]
|
|
51
|
-
/preset reload
|
|
52
|
-
/preset vars [set <name> <value>|get <name>|clear [name]]
|
|
53
|
-
/preset import-silly <path> [character_id]
|
|
54
|
-
/intercept
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## SillyTavern preset import
|
|
58
|
-
|
|
59
|
-
Import a SillyTavern preset JSON into `.pi/prompt-stacks/<id>.json` and write a migration report to `.pi/forge/import-reports/<id>.md`:
|
|
60
|
-
|
|
61
|
-
```txt
|
|
62
|
-
/preset import-silly <path> [character_id]
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
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.
|
|
66
|
-
|
|
67
|
-
## Agent tools
|
|
68
|
-
|
|
69
|
-
### forge_set_var
|
|
70
|
-
|
|
71
|
-
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).
|
|
72
|
-
|
|
73
|
-
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.
|
|
74
|
-
|
|
75
|
-
## Stack format
|
|
26
|
+
### Your first prompt stack
|
|
76
27
|
|
|
77
|
-
|
|
28
|
+
Create `.pi/prompt-stacks/default.json`:
|
|
78
29
|
|
|
79
30
|
```json
|
|
80
31
|
{
|
|
@@ -86,134 +37,271 @@ Minimal example:
|
|
|
86
37
|
"items": [
|
|
87
38
|
{
|
|
88
39
|
"kind": "block",
|
|
89
|
-
"id": "
|
|
40
|
+
"id": "role",
|
|
41
|
+
"name": "Main Role",
|
|
90
42
|
"enabled": true,
|
|
91
43
|
"role": "system",
|
|
92
|
-
"content": "You are a
|
|
44
|
+
"content": "You are a friendly and concise coding assistant. Prefer short answers with code examples."
|
|
93
45
|
},
|
|
94
46
|
{
|
|
95
47
|
"kind": "slot",
|
|
96
48
|
"id": "tools",
|
|
49
|
+
"name": "Available Tools",
|
|
97
50
|
"enabled": true,
|
|
98
51
|
"role": "system",
|
|
99
52
|
"slot": "tools"
|
|
100
53
|
},
|
|
101
|
-
{
|
|
102
|
-
"kind": "block",
|
|
103
|
-
"id": "history-open",
|
|
104
|
-
"enabled": true,
|
|
105
|
-
"role": "user",
|
|
106
|
-
"content": "<conversation_context>"
|
|
107
|
-
},
|
|
108
54
|
{
|
|
109
55
|
"kind": "slot",
|
|
110
56
|
"id": "chat-history",
|
|
57
|
+
"name": "Chat History",
|
|
111
58
|
"enabled": true,
|
|
112
59
|
"slot": "chat-history"
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"kind": "block",
|
|
116
|
-
"id": "history-close",
|
|
117
|
-
"enabled": true,
|
|
118
|
-
"role": "user",
|
|
119
|
-
"content": "</conversation_context>"
|
|
120
60
|
}
|
|
121
61
|
]
|
|
122
62
|
}
|
|
123
63
|
```
|
|
124
64
|
|
|
125
|
-
|
|
65
|
+
That's it. Restart Pi or run `/preset reload`. If no stack is already selected, `default.json` auto-activates. If you previously chose another stack or `/preset use none`, run `/preset use default`.
|
|
126
66
|
|
|
127
|
-
###
|
|
67
|
+
### Visual editor
|
|
128
68
|
|
|
129
|
-
|
|
69
|
+
Prefer clicking over typing JSON? pi-forge has a built-in web editor:
|
|
130
70
|
|
|
131
|
-
```json
|
|
132
|
-
{
|
|
133
|
-
"kind": "block",
|
|
134
|
-
"id": "post-history-nudge",
|
|
135
|
-
"enabled": true,
|
|
136
|
-
"role": "user",
|
|
137
|
-
"content": "Reason carefully about the latest request before answering."
|
|
138
|
-
}
|
|
139
71
|
```
|
|
72
|
+
/preset ui
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Drag, drop, edit, validate, preview, import, export, fork, and delete stacks — all in your browser.
|
|
140
76
|
|
|
141
|
-
|
|
77
|
+
Import accepts native pi-forge stack JSON and SillyTavern preset JSON. SillyTavern presets are converted to prompt stacks automatically; if a preset contains multiple `character_id` configs, the editor asks which one to use.
|
|
142
78
|
|
|
143
|
-
|
|
79
|
+
The editor runs on `127.0.0.1:41738` by default with a session token. Writes require a trusted project and stay inside `.pi/prompt-stacks`; successful save, import, fork, and delete actions reload into the current Pi session. Use `/preset ui restart` or `/preset ui stop` when needed.
|
|
80
|
+
|
|
81
|
+
To use a different fixed port, create `.pi/forge/config.json`:
|
|
144
82
|
|
|
145
83
|
```json
|
|
146
84
|
{
|
|
147
|
-
"
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
"role": "system",
|
|
151
|
-
"slot": "skills"
|
|
85
|
+
"webEditor": {
|
|
86
|
+
"port": 41738
|
|
87
|
+
}
|
|
152
88
|
}
|
|
153
89
|
```
|
|
154
90
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
- `
|
|
165
|
-
- `
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
</turn>
|
|
186
|
-
</prompt_variables>
|
|
91
|
+
## Use cases
|
|
92
|
+
|
|
93
|
+
### 🎭 Roleplay & creative writing
|
|
94
|
+
|
|
95
|
+
Turn Pi into a character. Define their personality in the system prompt, inject writing style rules as user messages, and use `{{lastUserMessage}}` to re-insert the user's input after the conversation history.
|
|
96
|
+
|
|
97
|
+
Useful pattern:
|
|
98
|
+
- Put long-term character rules in a `system` block.
|
|
99
|
+
- Keep Pi runtime context (tools, skills, project) in `user` slots.
|
|
100
|
+
- Set the `chat-history` slot to skip the latest user message.
|
|
101
|
+
- Add a final `user` block with `{{lastUserMessage}}`.
|
|
102
|
+
|
|
103
|
+
This keeps the latest request clear and avoids duplicating it.
|
|
104
|
+
|
|
105
|
+
For a copyable starter stack, see [examples/default-prompt-stack.json](examples/default-prompt-stack.json).
|
|
106
|
+
|
|
107
|
+
### 🧑💻 Focused code review
|
|
108
|
+
|
|
109
|
+
Create a `reviewer.json` stack with a strict review block: "prioritize correctness, regressions, security, and missing tests." Keep the `tools`, `project-context`, `variables`, and `chat-history` slots enabled so Pi can still inspect the repo and remember review state.
|
|
110
|
+
|
|
111
|
+
Use `mode: "append"` if you want to keep Pi's normal coding behavior and only add the sharper review lens.
|
|
112
|
+
|
|
113
|
+
### 🌐 Translation mode
|
|
114
|
+
|
|
115
|
+
Create a small `translator.json` stack with one system block for tone and target language, then keep `chat-history` and `{{lastUserMessage}}` in the layout. This works well for switching between bilingual editing, literal translation, and localization review without changing your default assistant.
|
|
116
|
+
|
|
117
|
+
### 🔀 Multi-mode switching
|
|
118
|
+
|
|
119
|
+
Create separate stacks for different tasks:
|
|
120
|
+
|
|
187
121
|
```
|
|
122
|
+
.pi/prompt-stacks/
|
|
123
|
+
coder.json # strict coding assistant
|
|
124
|
+
writer.json # creative writing partner
|
|
125
|
+
translator.json # bilingual translator
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Switch with `/preset use coder`, `/preset use writer`, etc.
|
|
188
129
|
|
|
189
|
-
|
|
130
|
+
### 🧠 Cross-turn memory
|
|
131
|
+
|
|
132
|
+
Define state the agent can read and write:
|
|
190
133
|
|
|
191
134
|
```json
|
|
192
|
-
{
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
|
|
135
|
+
"state": {
|
|
136
|
+
"definitions": {
|
|
137
|
+
"agent.progress": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"scope": "session",
|
|
140
|
+
"description": "What we're working on",
|
|
141
|
+
"agentWritable": true
|
|
142
|
+
}
|
|
143
|
+
}
|
|
196
144
|
}
|
|
197
145
|
```
|
|
198
146
|
|
|
199
|
-
|
|
147
|
+
The agent updates it with `forge_state_set`. You can also set state manually:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
/state set user.preference "use TypeScript, not JavaScript"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 📦 SillyTavern migration
|
|
154
|
+
|
|
155
|
+
Bring your ST presets into Pi:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
/preset import-silly ~/SillyTavern/presets/my-preset.json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
pi-forge converts the preset to a prompt stack and generates a migration report showing what was handled and what needs manual tweaking.
|
|
162
|
+
|
|
163
|
+
### 🔍 Prompt debugging
|
|
164
|
+
|
|
165
|
+
See exactly what gets sent to the model:
|
|
200
166
|
|
|
201
|
-
|
|
167
|
+
```
|
|
168
|
+
/payload next save=.pi/forge/payloads/last.json
|
|
169
|
+
```
|
|
202
170
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
171
|
+
Or preview your compiled prompt without sending anything:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
/preset preview
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## How it works
|
|
178
|
+
|
|
179
|
+
A prompt stack is a JSON file with two kinds of items:
|
|
180
|
+
|
|
181
|
+
| Kind | What it does |
|
|
182
|
+
|------|-------------|
|
|
183
|
+
| **Block** | Static text inserted at a specific position (system prompt, user message, assistant message) |
|
|
184
|
+
| **Slot** | Dynamic content from Pi's runtime — tools, skills, chat history, date, project context, etc. |
|
|
185
|
+
|
|
186
|
+
Items are arranged in order. When the stack is active, pi-forge:
|
|
187
|
+
|
|
188
|
+
1. Builds a system prompt from your `system`-role blocks and slots, then applies it with the stack's `mode`.
|
|
189
|
+
2. Inserts `user`/`assistant` blocks and slots around the conversation history.
|
|
190
|
+
3. Expands `{{macros}}` like `{{lastUserMessage}}`, `{{date}}`, and custom variables.
|
|
191
|
+
|
|
192
|
+
### Slots at a glance
|
|
193
|
+
|
|
194
|
+
| Slot | What it inserts |
|
|
195
|
+
|------|----------------|
|
|
196
|
+
| `chat-history` | The current conversation |
|
|
197
|
+
| `tools` | Available tools and their descriptions |
|
|
198
|
+
| `tool-guidelines` | Tool usage instructions |
|
|
199
|
+
| `skills` | Loaded Pi skills |
|
|
200
|
+
| `project-context` | Project instructions and context files |
|
|
201
|
+
| `variables` | Agent and user state (progress, preferences, notes) |
|
|
202
|
+
| `date` / `cwd` / `date-cwd` | Current date and working directory |
|
|
203
|
+
| `active-model` | Which model is being used |
|
|
204
|
+
| `append-system-prompt` | User's appended system prompt text |
|
|
205
|
+
| `pi-docs` | Pi documentation guidance |
|
|
206
|
+
|
|
207
|
+
### Modes
|
|
208
|
+
|
|
209
|
+
- **replace** (default) — your stack replaces Pi's system prompt entirely.
|
|
210
|
+
- **append** — your stack is added after Pi's default system prompt.
|
|
211
|
+
- **prepend** — your stack is added before Pi's default system prompt.
|
|
212
|
+
|
|
213
|
+
## Common commands
|
|
214
|
+
|
|
215
|
+
### Managing stacks
|
|
216
|
+
|
|
217
|
+
| Command | What it does |
|
|
218
|
+
|---------|-------------|
|
|
219
|
+
| `/preset list` | Show all available stacks |
|
|
220
|
+
| `/preset use <id>` | Activate a stack |
|
|
221
|
+
| `/preset use none` | Disable prompt stacks for the session |
|
|
222
|
+
| `/preset preview [id]` | See the compiled prompt |
|
|
223
|
+
| `/preset validate [id]` | Check a stack for issues |
|
|
224
|
+
| `/preset status` | Show the active stack and diagnostics summary |
|
|
225
|
+
| `/preset diagnostics` | Show runtime diagnostics |
|
|
226
|
+
| `/preset reload` | Reload stacks from disk |
|
|
227
|
+
| `/preset ui [stop\|restart]` | Open, stop, or restart the web editor |
|
|
228
|
+
|
|
229
|
+
### State management
|
|
230
|
+
|
|
231
|
+
| Command | What it does |
|
|
232
|
+
|---------|-------------|
|
|
233
|
+
| `/state list` | Show all session state |
|
|
234
|
+
| `/state status` | Show state definitions and current values |
|
|
235
|
+
| `/state set <name> <value>` | Set a state variable |
|
|
236
|
+
| `/state get <name>` | Read a state variable |
|
|
237
|
+
| `/state clear [name]` | Clear state (all or by name) |
|
|
238
|
+
| `/preset vars ...` | Legacy variable commands kept for older stacks |
|
|
239
|
+
|
|
240
|
+
### Import & debug
|
|
241
|
+
|
|
242
|
+
| Command | What it does |
|
|
243
|
+
|---------|-------------|
|
|
244
|
+
| `/preset import-silly <path>` | Import a SillyTavern preset |
|
|
245
|
+
| `/intercept` | Show the next provider payload |
|
|
246
|
+
| `/payload next [save=<path>]` | Show and optionally save the next payload |
|
|
247
|
+
|
|
248
|
+
## Common macros
|
|
249
|
+
|
|
250
|
+
Use these in block content to insert dynamic values:
|
|
251
|
+
|
|
252
|
+
| Macro | Expands to |
|
|
253
|
+
|-------|-----------|
|
|
254
|
+
| `{{lastUserMessage}}` | The user's latest message |
|
|
255
|
+
| `{{date}}` | Current date (YYYY-MM-DD) |
|
|
256
|
+
| `{{time}}` | Current time (HH:MM:SS) |
|
|
257
|
+
| `{{cwd}}` | Current working directory |
|
|
258
|
+
| `{{tools}}` | Comma-separated tool names |
|
|
259
|
+
| `{{selectedTools}}` | Alias for selected tool names |
|
|
260
|
+
| `{{activeModel}}` | Current model (provider/id) |
|
|
261
|
+
| `{{char}}` / `{{user}}` | Custom variables from your stack |
|
|
262
|
+
|
|
263
|
+
### Variable macros
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
{{setvar::name::value}} set a turn variable (cleared each message)
|
|
267
|
+
{{setsessionvar::name::value}} set a session variable (persists)
|
|
268
|
+
{{setvar::session::name::value}} also set a session variable
|
|
269
|
+
{{getvar::name}} read a variable (turn → session → static)
|
|
270
|
+
{{getturnvar::name}} read only a turn variable
|
|
271
|
+
{{getsessionvar::name}} read only a session variable
|
|
272
|
+
{{clearvar::name}} clear a variable
|
|
273
|
+
{{clearturnvar::name}} clear a turn variable
|
|
274
|
+
{{clearsessionvar::name}} clear a session variable
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Stack reference
|
|
278
|
+
|
|
279
|
+
### Full item types
|
|
280
|
+
|
|
281
|
+
**Block:**
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"kind": "block",
|
|
286
|
+
"id": "unique-id",
|
|
287
|
+
"name": "Readable label",
|
|
288
|
+
"enabled": true,
|
|
289
|
+
"role": "system",
|
|
290
|
+
"content": "Your text here. Use {{macros}} for dynamic content."
|
|
291
|
+
}
|
|
292
|
+
```
|
|
207
293
|
|
|
208
|
-
|
|
294
|
+
Valid roles: `system`, `user`, `assistant`, `custom`.
|
|
209
295
|
|
|
210
|
-
|
|
296
|
+
**Slot:**
|
|
211
297
|
|
|
212
298
|
```json
|
|
213
299
|
{
|
|
214
300
|
"kind": "slot",
|
|
215
|
-
"id": "
|
|
301
|
+
"id": "unique-id",
|
|
302
|
+
"name": "Chat History",
|
|
216
303
|
"enabled": true,
|
|
304
|
+
"role": "user",
|
|
217
305
|
"slot": "chat-history",
|
|
218
306
|
"options": {
|
|
219
307
|
"includeLastUserMessage": false
|
|
@@ -221,66 +309,97 @@ To omit the latest user message from a chat history slot, use:
|
|
|
221
309
|
}
|
|
222
310
|
```
|
|
223
311
|
|
|
224
|
-
|
|
312
|
+
### Chat history options
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
"options": {
|
|
316
|
+
"includeLastUserMessage": false
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Set to `false` when you use `{{lastUserMessage}}` after the history — prevents the user's message from appearing twice.
|
|
225
321
|
|
|
226
|
-
|
|
322
|
+
### Variables slot options
|
|
227
323
|
|
|
228
324
|
```json
|
|
229
325
|
{
|
|
230
|
-
"
|
|
231
|
-
|
|
326
|
+
"kind": "slot",
|
|
327
|
+
"id": "state",
|
|
328
|
+
"enabled": true,
|
|
329
|
+
"role": "user",
|
|
330
|
+
"slot": "variables",
|
|
331
|
+
"options": {
|
|
332
|
+
"includeScopes": ["session"],
|
|
333
|
+
"includeNamespaces": ["user.*", "agent.*"],
|
|
334
|
+
"includeMetadata": true,
|
|
335
|
+
"format": "xml",
|
|
336
|
+
"maxValueChars": 1200
|
|
232
337
|
}
|
|
233
338
|
}
|
|
234
339
|
```
|
|
235
340
|
|
|
236
|
-
|
|
341
|
+
### State definitions
|
|
237
342
|
|
|
238
|
-
|
|
343
|
+
```json
|
|
344
|
+
"state": {
|
|
345
|
+
"schemaVersion": 1,
|
|
346
|
+
"definitions": {
|
|
347
|
+
"agent.progress": {
|
|
348
|
+
"type": "string",
|
|
349
|
+
"scope": "session",
|
|
350
|
+
"description": "Current task progress",
|
|
351
|
+
"agentWritable": true
|
|
352
|
+
},
|
|
353
|
+
"user.preference": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"scope": "session",
|
|
356
|
+
"description": "User's preference for this session",
|
|
357
|
+
"userWritable": true
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
239
362
|
|
|
240
|
-
|
|
241
|
-
- `{{date}}`
|
|
242
|
-
- `{{lastUserMessage}}`
|
|
243
|
-
- `{{selectedTools}}` / `{{tools}}`
|
|
244
|
-
- `{{activeModel}}`
|
|
245
|
-
- custom variables from the stack `variables` object, e.g. `{{char}}`
|
|
363
|
+
Supported types: `string`, `number`, `boolean`, `null`, `object`, `array`, `string[]`, `number[]`, `boolean[]`, `unknown`, and unions like `string | null`.
|
|
246
364
|
|
|
247
|
-
|
|
365
|
+
## Agent tools
|
|
248
366
|
|
|
249
|
-
|
|
367
|
+
pi-forge registers two tools that the AI agent can call:
|
|
250
368
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
369
|
+
### `forge_state_set`
|
|
370
|
+
|
|
371
|
+
Batch-update persistent state. Only `agent.*` names are writable. Use for cross-turn tracking:
|
|
372
|
+
|
|
373
|
+
- Task progress (`agent.progress`)
|
|
374
|
+
- Open questions (`agent.openQuestions`)
|
|
375
|
+
- Story state (`agent.storyState`)
|
|
376
|
+
- User-requested notes (`agent.notes`)
|
|
257
377
|
|
|
258
|
-
|
|
378
|
+
### `forge_set_var`
|
|
259
379
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
380
|
+
Legacy alias for setting a single string value. Prefer `forge_state_set`.
|
|
381
|
+
|
|
382
|
+
## Package setup for development
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
git clone <repo>
|
|
386
|
+
cd pi-forge
|
|
387
|
+
# .pi/settings.json already points at the package root
|
|
388
|
+
pi # start Pi, trust the project, /reload if needed
|
|
267
389
|
```
|
|
268
390
|
|
|
269
|
-
|
|
391
|
+
Run tests:
|
|
270
392
|
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
{{setvar::session::name::value}}
|
|
274
|
-
{{getsessionvar::name}}
|
|
275
|
-
{{getvar::name}}
|
|
276
|
-
{{clearsessionvar::name}}
|
|
277
|
-
{{clearvar::session::name}}
|
|
393
|
+
```bash
|
|
394
|
+
npm test
|
|
278
395
|
```
|
|
279
396
|
|
|
280
|
-
|
|
397
|
+
Typecheck:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
npm run typecheck
|
|
401
|
+
```
|
|
281
402
|
|
|
282
|
-
|
|
283
|
-
2. session variables
|
|
284
|
-
3. static stack variables
|
|
403
|
+
## License
|
|
285
404
|
|
|
286
|
-
|
|
405
|
+
MIT
|