@zihanw/pi-forge 0.4.0-beta.1 → 0.4.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/CHANGELOG.md +37 -1
- package/PUBLIC_API.md +3 -26
- package/README.md +90 -601
- package/README.zh-CN.md +86 -585
- package/SUBAGENT_ADAPTER_CONTRACT.md +3 -197
- package/dist/forge-config.d.ts +80 -0
- package/dist/forge-config.d.ts.map +1 -1
- package/dist/forge-config.js +268 -18
- package/dist/forge-config.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -4
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.js +1 -1
- package/dist/profile-service.d.ts +1 -1
- package/dist/profile-service.d.ts.map +1 -1
- package/dist/profile-service.js +10 -5
- package/dist/profile-service.js.map +1 -1
- package/dist/runtime/subagent-runtime.d.ts +23 -8
- package/dist/runtime/subagent-runtime.d.ts.map +1 -1
- package/dist/runtime/subagent-runtime.js +283 -62
- package/dist/runtime/subagent-runtime.js.map +1 -1
- package/dist/storage.d.ts +1 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +15 -1
- package/dist/storage.js.map +1 -1
- package/dist/subagent/canonical.d.ts +19 -7
- package/dist/subagent/canonical.d.ts.map +1 -1
- package/dist/subagent/canonical.js +19 -47
- package/dist/subagent/canonical.js.map +1 -1
- package/dist/subagent/contract.d.ts +1 -2
- package/dist/subagent/contract.d.ts.map +1 -1
- package/dist/subagent/contract.js +1 -2
- package/dist/subagent/contract.js.map +1 -1
- package/dist/subagent/index.d.ts +4 -3
- package/dist/subagent/index.d.ts.map +1 -1
- package/dist/subagent/index.js +4 -3
- package/dist/subagent/index.js.map +1 -1
- package/dist/subagent/plan.d.ts +5 -1
- package/dist/subagent/plan.d.ts.map +1 -1
- package/dist/subagent/plan.js +28 -31
- package/dist/subagent/plan.js.map +1 -1
- package/dist/subagent/types.d.ts +62 -178
- package/dist/subagent/types.d.ts.map +1 -1
- package/dist/subagent/types.js +1 -1
- package/dist/subagent/types.js.map +1 -1
- package/dist/subagent/validation.d.ts +14 -14
- package/dist/subagent/validation.d.ts.map +1 -1
- package/dist/subagent/validation.js +52 -238
- package/dist/subagent/validation.js.map +1 -1
- package/dist/subagent-command.d.ts.map +1 -1
- package/dist/subagent-command.js +109 -16
- package/dist/subagent-command.js.map +1 -1
- package/dist/subagent-host.d.ts.map +1 -1
- package/dist/subagent-host.js +1 -0
- package/dist/subagent-host.js.map +1 -1
- package/dist/subagent-profile-tool.d.ts +25 -2
- package/dist/subagent-profile-tool.d.ts.map +1 -1
- package/dist/subagent-profile-tool.js +39 -8
- package/dist/subagent-profile-tool.js.map +1 -1
- package/dist/subagent-tool.d.ts +6 -3
- package/dist/subagent-tool.d.ts.map +1 -1
- package/dist/subagent-tool.js +85 -14
- package/dist/subagent-tool.js.map +1 -1
- package/dist/web-editor/client-script.generated.d.ts +1 -1
- package/dist/web-editor/client-script.generated.d.ts.map +1 -1
- package/dist/web-editor/client-script.generated.js +1 -1
- package/dist/web-editor/client-script.generated.js.map +1 -1
- package/dist/web-editor/client-styles.d.ts +2 -0
- package/dist/web-editor/client-styles.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.d.ts +2 -0
- package/dist/web-editor/client-styles.generated.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.js +3 -0
- package/dist/web-editor/client-styles.generated.js.map +1 -0
- package/dist/web-editor/client-styles.js +2 -0
- package/dist/web-editor/client-styles.js.map +1 -0
- package/dist/web-editor/page.d.ts +2 -0
- package/dist/web-editor/page.d.ts.map +1 -1
- package/dist/web-editor/page.js +11 -73
- package/dist/web-editor/page.js.map +1 -1
- package/dist/web-editor/server.d.ts.map +1 -1
- package/dist/web-editor/server.js +148 -0
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts.map +1 -1
- package/dist/web-editor/styles.js +60 -3
- package/dist/web-editor/styles.js.map +1 -1
- package/dist/web-editor/types.d.ts +79 -0
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +13 -2
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +301 -0
- package/dist/web-host.js.map +1 -1
- package/docs/README.md +41 -0
- package/docs/concepts/agent-profiles.md +60 -0
- package/docs/concepts/prompt-stacks.md +90 -0
- package/docs/design/README.md +17 -0
- package/docs/design/roadmap-0.4-archive.md +216 -0
- package/docs/design/subagents/design-review.md +220 -0
- package/docs/design/subagents/interface-design.md +274 -0
- package/docs/design/subagents/sdk-spike-findings.md +117 -0
- package/docs/development/complexity-review.md +86 -0
- package/docs/development/release.md +31 -0
- package/docs/development/roadmap.md +42 -0
- package/docs/development/setup.md +75 -0
- package/docs/getting-started.md +93 -0
- package/docs/guides/custom-macros-and-slots.md +68 -0
- package/docs/guides/debugging.md +39 -0
- package/docs/guides/delegation.md +99 -0
- package/docs/guides/sillytavern-import.md +47 -0
- package/docs/guides/use-cases.md +65 -0
- package/docs/guides/web-editor.md +75 -0
- package/docs/reference/commands.md +60 -0
- package/docs/reference/configuration.md +64 -0
- package/docs/reference/features.md +279 -0
- package/docs/reference/macros-and-slots.md +82 -0
- package/docs/reference/public-api.md +28 -0
- package/docs/reference/stack-schema.md +167 -0
- package/docs/reference/subagent-adapter.md +204 -0
- package/docs/zh-CN/README.md +37 -0
- package/docs/zh-CN/concepts/agent-profiles.md +44 -0
- package/docs/zh-CN/concepts/prompt-stacks.md +40 -0
- package/docs/zh-CN/getting-started.md +79 -0
- package/docs/zh-CN/guides/delegation.md +66 -0
- package/docs/zh-CN/guides/web-editor.md +45 -0
- package/docs/zh-CN/reference/commands.md +58 -0
- package/package.json +28 -14
- package/dist/subagent/backend-registry.d.ts +0 -75
- package/dist/subagent/backend-registry.d.ts.map +0 -1
- package/dist/subagent/backend-registry.js +0 -463
- package/dist/subagent/backend-registry.js.map +0 -1
- package/dist/subagent/diagnostics.d.ts +0 -3
- package/dist/subagent/diagnostics.d.ts.map +0 -1
- package/dist/subagent/diagnostics.js +0 -5
- package/dist/subagent/diagnostics.js.map +0 -1
- package/dist/subagent/pi-model-runtime.d.ts +0 -8
- package/dist/subagent/pi-model-runtime.d.ts.map +0 -1
- package/dist/subagent/pi-model-runtime.js +0 -22
- package/dist/subagent/pi-model-runtime.js.map +0 -1
- package/dist/subagent/pi-sdk-backend.d.ts +0 -23
- package/dist/subagent/pi-sdk-backend.d.ts.map +0 -1
- package/dist/subagent/pi-sdk-backend.js +0 -383
- package/dist/subagent/pi-sdk-backend.js.map +0 -1
- package/dist/subagent/pi-subprocess-backend.d.ts +0 -72
- package/dist/subagent/pi-subprocess-backend.d.ts.map +0 -1
- package/dist/subagent/pi-subprocess-backend.js +0 -756
- package/dist/subagent/pi-subprocess-backend.js.map +0 -1
- package/dist/subagent/subprocess-bridge.d.ts +0 -21
- package/dist/subagent/subprocess-bridge.d.ts.map +0 -1
- package/dist/subagent/subprocess-bridge.js +0 -87
- package/dist/subagent/subprocess-bridge.js.map +0 -1
- package/dist/subagent/subprocess-report.d.ts +0 -4
- package/dist/subagent/subprocess-report.d.ts.map +0 -1
- package/dist/subagent/subprocess-report.js +0 -55
- package/dist/subagent/subprocess-report.js.map +0 -1
- package/dist/subagent-contract.d.ts +0 -8
- package/dist/subagent-contract.d.ts.map +0 -1
- package/dist/subagent-contract.js +0 -8
- package/dist/subagent-contract.js.map +0 -1
- package/dist/web-editor/client/api.d.ts +0 -9
- package/dist/web-editor/client/api.d.ts.map +0 -1
- package/dist/web-editor/client/api.js +0 -26
- package/dist/web-editor/client/api.js.map +0 -1
- package/dist/web-editor/client/dom.d.ts +0 -13
- package/dist/web-editor/client/dom.d.ts.map +0 -1
- package/dist/web-editor/client/dom.js +0 -30
- package/dist/web-editor/client/dom.js.map +0 -1
- package/dist/web-editor/client/inspector.d.ts +0 -22
- package/dist/web-editor/client/inspector.d.ts.map +0 -1
- package/dist/web-editor/client/inspector.js +0 -226
- package/dist/web-editor/client/inspector.js.map +0 -1
- package/dist/web-editor/client/main.d.ts +0 -2
- package/dist/web-editor/client/main.d.ts.map +0 -1
- package/dist/web-editor/client/main.js +0 -1468
- package/dist/web-editor/client/main.js.map +0 -1
- package/dist/web-editor/client/policy-editor.d.ts +0 -16
- package/dist/web-editor/client/policy-editor.d.ts.map +0 -1
- package/dist/web-editor/client/policy-editor.js +0 -330
- package/dist/web-editor/client/policy-editor.js.map +0 -1
- package/dist/web-editor/client/regex-editor.d.ts +0 -19
- package/dist/web-editor/client/regex-editor.d.ts.map +0 -1
- package/dist/web-editor/client/regex-editor.js +0 -281
- package/dist/web-editor/client/regex-editor.js.map +0 -1
- package/dist/web-editor/client/types.d.ts +0 -60
- package/dist/web-editor/client/types.d.ts.map +0 -1
- package/dist/web-editor/client/types.js +0 -2
- package/dist/web-editor/client/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,666 +1,155 @@
|
|
|
1
1
|
# pi-forge
|
|
2
2
|
|
|
3
|
-
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md) · [Documentation](docs/README.md)
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
**pi-forge** lets you customize how Pi thinks and behaves.
|
|
7
|
+
**pi-forge** lets you customize how [Pi](https://github.com/badlogic/pi-mono) thinks and behaves. Prompt stacks control prompt composition and tool policy; agent profiles apply a model, thinking level, and stack as a reusable one-shot preset.
|
|
8
8
|
|
|
9
|
-
Think of it as a character sheet for your AI agent.
|
|
9
|
+
Think of it as a character sheet and workbench for your AI agent.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Highlights
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
13
|
+
- Compose Pi's system prompt, conversation history, tools, skills, project context, and runtime data as ordered blocks and slots.
|
|
14
|
+
- Switch between coding, reviewing, writing, roleplay, and translation modes with one command.
|
|
15
|
+
- Save and apply complete model/thinking/stack profiles.
|
|
16
|
+
- Enforce per-stack tool policy and filter model-visible skills.
|
|
17
|
+
- Use static, turn, and session variables with nested template macros.
|
|
18
|
+
- Apply deterministic regex transforms to outgoing prompts or finalized assistant messages.
|
|
19
|
+
- Import SillyTavern presets and inspect the migration report.
|
|
20
|
+
- Edit stacks and profiles in a local browser UI and inspect the exact provider payload.
|
|
21
|
+
- Run an explicitly enabled profile as an experimental, approval-gated foreground subagent.
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Install
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
pi-forge requires Node.js 22.19 or newer.
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
pi install npm:@zihanw/pi-forge
|
|
28
|
+
pi install npm:@zihanw/pi-forge
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Restart Pi after installing or updating the extension. Pi supplies its SDK packages to extensions at runtime; pi-forge keeps exact Pi versions only for reproducible development and tests. See [compatibility and setup](docs/development/setup.md#pi-compatibility) for the supported/tested policy.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
## Five-minute start
|
|
34
34
|
|
|
35
|
-
###
|
|
35
|
+
### 1. Create a prompt stack
|
|
36
36
|
|
|
37
|
-
Create `.pi/forge/prompt-stacks/default.json` from [
|
|
38
|
-
|
|
39
|
-
The default example mirrors Pi's own prompt builder from `@earendil-works/pi-coding-agent/dist/core/system-prompt.js`, but splits it into movable pi-forge slots: role, tools, guidelines, Pi docs guidance, appended system prompt text, project context, skills, date/cwd, and chat history.
|
|
37
|
+
Create `.pi/forge/prompt-stacks/default.json` from [the default Pi mirror](examples/default-prompt-stack.json):
|
|
40
38
|
|
|
41
39
|
```bash
|
|
42
40
|
mkdir -p .pi/forge/prompt-stacks
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Paste the example JSON into that file. If you are working inside this repository, you can copy it directly with `cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json`.
|
|
47
|
-
|
|
48
|
-
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`.
|
|
49
|
-
|
|
50
|
-
### Visual editor
|
|
51
|
-
|
|
52
|
-
Prefer clicking over typing JSON? pi-forge has a built-in web editor:
|
|
53
|
-
|
|
41
|
+
cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json
|
|
54
42
|
```
|
|
55
|
-
/preset ui
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Drag, drop, create, edit, validate, inspect full previews and captured payloads, manage variables/context/regex rules in tabs, switch dark mode, recover through raw stack JSON, import, export, fork, and delete stacks — all in your browser. New stacks start from the default Pi prompt mirror layout. Existing stack IDs are immutable; use Fork to create a new ID without risking profile references or active selection. Stack metadata is collapsible so the active editor stays in view. The policy tab shows registered tools and loaded skills with selected-pattern chips and filtering, so allow/deny rules can be built from exact names while still supporting wildcards.
|
|
59
43
|
|
|
60
|
-
|
|
44
|
+
If you installed from npm rather than cloning this repository, open `/preset ui` and create a new stack; the editor starts with the same Pi-mirror layout.
|
|
61
45
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
To copy old stacks into the new location, run `/preset migrate-stacks`. Add `--dry-run` to preview, `--overwrite` to replace existing target files, and `--delete-legacy` to remove old files after successful copy.
|
|
65
|
-
|
|
66
|
-
To prefer a specific port, create `.pi/forge/config.json`. If that port is busy, pi-forge falls back to another available port and shows the actual URL:
|
|
67
|
-
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"webEditor": {
|
|
71
|
-
"port": 41738
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Agent profiles
|
|
77
|
-
|
|
78
|
-
Agent profiles are project-local JSON files under `.pi/forge/agent-profiles`. The quickest way to create one is to configure Pi normally and capture the current model, thinking level, and prompt-stack selection:
|
|
46
|
+
Restart Pi or run:
|
|
79
47
|
|
|
80
48
|
```text
|
|
81
|
-
/
|
|
82
|
-
/
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Profiles are applied once. They do not continuously own Pi's model or thinking level, so later manual changes are preserved until `/profile use reviewer` is run again. Prompt-stack tool policy remains strict for as long as that stack is active.
|
|
86
|
-
|
|
87
|
-
A profile can also be written directly:
|
|
88
|
-
|
|
89
|
-
```json
|
|
90
|
-
{
|
|
91
|
-
"schemaVersion": 1,
|
|
92
|
-
"type": "pi-forge.agent-profile",
|
|
93
|
-
"id": "reviewer",
|
|
94
|
-
"name": "Reviewer",
|
|
95
|
-
"description": "Reviews code without making changes.",
|
|
96
|
-
"autoActivate": true,
|
|
97
|
-
"model": {
|
|
98
|
-
"provider": "provider-id",
|
|
99
|
-
"id": "model-id"
|
|
100
|
-
},
|
|
101
|
-
"thinkingLevel": "high",
|
|
102
|
-
"promptStack": "reviewer"
|
|
103
|
-
}
|
|
49
|
+
/preset reload
|
|
50
|
+
/preset use default
|
|
104
51
|
```
|
|
105
52
|
|
|
106
|
-
`
|
|
107
|
-
|
|
108
|
-
`promptStack` may be `null`. Tool names and skill lists do not belong in profile v1: the referenced prompt stack is the single source of truth for tool policy and model-visible skill filtering. Profile validation rejects unsupported fields rather than silently retaining inert generation or runner settings.
|
|
109
|
-
|
|
110
|
-
`/profile preview <id>` resolves the model, authentication, thinking-level support, prompt stack, and effective tools without changing runtime state. `/profile status` reports the last-applied profile and current drift; it deliberately does not describe a profile as active. Provenance follows the session branch for status purposes but never causes automatic reapplication during reload, resume, tree navigation, or compaction. Fresh-session auto-activation is still one-shot, so later manual changes are preserved.
|
|
53
|
+
`default.json` auto-activates when no stack or restored session selection takes precedence.
|
|
111
54
|
|
|
112
|
-
###
|
|
113
|
-
|
|
114
|
-
The 0.4 beta can run a stored profile as a separate, clean, one-shot Pi subprocess. The no-egress `forge_subagent_profiles` tool lets the main agent discover the currently loaded profile IDs, names, descriptions, declared model/thinking/stack, current resolution status, and approval mode. It should call that first when the user has not specified a profile, then invoke `forge_subagent`. A restrictive main-agent prompt stack must permit both tool names. The same execution path remains available to a human through commands:
|
|
55
|
+
### 2. Open the visual editor
|
|
115
56
|
|
|
116
57
|
```text
|
|
117
|
-
/
|
|
118
|
-
/forge-agent plan reviewer Review this API design for correctness.
|
|
119
|
-
/forge-agent run reviewer Review this API design for correctness.
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
`plan` resolves the profile and stack, compiles the exact provider-bound prompt, validates an immutable execution plan, and then discards it without contacting the provider. `/forge-agent run` and, by default, `forge_subagent` prepare that same exact plan before showing an approval screen. The default screen shows the agent task, profile/stack, provider, model, thinking level, effective tools, working directory, security boundary, payload size, and execution fingerprint. Choose **View full prompt** to inspect the complete system prompt and ordered provider-bound messages before approving; any editor changes are ignored.
|
|
123
|
-
|
|
124
|
-
To deliberately let the parent agent invoke `forge_subagent` without per-run approval, set the following trusted-project option in `.pi/forge/config.json`:
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
{
|
|
128
|
-
"subagents": {
|
|
129
|
-
"allowAgentInvocationWithoutApproval": true
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
This option affects only the model-callable `forge_subagent` tool; `/forge-agent run` remains interactively approved. The exact preflight and immutable-plan checks still run, and the tool result records `trusted-project-config` as its authorization source, but provider transport begins without showing the prompt to a human. Profile discovery reports the active approval mode. The setting is ignored for untrusted projects and malformed values fail closed. Treat the project config as authorization: do not enable or commit this option in a repository unless every parent agent allowed to use `forge_subagent` should be able to send the compiled prompt and readable file contents to the selected provider without asking again.
|
|
135
|
-
|
|
136
|
-
The child starts with a clean conversation and receives no parent history automatically. It runs in the foreground with the profile's exact model/thinking level and prompt stack. Its only candidate tools are `read`, `grep`, `find`, and `ls`, further restricted by the stack's tool policy; it receives no write/edit/shell tools, skills, prompt templates, context files, or third-party extensions. The final tool result contains a bounded model-visible report plus expandable human-visible execution details. Retained transcript strings are individually bounded, base64-like text is redacted, and the transcript keeps a 512 KiB rolling tail so the final report remains available without making the TUI retain an unbounded tool history. Inline image data stays inside the child long enough for the selected vision model to use it, but the dedicated report channel replaces binary payloads with MIME type and encoded-size metadata before anything is retained in the parent session.
|
|
137
|
-
|
|
138
|
-
Important: this first backend is **shared-user**, not an operating-system sandbox. Read-only is a model-tool policy: the subprocess retains the invoking user's OS permissions, and absolute paths readable by that user may be read, sent to the selected provider, and retained as text inside the parent tool-result details. Host timeout and cancellation are best effort. `/tree` removes the invocation and result from the active conversation branch, but abandoned entries can remain in Pi's on-disk session JSONL; deleting sensitive retained text requires deleting the relevant session data. `/tree` also cannot undo provider requests, billing, or external side effects. The default tool set intentionally provides no filesystem mutation path while a bubblewrap-style sandbox and staged write mode remain future work.
|
|
139
|
-
|
|
140
|
-
## Use cases
|
|
141
|
-
|
|
142
|
-
### 🎭 Roleplay & creative writing
|
|
143
|
-
|
|
144
|
-
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.
|
|
145
|
-
|
|
146
|
-
Useful pattern:
|
|
147
|
-
- Put long-term character rules in a `system` block.
|
|
148
|
-
- Keep Pi runtime context (tools, skills, project) in `user` slots.
|
|
149
|
-
- Set the `chat-history` slot to skip the latest user message.
|
|
150
|
-
- Add a final `user` block with `{{lastUserMessage}}`.
|
|
151
|
-
|
|
152
|
-
This keeps the latest request clear and avoids duplicating it.
|
|
153
|
-
|
|
154
|
-
For a baseline stack to fork before turning Pi into a character, start from [examples/default-prompt-stack.json](examples/default-prompt-stack.json).
|
|
155
|
-
|
|
156
|
-
### 🧑💻 Focused code review
|
|
157
|
-
|
|
158
|
-
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 see any template variables you expose.
|
|
159
|
-
|
|
160
|
-
Use `mode: "append"` if you want to keep Pi's normal coding behavior and only add the sharper review lens.
|
|
161
|
-
|
|
162
|
-
### 🌐 Translation mode
|
|
163
|
-
|
|
164
|
-
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.
|
|
165
|
-
|
|
166
|
-
### 🔀 Multi-mode switching
|
|
167
|
-
|
|
168
|
-
Create separate stacks for different tasks:
|
|
169
|
-
|
|
170
|
-
```
|
|
171
|
-
.pi/forge/prompt-stacks/
|
|
172
|
-
coder.json # strict coding assistant
|
|
173
|
-
writer.json # creative writing partner
|
|
174
|
-
translator.json # bilingual translator
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
Switch with `/preset use coder`, `/preset use writer`, etc.
|
|
178
|
-
|
|
179
|
-
### 🧪 Presets that show off pi-forge
|
|
180
|
-
|
|
181
|
-
- **Pi mirror** — start from [examples/default-prompt-stack.json](examples/default-prompt-stack.json). It preserves normal Pi behavior while making every runtime section movable and inspectable.
|
|
182
|
-
- **Focused reviewer** — see [examples/reviewer-prompt-stack.json](examples/reviewer-prompt-stack.json). It denies file-writing tools, wraps prior chat history as background, removes the latest user message from history, then reinserts `{{lastUserMessage}}` as the explicit review target.
|
|
183
|
-
- **Read-only scout** — use `tools.allow` for `read`, `grep`, `find`, and `ls`; omit editing tools; cap `chat-history` with `maxChars`. Good for exploration turns where the model should report findings without changing files.
|
|
184
|
-
- **Surgical patcher** — keep the Pi mirror, require `read`, `edit`, and `bash`, strip assistant thinking from inserted history, and move `project-context` near the final user turn. Good for focused implementation passes.
|
|
185
|
-
- **SillyTavern DM writer** — see [examples/sillytavern-dm-writer-prompt-stack.json](examples/sillytavern-dm-writer-prompt-stack.json). It defines a Dungeon Master character with `{{char}}` / `{{user}}`, wraps prior adventure history, reinserts `{{lastUserMessage}}` as the current player action, and uses regex cleanup for OOC notes, secret-roll markers, dice notation, and `Player:` prefixes.
|
|
186
|
-
- **Payload lab** — include `active-model`, `date-cwd`, and variables slots, then add `compiled` regex rules for deterministic redaction or formatting. Pair it with `/payload next` or the web editor's capture view to audit exactly what changed.
|
|
187
|
-
- **Docs-only Pi expert** — allow only read/search tools, enable the `pi-docs` slot, and keep project context. Useful when you want answers grounded in the installed Pi docs instead of general memory.
|
|
188
|
-
|
|
189
|
-
### 🔧 Template variables
|
|
190
|
-
|
|
191
|
-
```json
|
|
192
|
-
"variables": {
|
|
193
|
-
"char": "Konata",
|
|
194
|
-
"user": "User"
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Use static variables for stable prompt constants, and ST-style macros for local prompt-time mutation:
|
|
199
|
-
|
|
200
|
-
```
|
|
201
|
-
{{setvar::mood::focused}}
|
|
202
|
-
{{getvar::mood}}
|
|
203
|
-
{{setsessionvar::topic::compiler cleanup}}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
For durable project memory, use normal files in the repo rather than pi-forge prompt variables.
|
|
207
|
-
|
|
208
|
-
### 📦 SillyTavern migration
|
|
209
|
-
|
|
210
|
-
Bring your ST presets into Pi:
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
/preset import-silly ~/SillyTavern/presets/my-preset.json
|
|
58
|
+
/preset ui
|
|
214
59
|
```
|
|
215
60
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
Deterministic SillyTavern `promptOnly` regex scripts are converted to pi-forge `regex.rules` as history-stage rules when they can be represented safely, including full-match token conversion, trim strings, depth fields, and clear user/assistant placements. Display-only, mixed prompt/display, DOM/browser, CSS/HTML decoration, JavaScript, unsupported placements, and invalid regex scripts stay report-only for manual review.
|
|
219
|
-
|
|
220
|
-
### 🔍 Prompt debugging
|
|
221
|
-
|
|
222
|
-
See exactly what gets sent to the model:
|
|
61
|
+
The local editor can create, fork, validate, preview, import, export, and delete prompt stacks. Its **Agent profiles** view manages one-shot model/thinking/stack presets and experimental delegation settings. Writes require a trusted project.
|
|
223
62
|
|
|
224
|
-
|
|
225
|
-
/payload next save=.pi/forge/payloads/last.json
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
Or open `/preset ui`, click **Arm payload**, send the next Pi prompt, and inspect the redacted provider payload in the browser. Credential-shaped token fields remain hidden, while normal limits and accounting fields such as `max_tokens`, `input_tokens`, and `output_tokens` remain visible.
|
|
63
|
+
### 3. Save a profile
|
|
229
64
|
|
|
230
|
-
|
|
65
|
+
Configure Pi normally, then capture and reuse the current settings:
|
|
231
66
|
|
|
232
|
-
```
|
|
233
|
-
/
|
|
67
|
+
```text
|
|
68
|
+
/profile save reviewer
|
|
69
|
+
/profile use reviewer
|
|
234
70
|
```
|
|
235
71
|
|
|
236
|
-
|
|
72
|
+
A profile applies once. Later manual changes to the model or thinking level remain in effect until the profile is applied again; an active prompt stack continues enforcing its tool policy.
|
|
237
73
|
|
|
238
|
-
|
|
74
|
+
## The basic model
|
|
239
75
|
|
|
240
|
-
|
|
241
|
-
|------|-------------|
|
|
242
|
-
| **Block** | Static text inserted at a specific position (system prompt, user message, assistant message) |
|
|
243
|
-
| **Slot** | Dynamic content from Pi's runtime — tools, skills, chat history, date, project context, etc. |
|
|
76
|
+
A prompt stack is an ordered JSON document containing:
|
|
244
77
|
|
|
245
|
-
|
|
78
|
+
| Item | Purpose |
|
|
79
|
+
|---|---|
|
|
80
|
+
| **Block** | Static `system`, `user`, `assistant`, or hidden `custom` text |
|
|
81
|
+
| **Slot** | Runtime content such as tools, skills, project context, variables, date/cwd, or chat history |
|
|
246
82
|
|
|
247
|
-
|
|
248
|
-
2. Inserts `user`/`assistant` blocks and slots around the conversation history.
|
|
249
|
-
3. Expands `{{macros}}` like `{{lastUserMessage}}`, `{{date}}`, and custom variables.
|
|
250
|
-
4. Applies stack tool policy to Pi's active tool set and filters pi-forge-rendered tool/skill slots.
|
|
251
|
-
5. Applies enabled outgoing regex rules for the `history` and `compiled` stages.
|
|
252
|
-
6. Optionally applies destructive `finalize` regex rules when an assistant message finishes.
|
|
83
|
+
Stacks can `replace`, `append`, or `prepend` Pi's base system prompt. During compilation, pi-forge expands macros, inserts conversation content, enforces tool policy, filters its skill listing, and applies enabled regex rules.
|
|
253
84
|
|
|
254
|
-
|
|
85
|
+
Agent profiles are project-local references to an exact provider/model, thinking level, and prompt stack. They intentionally do not duplicate tool or skill policy—the referenced stack remains the source of truth.
|
|
255
86
|
|
|
256
|
-
|
|
257
|
-
|------|----------------|
|
|
258
|
-
| `chat-history` | The current conversation |
|
|
259
|
-
| `tools` | Available tools and their descriptions |
|
|
260
|
-
| `tool-guidelines` | Tool usage instructions |
|
|
261
|
-
| `skills` | Loaded Pi skills |
|
|
262
|
-
| `project-context` | Project instructions and context files |
|
|
263
|
-
| `variables` | Static/session/turn template variables |
|
|
264
|
-
| `date` / `cwd` / `date-cwd` | Current date, optional current time, and working directory |
|
|
265
|
-
| `active-model` | Which model is being used |
|
|
266
|
-
| `append-system-prompt` | User's appended system prompt text |
|
|
267
|
-
| `pi-docs` | Pi documentation guidance |
|
|
87
|
+
Start with these examples:
|
|
268
88
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
-
|
|
272
|
-
-
|
|
273
|
-
- **prepend** — your stack is added before Pi's default system prompt.
|
|
89
|
+
- [Default Pi mirror](examples/default-prompt-stack.json) keeps normal Pi behavior while making its sections movable.
|
|
90
|
+
- [Focused reviewer](examples/reviewer-prompt-stack.json) creates a read-only review layout with an explicit latest-user target.
|
|
91
|
+
- [SillyTavern DM writer](examples/sillytavern-dm-writer-prompt-stack.json) demonstrates characters, variables, history placement, and regex cleanup.
|
|
92
|
+
- [Custom system-status extension](examples/custom-system-status-extension/README.md) registers a trusted macro and slot.
|
|
274
93
|
|
|
275
94
|
## Common commands
|
|
276
95
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
|
280
|
-
|
|
281
|
-
| `/preset
|
|
282
|
-
| `/preset
|
|
283
|
-
| `/preset
|
|
284
|
-
| `/preset
|
|
285
|
-
| `/
|
|
286
|
-
| `/
|
|
287
|
-
| `/preset diagnostics` | Show runtime diagnostics |
|
|
288
|
-
| `/preset reload` | Reload stacks from disk |
|
|
289
|
-
| `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | Copy legacy `.pi/prompt-stacks` files into `.pi/forge/prompt-stacks` |
|
|
290
|
-
| `/preset ui [stop\|restart]` | Open, stop, or restart the web editor |
|
|
291
|
-
|
|
292
|
-
### Managing agent profiles
|
|
293
|
-
|
|
294
|
-
| Command | What it does |
|
|
295
|
-
|---------|-------------|
|
|
296
|
-
| `/profile list` | Show project profiles and resolution diagnostics |
|
|
96
|
+
| Command | Purpose |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `/preset ui [stop\|restart]` | Open or manage the web editor |
|
|
99
|
+
| `/preset list` | List prompt stacks |
|
|
100
|
+
| `/preset use <id\|none>` | Select or disable a stack |
|
|
101
|
+
| `/preset preview [id]` | Compile a stack without sending a request |
|
|
102
|
+
| `/preset validate [id]` | Validate one stack or all stacks |
|
|
103
|
+
| `/preset diagnostics` | Show runtime and extension diagnostics |
|
|
104
|
+
| `/profile list` | List and preflight profiles |
|
|
105
|
+
| `/profile save <id> [--overwrite]` | Capture the current runtime as a profile |
|
|
297
106
|
| `/profile use <id>` | Preflight and apply a profile once |
|
|
298
|
-
| `/profile
|
|
299
|
-
| `/
|
|
300
|
-
| `/profile preview <id>` | Preview resolved effects and effective tools without applying |
|
|
301
|
-
| `/profile validate [id]` | Validate one profile, or all profiles when omitted |
|
|
302
|
-
| `/profile reload` | Reload profile files without applying them |
|
|
303
|
-
| `/profile forget` | Forget last-applied provenance without changing runtime state |
|
|
304
|
-
|
|
305
|
-
### Experimental foreground subagent
|
|
107
|
+
| `/profile status` | Show last-applied provenance and runtime drift |
|
|
108
|
+
| `/payload next [save=<path>]` | Inspect the next redacted provider payload |
|
|
306
109
|
|
|
307
|
-
|
|
308
|
-
|---------|-------------|
|
|
309
|
-
| `/forge-agent backends` | Show the available experimental backend and its capabilities |
|
|
310
|
-
| `/forge-agent plan <profile> <task>` | Prepare, validate, display, and discard an exact plan without provider transport |
|
|
311
|
-
| `/forge-agent run <profile> <task>` | Review the exact plan and run one foreground read-only text task after approval |
|
|
110
|
+
See the [complete command reference](docs/reference/commands.md).
|
|
312
111
|
|
|
313
|
-
|
|
112
|
+
## Experimental foreground delegation
|
|
314
113
|
|
|
315
|
-
|
|
114
|
+
pi-forge can run an explicitly enabled profile as a clean, foreground Pi subprocess. The model can discover eligible profiles with `forge_subagent_profiles` and invoke one with `forge_subagent`; humans use `/forge-agent plan` and `/forge-agent run`.
|
|
316
115
|
|
|
317
|
-
|
|
318
|
-
|---------|-------------|
|
|
319
|
-
| `/preset import-silly <path>` | Import a SillyTavern preset |
|
|
320
|
-
| `/intercept` | Show the next provider payload |
|
|
321
|
-
| `/payload next [save=<path>]` | Show, save, and expose the next payload to the web editor |
|
|
116
|
+
This feature is **experimental** and profiles are not delegatable by default. Enable each profile in the trusted project's `.pi/forge/config.json` or its web-editor delegation card. Interactive execution presents an immutable plan for approval unless the project explicitly authorizes unattended model invocation.
|
|
322
117
|
|
|
323
|
-
|
|
118
|
+
> **Security boundary:** The current backends are shared-user processes, not operating-system sandboxes. “Read-only” describes the model-visible tool policy. The child retains the invoking user's OS read permissions, and readable content may be sent to the selected provider and retained in Pi's session data. Timeout and cancellation are best effort, and `/tree` cannot undo provider requests, billing, or external effects.
|
|
324
119
|
|
|
325
|
-
|
|
120
|
+
Read [foreground delegation and its safety model](docs/guides/delegation.md) before enabling it.
|
|
326
121
|
|
|
327
|
-
|
|
328
|
-
|-------|-----------|
|
|
329
|
-
| `{{lastUserMessage}}` | The user's latest message |
|
|
330
|
-
| `{{date}}` | Current date (YYYY-MM-DD) |
|
|
331
|
-
| `{{time}}` | Current time (HH:MM:SS) |
|
|
332
|
-
| `{{cwd}}` | Current working directory |
|
|
333
|
-
| `{{tools}}` | Comma-separated tool names |
|
|
334
|
-
| `{{selectedTools}}` | Alias for selected tool names |
|
|
335
|
-
| `{{activeModel}}` | Current model (provider/id) |
|
|
336
|
-
| `{{char}}` / `{{user}}` | Custom variables from your stack |
|
|
122
|
+
## Documentation
|
|
337
123
|
|
|
338
|
-
###
|
|
124
|
+
### Learn
|
|
339
125
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
{{clearturnvar::name}} clear a turn variable
|
|
349
|
-
{{clearsessionvar::name}} clear a session variable
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### Filter and conditional macros
|
|
353
|
-
|
|
354
|
-
Nested macros are supported, and `::` separators are parsed only at the current macro depth.
|
|
355
|
-
|
|
356
|
-
| Macro | Expands to |
|
|
357
|
-
|-------|-----------|
|
|
358
|
-
| `{{trim::value}}` | `value` with leading/trailing whitespace removed |
|
|
359
|
-
| `{{upper::value}}` | Uppercase `value` |
|
|
360
|
-
| `{{lower::value}}` | Lowercase `value` |
|
|
361
|
-
| `{{json::value}}` | JSON string literal for `value` |
|
|
362
|
-
| `{{xml::value}}` | XML-escaped `value` |
|
|
363
|
-
| `{{ifvar::name::then::else}}` | `then` when a variable exists, otherwise `else` |
|
|
364
|
-
| `{{ifeq::name::expected::then::else}}` | `then` when a variable equals `expected`, otherwise `else` |
|
|
365
|
-
| `{{iftools::tool::then::else}}` | `then` when the selected tool list includes `tool`, otherwise `else` |
|
|
366
|
-
| `{{ifslot::slot::then::else}}` | `then` when the enabled stack items include `slot`, otherwise `else` |
|
|
367
|
-
|
|
368
|
-
Conditional branches are lazy: only the selected branch is expanded, so skipped branches cannot set or clear variables. The final `else` argument is optional and defaults to empty text.
|
|
369
|
-
|
|
370
|
-
### Trusted custom macros and slots
|
|
371
|
-
|
|
372
|
-
Custom macros and slots are registered by trusted extension code, not embedded in prompt-stack JSON. For project-local customization, put registration modules in `.pi/forge/extensions/`. For machine-wide personal customization, put them in `~/.pi/forge/extensions/`. pi-forge loads global modules first, then project-local modules, after project trust and before stack validation. Both locations reload on `/preset reload`.
|
|
373
|
-
|
|
374
|
-
These modules receive the registration API from pi-forge, so they do not need to import `@zihanw/pi-forge` or know where pi-forge is installed.
|
|
375
|
-
|
|
376
|
-
```ts
|
|
377
|
-
// .pi/forge/extensions/ticket-context.ts
|
|
378
|
-
export default function register(api) {
|
|
379
|
-
api.registerMacro({
|
|
380
|
-
name: "ticketId",
|
|
381
|
-
description: "Current ticket id from session variables.",
|
|
382
|
-
render: (ctx) => ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
api.registerSlot({
|
|
386
|
-
name: "ticket-context",
|
|
387
|
-
description: "Render ticket context for the current task.",
|
|
388
|
-
options: {
|
|
389
|
-
heading: { type: "string", default: "Ticket context" },
|
|
390
|
-
},
|
|
391
|
-
render: (ctx) => [
|
|
392
|
-
String(ctx.options.heading ?? "Ticket context") + ":",
|
|
393
|
-
"- Ticket: " + ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
394
|
-
"- Project: " + ctx.helpers.normalizePath(ctx.runtime.options.cwd),
|
|
395
|
-
].join("\n"),
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
The stack remains declarative:
|
|
401
|
-
|
|
402
|
-
```json
|
|
403
|
-
{
|
|
404
|
-
"kind": "slot",
|
|
405
|
-
"id": "ticket-context",
|
|
406
|
-
"enabled": true,
|
|
407
|
-
"role": "system",
|
|
408
|
-
"slot": "ticket-context",
|
|
409
|
-
"options": {
|
|
410
|
-
"heading": "Current ticket"
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
Supported module files are `.ts`, `.js`, `.mjs`, `.cjs`, and `index.*` inside a subdirectory. TypeScript modules should stick to syntax Node can strip at runtime, or you can use `.js` / `.mjs` instead. A module can export either `default function register(api)` or `export function register(api)`. Registered macro and slot names must be unique across built-ins, global extensions, and project extensions; duplicate names show as extension load warnings.
|
|
416
|
-
|
|
417
|
-
The API includes `cwd`, `forgeDir`, `extensionPath`, `helpers`, `registerMacro`, `registerSlot`, `getRegisteredMacros`, and `getRegisteredSlots`. For global modules, `forgeDir` is `~/.pi/forge`; for project modules, it is `<project>/.pi/forge`.
|
|
418
|
-
|
|
419
|
-
Missing custom slots are validation warnings until the registering module is loaded. Built-in macros and slots use the same registry internally, so `getRegisteredMacros()` and `getRegisteredSlots()` can be used as implementation references. `/preset diagnostics` shows loaded pi-forge extension files and load failures.
|
|
420
|
-
|
|
421
|
-
For a complete copyable extension and stack, see [examples/custom-system-status-extension](examples/custom-system-status-extension). It registers a `{{cpuLoad}}` macro and a `machine-status` slot from `.pi/forge/extensions/system-status.ts`.
|
|
422
|
-
|
|
423
|
-
Reusable Pi packages can still import `registerMacro` and `registerSlot` from `@zihanw/pi-forge`. The `.pi/forge/extensions` and `~/.pi/forge/extensions` loaders are intended for small trusted customizations without package boilerplate.
|
|
424
|
-
|
|
425
|
-
## Stack reference
|
|
426
|
-
|
|
427
|
-
### Full item types
|
|
428
|
-
|
|
429
|
-
**Block:**
|
|
430
|
-
|
|
431
|
-
```json
|
|
432
|
-
{
|
|
433
|
-
"kind": "block",
|
|
434
|
-
"id": "unique-id",
|
|
435
|
-
"name": "Readable label",
|
|
436
|
-
"enabled": true,
|
|
437
|
-
"role": "system",
|
|
438
|
-
"content": "Your text here. Use {{macros}} for dynamic content."
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
Valid roles: `system`, `user`, `assistant`, `custom`.
|
|
443
|
-
|
|
444
|
-
**Slot:**
|
|
445
|
-
|
|
446
|
-
```json
|
|
447
|
-
{
|
|
448
|
-
"kind": "slot",
|
|
449
|
-
"id": "unique-id",
|
|
450
|
-
"name": "Chat History",
|
|
451
|
-
"enabled": true,
|
|
452
|
-
"role": "user",
|
|
453
|
-
"slot": "chat-history",
|
|
454
|
-
"options": {
|
|
455
|
-
"includeLastUserMessage": false
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### Chat history options
|
|
461
|
-
|
|
462
|
-
```json
|
|
463
|
-
"options": {
|
|
464
|
-
"includeLastUserMessage": false,
|
|
465
|
-
"stripAssistantThinking": true,
|
|
466
|
-
"includeSummaries": true,
|
|
467
|
-
"toolMode": "keep",
|
|
468
|
-
"roles": ["user", "assistant"],
|
|
469
|
-
"maxMessages": 40,
|
|
470
|
-
"maxChars": 20000
|
|
471
|
-
}
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
Set to `false` when you use `{{lastUserMessage}}` after the history — prevents the user's message from appearing twice.
|
|
475
|
-
|
|
476
|
-
Set `stripAssistantThinking` to `true` to remove prior assistant thinking blocks from inserted chat history. Visible assistant text, tool calls, and tool result messages are preserved. This only affects history inserted by that slot and does not alter the current agent loop or stored transcript.
|
|
477
|
-
|
|
478
|
-
Use `includeSummaries: false` to omit Pi branch/compaction summary messages, `roles` to keep only specific message roles, `toolMode: "drop"` to remove prior tool-call/tool-result history, and `maxMessages` / `maxChars` to keep only recent history. When filters or limits can break tool-call pairs, pi-forge removes dangling tool calls/results instead of sending inconsistent tool history.
|
|
479
|
-
|
|
480
|
-
### Date slot options
|
|
126
|
+
- [Getting started](docs/getting-started.md)
|
|
127
|
+
- [Prompt-stack concepts](docs/concepts/prompt-stacks.md)
|
|
128
|
+
- [Agent-profile concepts](docs/concepts/agent-profiles.md)
|
|
129
|
+
- [Web editor](docs/guides/web-editor.md)
|
|
130
|
+
- [Prompt-stack patterns and examples](docs/guides/use-cases.md)
|
|
131
|
+
- [SillyTavern import](docs/guides/sillytavern-import.md)
|
|
132
|
+
- [Custom macros and slots](docs/guides/custom-macros-and-slots.md)
|
|
133
|
+
- [Prompt and payload debugging](docs/guides/debugging.md)
|
|
481
134
|
|
|
482
|
-
|
|
135
|
+
### Reference
|
|
483
136
|
|
|
484
|
-
|
|
137
|
+
- [Commands](docs/reference/commands.md)
|
|
138
|
+
- [Stack schema and policy](docs/reference/stack-schema.md)
|
|
139
|
+
- [Macros and slots](docs/reference/macros-and-slots.md)
|
|
140
|
+
- [Configuration](docs/reference/configuration.md)
|
|
141
|
+
- [Public API policy](docs/reference/public-api.md)
|
|
142
|
+
- [Experimental subagent adapter](docs/reference/subagent-adapter.md)
|
|
485
143
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
```json
|
|
489
|
-
{
|
|
490
|
-
"kind": "slot",
|
|
491
|
-
"id": "tools",
|
|
492
|
-
"enabled": true,
|
|
493
|
-
"role": "system",
|
|
494
|
-
"slot": "tools",
|
|
495
|
-
"options": {
|
|
496
|
-
"format": "plain"
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
The default Pi mirror uses a few extra slot options:
|
|
502
|
-
|
|
503
|
-
```json
|
|
504
|
-
{
|
|
505
|
-
"slot": "tools",
|
|
506
|
-
"options": {
|
|
507
|
-
"format": "plain",
|
|
508
|
-
"onlyWithSnippets": true
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
`tools.onlyWithSnippets` matches Pi's default "Available tools" section by hiding tools that do not provide prompt snippets. `tool-guidelines.heading`, `tool-guidelines.includePiDefaultGuidelines`, and `tool-guidelines.piStyle` make the guidelines slot match Pi's default heading and bullets. `skills.requireReadTool` hides skills unless the read tool is active, matching Pi's default behavior.
|
|
514
|
-
|
|
515
|
-
### Tool and skill policy
|
|
516
|
-
|
|
517
|
-
Prompt stacks can constrain active tools and filter model-visible skills with stack-level `allow` or `deny` lists. Patterns are exact by default and support `*` wildcards.
|
|
518
|
-
|
|
519
|
-
```json
|
|
520
|
-
{
|
|
521
|
-
"tools": {
|
|
522
|
-
"allow": ["read", "bash"]
|
|
523
|
-
},
|
|
524
|
-
"skills": {
|
|
525
|
-
"deny": ["browser-danger"]
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
For tools, use `allow` when only matching active tools should remain and `deny` when matching active tools should be removed. For skills, the same patterns control which skills remain visible in pi-forge's rendered `skills` slots. A single resource policy cannot contain both non-empty lists; mixed `allow` and `deny` entries are validation errors.
|
|
531
|
-
|
|
532
|
-
Tool policy is enforced through Pi's active tool list while the stack is active. On startup and reload, pi-forge waits for other extensions to finish their `session_start` tool configuration before capturing the baseline and applying the stack policy. It reasserts the policy before user input and turns, and a tool-call guard blocks disallowed model tool execution even if another extension later calls `setActiveTools()`. External tool additions are preserved in the restorable baseline, which is restored when prompt stacks are disabled or switched to an unrestricted stack.
|
|
533
|
-
|
|
534
|
-
Skill policy filters skills rendered by pi-forge's `skills` slot. It does not disable explicit skill invocation and is not a capability or security boundary. If a stack uses `mode: "append"` or `"prepend"`, Pi's base prompt may already contain unfiltered skills; use `mode: "replace"` when model-visible skill listings must be controlled.
|
|
535
|
-
|
|
536
|
-
### Regex transforms
|
|
537
|
-
|
|
538
|
-
Prompt stacks can run deterministic regex replacements on model-bound prompt text and, optionally, finalized assistant messages. Outgoing rules support `history` and `compiled` stages. Destructive final-message cleanup uses `effect: "finalize"` at `stage: "compiled"` with the `messages` target. True display-only streaming transforms and provider-payload rewrites are not active yet.
|
|
539
|
-
|
|
540
|
-
```json
|
|
541
|
-
"regex": {
|
|
542
|
-
"schemaVersion": 1,
|
|
543
|
-
"rules": [
|
|
544
|
-
{
|
|
545
|
-
"id": "trim-ooc",
|
|
546
|
-
"enabled": true,
|
|
547
|
-
"stage": "history",
|
|
548
|
-
"effect": "outgoing",
|
|
549
|
-
"pattern": "\\(OOC:[^)]+\\)",
|
|
550
|
-
"flags": "gi",
|
|
551
|
-
"replace": "",
|
|
552
|
-
"roles": ["assistant"],
|
|
553
|
-
"maxMessages": 20
|
|
554
|
-
}
|
|
555
|
-
]
|
|
556
|
-
}
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
Use `stage: "history"` to transform messages inserted by the `chat-history` slot. Use `stage: "compiled"` with optional `targets: ["system"]`, `["messages"]`, or both to transform the final compiled prompt. Message rules can filter by `roles`, `maxMessages`, `maxChars`, `minDepth`, and `maxDepth`, where depth `0` is the latest message. Replacements use JavaScript syntax (`$&` for the full match, `$1` for captures; `$0` is also accepted as a full-match alias, and `$$` escapes a literal `$`). `trimStrings` removes literal strings from expanded replacement matches/captures, matching SillyTavern's Trim Out behavior. Supported regex flags are `g`, `i`, `m`, `s`, and `u`.
|
|
560
|
-
|
|
561
|
-
To clean a completed assistant message after streaming, use `effect: "finalize"`:
|
|
562
|
-
|
|
563
|
-
```json
|
|
564
|
-
{
|
|
565
|
-
"id": "finalize-ooc",
|
|
566
|
-
"enabled": true,
|
|
567
|
-
"stage": "compiled",
|
|
568
|
-
"effect": "finalize",
|
|
569
|
-
"targets": ["messages"],
|
|
570
|
-
"roles": ["assistant"],
|
|
571
|
-
"pattern": "\\s*\\(OOC:[^)]+\\)",
|
|
572
|
-
"flags": "gi",
|
|
573
|
-
"replace": ""
|
|
574
|
-
}
|
|
575
|
-
```
|
|
144
|
+
### Develop and design
|
|
576
145
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
SillyTavern imports convert deterministic prompt-only `{{match}}` / `$0` full-match replacements to JavaScript `$&` (both `$0` and `$&` work in pi-forge), preserve original regex metadata in `source.sillytavern`, and run as history-stage rules so depth stays chat-relative. Display-only/browser/unsupported-placement scripts stay report-only. The web editor has a structured Regex dialog for these rule fields and preserves advanced unknown fields for raw JSON editing.
|
|
582
|
-
|
|
583
|
-
### Variables slot options
|
|
584
|
-
|
|
585
|
-
```json
|
|
586
|
-
{
|
|
587
|
-
"kind": "slot",
|
|
588
|
-
"id": "variables",
|
|
589
|
-
"enabled": true,
|
|
590
|
-
"role": "user",
|
|
591
|
-
"slot": "variables",
|
|
592
|
-
"options": {
|
|
593
|
-
"includeStatic": true,
|
|
594
|
-
"includeSession": true,
|
|
595
|
-
"includeTurn": false,
|
|
596
|
-
"format": "xml"
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
## Package setup for development
|
|
602
|
-
|
|
603
|
-
```bash
|
|
604
|
-
git clone https://github.com/MacroSony/pi-forge.git
|
|
605
|
-
cd pi-forge
|
|
606
|
-
npm install
|
|
607
|
-
npm run build
|
|
608
|
-
# .pi/settings.json loads the package's built dist/index.js
|
|
609
|
-
pi # start Pi, trust the project, /reload if needed
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
The npm package intentionally omits physical `src/` files and loads compiled `dist/` output at runtime. To inspect or modify pi-forge itself, clone or fork the repository instead of editing `node_modules` or generated `dist/` files. A clone preserves your changes in Git and includes the development dependencies, tests, and source-to-dist consistency checks.
|
|
613
|
-
|
|
614
|
-
For release-like local testing, register the cloned package directory. Its package manifest loads the tracked `dist/index.js`:
|
|
615
|
-
|
|
616
|
-
```json
|
|
617
|
-
{
|
|
618
|
-
"packages": ["../pi-forge"]
|
|
619
|
-
}
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
For live source development, remove that pi-forge package entry and load the TypeScript extension directly from `.pi/settings.json`:
|
|
623
|
-
|
|
624
|
-
```json
|
|
625
|
-
{
|
|
626
|
-
"extensions": ["../pi-forge/src/index.ts"]
|
|
627
|
-
}
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
You can also run `pi -e ../pi-forge/src/index.ts` for a one-off source-level smoke test. Do not load the package and source entry simultaneously or pi-forge will initialize twice. Browser-client source changes additionally require `npm run build:client` because the local editor serves its generated browser bundle.
|
|
631
|
-
|
|
632
|
-
Run tests:
|
|
633
|
-
|
|
634
|
-
```bash
|
|
635
|
-
npm test
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
Run the real-browser editor smoke test (set `CHROME_PATH` if Chrome is not in a standard location):
|
|
639
|
-
|
|
640
|
-
```bash
|
|
641
|
-
npm run test:browser
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
Typecheck:
|
|
645
|
-
|
|
646
|
-
```bash
|
|
647
|
-
npm run typecheck
|
|
648
|
-
```
|
|
649
|
-
|
|
650
|
-
Build package output:
|
|
651
|
-
|
|
652
|
-
```bash
|
|
653
|
-
npm run build
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
Run the full repository verification, including a clean temporary build that checks tracked `dist/` byte-for-byte against `src/`:
|
|
657
|
-
|
|
658
|
-
```bash
|
|
659
|
-
npm run verify
|
|
660
|
-
```
|
|
146
|
+
- [Development setup](docs/development/setup.md)
|
|
147
|
+
- [Release process](docs/development/release.md)
|
|
148
|
+
- [Roadmap](docs/development/roadmap.md)
|
|
149
|
+
- [Historical design archive](docs/design/README.md)
|
|
661
150
|
|
|
662
|
-
|
|
151
|
+
Chinese user documentation starts at [docs/zh-CN/README.md](docs/zh-CN/README.md).
|
|
663
152
|
|
|
664
153
|
## License
|
|
665
154
|
|
|
666
|
-
MIT
|
|
155
|
+
[MIT](LICENSE)
|