@zihanw/pi-forge 0.3.2 → 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 +196 -0
- package/PUBLIC_API.md +5 -0
- package/README.md +93 -478
- package/README.zh-CN.md +88 -461
- package/SUBAGENT_ADAPTER_CONTRACT.md +5 -0
- package/dist/agent-profile.d.ts +71 -0
- package/dist/agent-profile.d.ts.map +1 -0
- package/dist/agent-profile.js +303 -0
- package/dist/agent-profile.js.map +1 -0
- package/dist/forge-config.d.ts +88 -0
- package/dist/forge-config.d.ts.map +1 -0
- package/dist/forge-config.js +290 -0
- package/dist/forge-config.js.map +1 -0
- package/dist/forge-extensions.d.ts.map +1 -1
- package/dist/forge-extensions.js +19 -3
- package/dist/forge-extensions.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -358
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +11 -3
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +90 -4
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +116 -5
- package/dist/loader.js.map +1 -1
- package/dist/payload-capture.d.ts.map +1 -1
- package/dist/payload-capture.js +27 -0
- package/dist/payload-capture.js.map +1 -1
- package/dist/payload-command.d.ts +3 -3
- package/dist/payload-command.d.ts.map +1 -1
- package/dist/payload-command.js.map +1 -1
- package/dist/preview.d.ts +2 -2
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +2 -3
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.d.ts +12 -0
- package/dist/profile-command.d.ts.map +1 -0
- package/dist/profile-command.js +291 -0
- package/dist/profile-command.js.map +1 -0
- package/dist/profile-service.d.ts +103 -0
- package/dist/profile-service.d.ts.map +1 -0
- package/dist/profile-service.js +220 -0
- package/dist/profile-service.js.map +1 -0
- package/dist/runtime/profile-runtime.d.ts +13 -0
- package/dist/runtime/profile-runtime.d.ts.map +1 -0
- package/dist/runtime/profile-runtime.js +47 -0
- package/dist/runtime/profile-runtime.js.map +1 -0
- package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
- package/dist/runtime/prompt-stack-runtime.js +104 -0
- package/dist/runtime/prompt-stack-runtime.js.map +1 -0
- package/dist/runtime/subagent-runtime.d.ts +45 -0
- package/dist/runtime/subagent-runtime.d.ts.map +1 -0
- package/dist/runtime/subagent-runtime.js +335 -0
- package/dist/runtime/subagent-runtime.js.map +1 -0
- package/dist/runtime/tool-policy-runtime.d.ts +15 -0
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
- package/dist/runtime/tool-policy-runtime.js +170 -0
- package/dist/runtime/tool-policy-runtime.js.map +1 -0
- package/dist/runtime/web-editor-runtime.d.ts +9 -0
- package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
- package/dist/runtime/web-editor-runtime.js +131 -0
- package/dist/runtime/web-editor-runtime.js.map +1 -0
- package/dist/runtime-state.d.ts +4 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +2 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/storage.d.ts +4 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +24 -1
- package/dist/storage.js.map +1 -1
- package/dist/subagent/canonical.d.ts +22 -0
- package/dist/subagent/canonical.d.ts.map +1 -0
- package/dist/subagent/canonical.js +24 -0
- package/dist/subagent/canonical.js.map +1 -0
- package/dist/subagent/context.d.ts +8 -0
- package/dist/subagent/context.d.ts.map +1 -0
- package/dist/subagent/context.js +125 -0
- package/dist/subagent/context.js.map +1 -0
- package/dist/subagent/contract.d.ts +10 -0
- package/dist/subagent/contract.d.ts.map +1 -0
- package/dist/subagent/contract.js +10 -0
- package/dist/subagent/contract.js.map +1 -0
- package/dist/subagent/index.d.ts +14 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +14 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/plan.d.ts +18 -0
- package/dist/subagent/plan.d.ts.map +1 -0
- package/dist/subagent/plan.js +157 -0
- package/dist/subagent/plan.js.map +1 -0
- package/dist/subagent/preflight.d.ts +4 -0
- package/dist/subagent/preflight.d.ts.map +1 -0
- package/dist/subagent/preflight.js +108 -0
- package/dist/subagent/preflight.js.map +1 -0
- package/dist/subagent/request.d.ts +4 -0
- package/dist/subagent/request.d.ts.map +1 -0
- package/dist/subagent/request.js +122 -0
- package/dist/subagent/request.js.map +1 -0
- package/dist/subagent/response.d.ts +8 -0
- package/dist/subagent/response.d.ts.map +1 -0
- package/dist/subagent/response.js +155 -0
- package/dist/subagent/response.js.map +1 -0
- package/dist/subagent/tools.d.ts +4 -0
- package/dist/subagent/tools.d.ts.map +1 -0
- package/dist/subagent/tools.js +42 -0
- package/dist/subagent/tools.js.map +1 -0
- package/dist/subagent/types.d.ts +268 -0
- package/dist/subagent/types.d.ts.map +1 -0
- package/dist/subagent/types.js +3 -0
- package/dist/subagent/types.js.map +1 -0
- package/dist/subagent/validation.d.ts +35 -0
- package/dist/subagent/validation.d.ts.map +1 -0
- package/dist/subagent/validation.js +314 -0
- package/dist/subagent/validation.js.map +1 -0
- package/dist/subagent-command.d.ts +4 -0
- package/dist/subagent-command.d.ts.map +1 -0
- package/dist/subagent-command.js +246 -0
- package/dist/subagent-command.js.map +1 -0
- package/dist/subagent-host.d.ts +44 -0
- package/dist/subagent-host.d.ts.map +1 -0
- package/dist/subagent-host.js +292 -0
- package/dist/subagent-host.js.map +1 -0
- package/dist/subagent-profile-tool.d.ts +49 -0
- package/dist/subagent-profile-tool.d.ts.map +1 -0
- package/dist/subagent-profile-tool.js +124 -0
- package/dist/subagent-profile-tool.js.map +1 -0
- package/dist/subagent-tool.d.ts +53 -0
- package/dist/subagent-tool.d.ts.map +1 -0
- package/dist/subagent-tool.js +456 -0
- package/dist/subagent-tool.js.map +1 -0
- package/dist/web-editor/client-script.d.ts +2 -0
- package/dist/web-editor/client-script.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.d.ts +2 -0
- package/dist/web-editor/client-script.generated.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.js +3 -0
- package/dist/web-editor/client-script.generated.js.map +1 -0
- package/dist/web-editor/client-script.js +2 -0
- package/dist/web-editor/client-script.js.map +1 -0
- 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 +14 -3319
- 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 +2 -0
- package/dist/web-editor/styles.d.ts.map +1 -0
- package/dist/web-editor/styles.js +1053 -0
- package/dist/web-editor/styles.js.map +1 -0
- 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 +16 -5
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +307 -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 +55 -13
- package/src/compiler.ts +0 -578
- package/src/extension-registry.ts +0 -33
- package/src/forge-extensions.ts +0 -223
- package/src/index.ts +0 -445
- package/src/lifecycle.ts +0 -171
- package/src/loader.ts +0 -394
- package/src/macro-engine.ts +0 -358
- package/src/payload-capture.ts +0 -85
- package/src/payload-command.ts +0 -138
- package/src/policy.ts +0 -42
- package/src/preset-command.ts +0 -280
- package/src/preview.ts +0 -226
- package/src/regex.ts +0 -500
- package/src/render-helpers.ts +0 -169
- package/src/runtime-state.ts +0 -40
- package/src/sillytavern-importer/items.ts +0 -98
- package/src/sillytavern-importer/macros.ts +0 -159
- package/src/sillytavern-importer/prompt-order.ts +0 -54
- package/src/sillytavern-importer/regex.ts +0 -270
- package/src/sillytavern-importer/report.ts +0 -202
- package/src/sillytavern-importer/types.ts +0 -120
- package/src/sillytavern-importer.ts +0 -152
- package/src/slot-renderers.ts +0 -414
- package/src/stack-migration.ts +0 -159
- package/src/storage.ts +0 -45
- package/src/types.ts +0 -209
- package/src/web-editor/index.ts +0 -2
- package/src/web-editor/page.ts +0 -3330
- package/src/web-editor/server.ts +0 -294
- package/src/web-editor/types.ts +0 -98
- package/src/web-host.ts +0 -232
package/README.md
CHANGED
|
@@ -1,540 +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
|
-
-
|
|
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.
|
|
21
22
|
|
|
22
|
-
##
|
|
23
|
+
## Install
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
pi-forge requires Node.js 22.19 or newer.
|
|
25
26
|
|
|
26
27
|
```bash
|
|
27
28
|
pi install npm:@zihanw/pi-forge
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
|
|
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.
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
## Five-minute start
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
### 1. Create a prompt stack
|
|
36
|
+
|
|
37
|
+
Create `.pi/forge/prompt-stacks/default.json` from [the default Pi mirror](examples/default-prompt-stack.json):
|
|
35
38
|
|
|
36
39
|
```bash
|
|
37
40
|
mkdir -p .pi/forge/prompt-stacks
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
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`.
|
|
42
|
-
|
|
43
|
-
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`.
|
|
44
|
-
|
|
45
|
-
### Visual editor
|
|
46
|
-
|
|
47
|
-
Prefer clicking over typing JSON? pi-forge has a built-in web editor:
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
/preset ui
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
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. 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.
|
|
54
|
-
|
|
55
|
-
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.
|
|
56
|
-
|
|
57
|
-
The editor runs on an available `127.0.0.1` port with a session token, so multiple Pi instances can run editors at the same time. If Pi reinitializes the extension after session navigation or a new session, `/preset ui` reuses the existing editor URL for the same project instead of orphaning the old server. Writes require a trusted project and stay inside prompt-stack storage. New stacks are written to `.pi/forge/prompt-stacks`; existing legacy stacks under `.pi/prompt-stacks` remain readable and editable. Successful save, import, fork, and delete actions reload into the current Pi session. Use `/preset ui restart` or `/preset ui stop` when needed.
|
|
58
|
-
|
|
59
|
-
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.
|
|
60
|
-
|
|
61
|
-
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:
|
|
62
|
-
|
|
63
|
-
```json
|
|
64
|
-
{
|
|
65
|
-
"webEditor": {
|
|
66
|
-
"port": 41738
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Use cases
|
|
72
|
-
|
|
73
|
-
### 🎭 Roleplay & creative writing
|
|
74
|
-
|
|
75
|
-
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.
|
|
76
|
-
|
|
77
|
-
Useful pattern:
|
|
78
|
-
- Put long-term character rules in a `system` block.
|
|
79
|
-
- Keep Pi runtime context (tools, skills, project) in `user` slots.
|
|
80
|
-
- Set the `chat-history` slot to skip the latest user message.
|
|
81
|
-
- Add a final `user` block with `{{lastUserMessage}}`.
|
|
82
|
-
|
|
83
|
-
This keeps the latest request clear and avoids duplicating it.
|
|
84
|
-
|
|
85
|
-
For a baseline stack to fork before turning Pi into a character, start from [examples/default-prompt-stack.json](examples/default-prompt-stack.json).
|
|
86
|
-
|
|
87
|
-
### 🧑💻 Focused code review
|
|
88
|
-
|
|
89
|
-
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.
|
|
90
|
-
|
|
91
|
-
Use `mode: "append"` if you want to keep Pi's normal coding behavior and only add the sharper review lens.
|
|
92
|
-
|
|
93
|
-
### 🌐 Translation mode
|
|
94
|
-
|
|
95
|
-
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.
|
|
96
|
-
|
|
97
|
-
### 🔀 Multi-mode switching
|
|
98
|
-
|
|
99
|
-
Create separate stacks for different tasks:
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
.pi/forge/prompt-stacks/
|
|
103
|
-
coder.json # strict coding assistant
|
|
104
|
-
writer.json # creative writing partner
|
|
105
|
-
translator.json # bilingual translator
|
|
41
|
+
cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json
|
|
106
42
|
```
|
|
107
43
|
|
|
108
|
-
|
|
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.
|
|
109
45
|
|
|
110
|
-
|
|
46
|
+
Restart Pi or run:
|
|
111
47
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- **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.
|
|
116
|
-
- **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.
|
|
117
|
-
- **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.
|
|
118
|
-
- **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.
|
|
119
|
-
|
|
120
|
-
### 🔧 Template variables
|
|
121
|
-
|
|
122
|
-
```json
|
|
123
|
-
"variables": {
|
|
124
|
-
"char": "Konata",
|
|
125
|
-
"user": "User"
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Use static variables for stable prompt constants, and ST-style macros for local prompt-time mutation:
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
{{setvar::mood::focused}}
|
|
133
|
-
{{getvar::mood}}
|
|
134
|
-
{{setsessionvar::topic::compiler cleanup}}
|
|
48
|
+
```text
|
|
49
|
+
/preset reload
|
|
50
|
+
/preset use default
|
|
135
51
|
```
|
|
136
52
|
|
|
137
|
-
|
|
53
|
+
`default.json` auto-activates when no stack or restored session selection takes precedence.
|
|
138
54
|
|
|
139
|
-
###
|
|
55
|
+
### 2. Open the visual editor
|
|
140
56
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
/preset import-silly ~/SillyTavern/presets/my-preset.json
|
|
57
|
+
```text
|
|
58
|
+
/preset ui
|
|
145
59
|
```
|
|
146
60
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
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.
|
|
150
|
-
|
|
151
|
-
### 🔍 Prompt debugging
|
|
152
|
-
|
|
153
|
-
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.
|
|
154
62
|
|
|
155
|
-
|
|
156
|
-
/payload next save=.pi/forge/payloads/last.json
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Or open `/preset ui`, click **Arm payload**, send the next Pi prompt, and inspect the redacted provider payload in the browser.
|
|
63
|
+
### 3. Save a profile
|
|
160
64
|
|
|
161
|
-
|
|
65
|
+
Configure Pi normally, then capture and reuse the current settings:
|
|
162
66
|
|
|
67
|
+
```text
|
|
68
|
+
/profile save reviewer
|
|
69
|
+
/profile use reviewer
|
|
163
70
|
```
|
|
164
|
-
/preset preview
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## How it works
|
|
168
71
|
|
|
169
|
-
A
|
|
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.
|
|
170
73
|
|
|
171
|
-
|
|
172
|
-
|------|-------------|
|
|
173
|
-
| **Block** | Static text inserted at a specific position (system prompt, user message, assistant message) |
|
|
174
|
-
| **Slot** | Dynamic content from Pi's runtime — tools, skills, chat history, date, project context, etc. |
|
|
74
|
+
## The basic model
|
|
175
75
|
|
|
176
|
-
|
|
76
|
+
A prompt stack is an ordered JSON document containing:
|
|
177
77
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
5. Applies enabled outgoing regex rules for the `history` and `compiled` stages.
|
|
183
|
-
6. Optionally applies destructive `finalize` regex rules when an assistant message finishes.
|
|
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 |
|
|
184
82
|
|
|
185
|
-
|
|
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.
|
|
186
84
|
|
|
187
|
-
|
|
188
|
-
|------|----------------|
|
|
189
|
-
| `chat-history` | The current conversation |
|
|
190
|
-
| `tools` | Available tools and their descriptions |
|
|
191
|
-
| `tool-guidelines` | Tool usage instructions |
|
|
192
|
-
| `skills` | Loaded Pi skills |
|
|
193
|
-
| `project-context` | Project instructions and context files |
|
|
194
|
-
| `variables` | Static/session/turn template variables |
|
|
195
|
-
| `date` / `cwd` / `date-cwd` | Current date, optional current time, and working directory |
|
|
196
|
-
| `active-model` | Which model is being used |
|
|
197
|
-
| `append-system-prompt` | User's appended system prompt text |
|
|
198
|
-
| `pi-docs` | Pi documentation guidance |
|
|
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.
|
|
199
86
|
|
|
200
|
-
|
|
87
|
+
Start with these examples:
|
|
201
88
|
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
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.
|
|
205
93
|
|
|
206
94
|
## Common commands
|
|
207
95
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
|
211
|
-
|
|
212
|
-
| `/preset
|
|
213
|
-
| `/preset
|
|
214
|
-
| `/preset
|
|
215
|
-
| `/preset
|
|
216
|
-
| `/
|
|
217
|
-
| `/
|
|
218
|
-
| `/
|
|
219
|
-
| `/
|
|
220
|
-
| `/
|
|
221
|
-
| `/preset ui [stop\|restart]` | Open, stop, or restart the web editor |
|
|
222
|
-
|
|
223
|
-
### Import & debug
|
|
224
|
-
|
|
225
|
-
| Command | What it does |
|
|
226
|
-
|---------|-------------|
|
|
227
|
-
| `/preset import-silly <path>` | Import a SillyTavern preset |
|
|
228
|
-
| `/intercept` | Show the next provider payload |
|
|
229
|
-
| `/payload next [save=<path>]` | Show, save, and expose the next payload to the web editor |
|
|
230
|
-
|
|
231
|
-
## Common macros
|
|
232
|
-
|
|
233
|
-
Use these in block content to insert dynamic values:
|
|
234
|
-
|
|
235
|
-
| Macro | Expands to |
|
|
236
|
-
|-------|-----------|
|
|
237
|
-
| `{{lastUserMessage}}` | The user's latest message |
|
|
238
|
-
| `{{date}}` | Current date (YYYY-MM-DD) |
|
|
239
|
-
| `{{time}}` | Current time (HH:MM:SS) |
|
|
240
|
-
| `{{cwd}}` | Current working directory |
|
|
241
|
-
| `{{tools}}` | Comma-separated tool names |
|
|
242
|
-
| `{{selectedTools}}` | Alias for selected tool names |
|
|
243
|
-
| `{{activeModel}}` | Current model (provider/id) |
|
|
244
|
-
| `{{char}}` / `{{user}}` | Custom variables from your stack |
|
|
245
|
-
|
|
246
|
-
### Variable macros
|
|
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 |
|
|
106
|
+
| `/profile use <id>` | Preflight and apply a profile once |
|
|
107
|
+
| `/profile status` | Show last-applied provenance and runtime drift |
|
|
108
|
+
| `/payload next [save=<path>]` | Inspect the next redacted provider payload |
|
|
247
109
|
|
|
248
|
-
|
|
249
|
-
{{setvar::name::value}} set a turn variable (cleared each message)
|
|
250
|
-
{{setsessionvar::name::value}} set a session variable (persists)
|
|
251
|
-
{{setvar::session::name::value}} also set a session variable
|
|
252
|
-
{{getvar::name}} read a variable (turn → session → static)
|
|
253
|
-
{{getturnvar::name}} read only a turn variable
|
|
254
|
-
{{getsessionvar::name}} read only a session variable
|
|
255
|
-
{{clearvar::name}} clear a variable
|
|
256
|
-
{{clearturnvar::name}} clear a turn variable
|
|
257
|
-
{{clearsessionvar::name}} clear a session variable
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Filter and conditional macros
|
|
261
|
-
|
|
262
|
-
Nested macros are supported, and `::` separators are parsed only at the current macro depth.
|
|
263
|
-
|
|
264
|
-
| Macro | Expands to |
|
|
265
|
-
|-------|-----------|
|
|
266
|
-
| `{{trim::value}}` | `value` with leading/trailing whitespace removed |
|
|
267
|
-
| `{{upper::value}}` | Uppercase `value` |
|
|
268
|
-
| `{{lower::value}}` | Lowercase `value` |
|
|
269
|
-
| `{{json::value}}` | JSON string literal for `value` |
|
|
270
|
-
| `{{xml::value}}` | XML-escaped `value` |
|
|
271
|
-
| `{{ifvar::name::then::else}}` | `then` when a variable exists, otherwise `else` |
|
|
272
|
-
| `{{ifeq::name::expected::then::else}}` | `then` when a variable equals `expected`, otherwise `else` |
|
|
273
|
-
| `{{iftools::tool::then::else}}` | `then` when the selected tool list includes `tool`, otherwise `else` |
|
|
274
|
-
| `{{ifslot::slot::then::else}}` | `then` when the enabled stack items include `slot`, otherwise `else` |
|
|
275
|
-
|
|
276
|
-
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.
|
|
277
|
-
|
|
278
|
-
### Trusted custom macros and slots
|
|
279
|
-
|
|
280
|
-
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`.
|
|
281
|
-
|
|
282
|
-
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.
|
|
283
|
-
|
|
284
|
-
```ts
|
|
285
|
-
// .pi/forge/extensions/ticket-context.ts
|
|
286
|
-
export default function register(api) {
|
|
287
|
-
api.registerMacro({
|
|
288
|
-
name: "ticketId",
|
|
289
|
-
description: "Current ticket id from session variables.",
|
|
290
|
-
render: (ctx) => ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
api.registerSlot({
|
|
294
|
-
name: "ticket-context",
|
|
295
|
-
description: "Render ticket context for the current task.",
|
|
296
|
-
options: {
|
|
297
|
-
heading: { type: "string", default: "Ticket context" },
|
|
298
|
-
},
|
|
299
|
-
render: (ctx) => [
|
|
300
|
-
String(ctx.options.heading ?? "Ticket context") + ":",
|
|
301
|
-
"- Ticket: " + ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
302
|
-
"- Project: " + ctx.helpers.normalizePath(ctx.runtime.options.cwd),
|
|
303
|
-
].join("\n"),
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
The stack remains declarative:
|
|
309
|
-
|
|
310
|
-
```json
|
|
311
|
-
{
|
|
312
|
-
"kind": "slot",
|
|
313
|
-
"id": "ticket-context",
|
|
314
|
-
"enabled": true,
|
|
315
|
-
"role": "system",
|
|
316
|
-
"slot": "ticket-context",
|
|
317
|
-
"options": {
|
|
318
|
-
"heading": "Current ticket"
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
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.
|
|
324
|
-
|
|
325
|
-
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`.
|
|
110
|
+
See the [complete command reference](docs/reference/commands.md).
|
|
326
111
|
|
|
327
|
-
|
|
112
|
+
## Experimental foreground delegation
|
|
328
113
|
|
|
329
|
-
|
|
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`.
|
|
330
115
|
|
|
331
|
-
|
|
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.
|
|
332
117
|
|
|
333
|
-
|
|
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.
|
|
334
119
|
|
|
335
|
-
|
|
120
|
+
Read [foreground delegation and its safety model](docs/guides/delegation.md) before enabling it.
|
|
336
121
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
```json
|
|
340
|
-
{
|
|
341
|
-
"kind": "block",
|
|
342
|
-
"id": "unique-id",
|
|
343
|
-
"name": "Readable label",
|
|
344
|
-
"enabled": true,
|
|
345
|
-
"role": "system",
|
|
346
|
-
"content": "Your text here. Use {{macros}} for dynamic content."
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
Valid roles: `system`, `user`, `assistant`, `custom`.
|
|
351
|
-
|
|
352
|
-
**Slot:**
|
|
353
|
-
|
|
354
|
-
```json
|
|
355
|
-
{
|
|
356
|
-
"kind": "slot",
|
|
357
|
-
"id": "unique-id",
|
|
358
|
-
"name": "Chat History",
|
|
359
|
-
"enabled": true,
|
|
360
|
-
"role": "user",
|
|
361
|
-
"slot": "chat-history",
|
|
362
|
-
"options": {
|
|
363
|
-
"includeLastUserMessage": false
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Chat history options
|
|
369
|
-
|
|
370
|
-
```json
|
|
371
|
-
"options": {
|
|
372
|
-
"includeLastUserMessage": false,
|
|
373
|
-
"stripAssistantThinking": true,
|
|
374
|
-
"includeSummaries": true,
|
|
375
|
-
"toolMode": "keep",
|
|
376
|
-
"roles": ["user", "assistant"],
|
|
377
|
-
"maxMessages": 40,
|
|
378
|
-
"maxChars": 20000
|
|
379
|
-
}
|
|
380
|
-
```
|
|
122
|
+
## Documentation
|
|
381
123
|
|
|
382
|
-
|
|
124
|
+
### Learn
|
|
383
125
|
|
|
384
|
-
|
|
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)
|
|
385
134
|
|
|
386
|
-
|
|
135
|
+
### Reference
|
|
387
136
|
|
|
388
|
-
|
|
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)
|
|
389
143
|
|
|
390
|
-
|
|
144
|
+
### Develop and design
|
|
391
145
|
|
|
392
|
-
|
|
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)
|
|
393
150
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
```json
|
|
397
|
-
{
|
|
398
|
-
"kind": "slot",
|
|
399
|
-
"id": "tools",
|
|
400
|
-
"enabled": true,
|
|
401
|
-
"role": "system",
|
|
402
|
-
"slot": "tools",
|
|
403
|
-
"options": {
|
|
404
|
-
"format": "plain"
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
The default Pi mirror uses a few extra slot options:
|
|
410
|
-
|
|
411
|
-
```json
|
|
412
|
-
{
|
|
413
|
-
"slot": "tools",
|
|
414
|
-
"options": {
|
|
415
|
-
"format": "plain",
|
|
416
|
-
"onlyWithSnippets": true
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
`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.
|
|
422
|
-
|
|
423
|
-
### Tool and skill policy
|
|
424
|
-
|
|
425
|
-
Prompt stacks can constrain tools and skills with stack-level `allow` or `deny` lists. Patterns are exact by default and support `*` wildcards.
|
|
426
|
-
|
|
427
|
-
```json
|
|
428
|
-
{
|
|
429
|
-
"tools": {
|
|
430
|
-
"allow": ["read", "bash"]
|
|
431
|
-
},
|
|
432
|
-
"skills": {
|
|
433
|
-
"deny": ["browser-danger"]
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
Use `allow` when only matching tools or skills should remain active. Use `deny` when everything except matching tools or skills should remain active. A single resource policy cannot contain both non-empty lists; mixed `allow` and `deny` entries are validation errors.
|
|
439
|
-
|
|
440
|
-
Tool policy is enforced through Pi's active tool list while the stack is active. pi-forge remembers the previous active tools and restores them when prompt stacks are disabled or switched to an unrestricted stack.
|
|
441
|
-
|
|
442
|
-
Skill policy filters skills rendered by pi-forge's `skills` slot. If a stack uses `mode: "append"` or `"prepend"`, Pi's base prompt may already contain unfiltered skills; use `mode: "replace"` when skill visibility must be controlled.
|
|
443
|
-
|
|
444
|
-
### Regex transforms
|
|
445
|
-
|
|
446
|
-
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.
|
|
447
|
-
|
|
448
|
-
```json
|
|
449
|
-
"regex": {
|
|
450
|
-
"schemaVersion": 1,
|
|
451
|
-
"rules": [
|
|
452
|
-
{
|
|
453
|
-
"id": "trim-ooc",
|
|
454
|
-
"enabled": true,
|
|
455
|
-
"stage": "history",
|
|
456
|
-
"effect": "outgoing",
|
|
457
|
-
"pattern": "\\(OOC:[^)]+\\)",
|
|
458
|
-
"flags": "gi",
|
|
459
|
-
"replace": "",
|
|
460
|
-
"roles": ["assistant"],
|
|
461
|
-
"maxMessages": 20
|
|
462
|
-
}
|
|
463
|
-
]
|
|
464
|
-
}
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
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`.
|
|
468
|
-
|
|
469
|
-
To clean a completed assistant message after streaming, use `effect: "finalize"`:
|
|
470
|
-
|
|
471
|
-
```json
|
|
472
|
-
{
|
|
473
|
-
"id": "finalize-ooc",
|
|
474
|
-
"enabled": true,
|
|
475
|
-
"stage": "compiled",
|
|
476
|
-
"effect": "finalize",
|
|
477
|
-
"targets": ["messages"],
|
|
478
|
-
"roles": ["assistant"],
|
|
479
|
-
"pattern": "\\s*\\(OOC:[^)]+\\)",
|
|
480
|
-
"flags": "gi",
|
|
481
|
-
"replace": ""
|
|
482
|
-
}
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
Warning: `finalize` runs at `message_end`, after raw output may already have streamed in the TUI. It returns a cleaned replacement message to Pi, so the original model output is not preserved in the stored transcript.
|
|
486
|
-
|
|
487
|
-
`effect: "outgoing"` changes model input. `effect: "finalize"` changes finalized assistant transcript content. `effect: "display"` and `"both"` validate with warnings but are ignored at runtime until true display transforms are implemented.
|
|
488
|
-
|
|
489
|
-
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.
|
|
490
|
-
|
|
491
|
-
### Variables slot options
|
|
492
|
-
|
|
493
|
-
```json
|
|
494
|
-
{
|
|
495
|
-
"kind": "slot",
|
|
496
|
-
"id": "variables",
|
|
497
|
-
"enabled": true,
|
|
498
|
-
"role": "user",
|
|
499
|
-
"slot": "variables",
|
|
500
|
-
"options": {
|
|
501
|
-
"includeStatic": true,
|
|
502
|
-
"includeSession": true,
|
|
503
|
-
"includeTurn": false,
|
|
504
|
-
"format": "xml"
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
## Package setup for development
|
|
510
|
-
|
|
511
|
-
```bash
|
|
512
|
-
git clone <repo>
|
|
513
|
-
cd pi-forge
|
|
514
|
-
npm install
|
|
515
|
-
npm run build
|
|
516
|
-
# .pi/settings.json already points at the package root
|
|
517
|
-
pi # start Pi, trust the project, /reload if needed
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
Run tests:
|
|
521
|
-
|
|
522
|
-
```bash
|
|
523
|
-
npm test
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
Typecheck:
|
|
527
|
-
|
|
528
|
-
```bash
|
|
529
|
-
npm run typecheck
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
Build package output:
|
|
533
|
-
|
|
534
|
-
```bash
|
|
535
|
-
npm run build
|
|
536
|
-
```
|
|
151
|
+
Chinese user documentation starts at [docs/zh-CN/README.md](docs/zh-CN/README.md).
|
|
537
152
|
|
|
538
153
|
## License
|
|
539
154
|
|
|
540
|
-
MIT
|
|
155
|
+
[MIT](LICENSE)
|