@fleetagent/pi-coding-agent 0.0.5 → 0.0.7
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 +49 -0
- package/README.md +28 -5
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -3
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -2
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +13 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +130 -23
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/diagnostics.d.ts +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/diagnostics.js.map +1 -1
- package/dist/core/export-html/template.js +6 -3
- package/dist/core/extensions/runner.d.ts +5 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +13 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +65 -13
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +161 -24
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-agent.d.ts.map +1 -1
- package/dist/core/pi-agent.js +12 -3
- package/dist/core/pi-agent.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +30 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +94 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rules.d.ts +57 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +384 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/session/jsonl-helpers.d.ts +2 -1
- package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
- package/dist/core/session/jsonl-helpers.js +6 -3
- package/dist/core/session/jsonl-helpers.js.map +1 -1
- package/dist/core/session/local-session-manager.d.ts +1 -0
- package/dist/core/session/local-session-manager.d.ts.map +1 -1
- package/dist/core/session/local-session-manager.js +12 -4
- package/dist/core/session/local-session-manager.js.map +1 -1
- package/dist/core/session/session-manager.d.ts +1 -0
- package/dist/core/session/session-manager.d.ts.map +1 -1
- package/dist/core/session/session-manager.js.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts +2 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.js +105 -78
- package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +28 -9
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +3 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +11 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +73 -63
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +45 -76
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +27 -12
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +11 -2
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +3 -3
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +13 -4
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +1 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +37 -0
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +13 -8
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +24 -32
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -2
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +118 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +12 -3
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +14 -5
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +64 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +5 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +91 -18
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -3
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +3 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +14 -8
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/image-resize-core.d.ts +30 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -0
- package/dist/utils/image-resize-core.js +124 -0
- package/dist/utils/image-resize-core.js.map +1 -0
- package/dist/utils/image-resize-worker.d.ts +2 -0
- package/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/dist/utils/image-resize-worker.js +31 -0
- package/dist/utils/image-resize-worker.js.map +1 -0
- package/dist/utils/image-resize.d.ts +6 -27
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +60 -116
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/docs/custom-provider.md +22 -9
- package/docs/extensions.md +13 -11
- package/docs/index.md +3 -2
- package/docs/models.md +34 -12
- package/docs/packages.md +11 -8
- package/docs/providers.md +13 -5
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +4 -2
- package/docs/rules.md +102 -0
- package/docs/sdk.md +57 -1
- package/docs/settings.md +6 -3
- package/docs/terminal-setup.md +6 -0
- package/docs/usage.md +6 -4
- package/examples/extensions/README.md +2 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dynamic-resources/RULES.md +8 -0
- package/examples/extensions/dynamic-resources/index.ts +1 -0
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +1 -0
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +13 -12
- package/package.json +5 -5
package/docs/custom-provider.md
CHANGED
|
@@ -43,7 +43,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
43
43
|
pi.registerProvider("my-provider", {
|
|
44
44
|
name: "My Provider",
|
|
45
45
|
baseUrl: "https://api.example.com",
|
|
46
|
-
apiKey: "MY_API_KEY",
|
|
46
|
+
apiKey: "$MY_API_KEY",
|
|
47
47
|
api: "openai-completions",
|
|
48
48
|
models: [
|
|
49
49
|
{
|
|
@@ -83,7 +83,7 @@ pi.registerProvider("openai", {
|
|
|
83
83
|
pi.registerProvider("google", {
|
|
84
84
|
baseUrl: "https://ai-gateway.corp.com/google",
|
|
85
85
|
headers: {
|
|
86
|
-
"X-Corp-Auth": "CORP_AUTH_TOKEN" // env var or literal
|
|
86
|
+
"X-Corp-Auth": "$CORP_AUTH_TOKEN" // env var or literal
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
```
|
|
@@ -112,7 +112,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
112
112
|
|
|
113
113
|
pi.registerProvider("local-openai", {
|
|
114
114
|
baseUrl: "http://localhost:1234/v1",
|
|
115
|
-
apiKey: "LOCAL_OPENAI_API_KEY",
|
|
115
|
+
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
116
116
|
api: "openai-completions",
|
|
117
117
|
models: payload.data.map((model) => ({
|
|
118
118
|
id: model.id,
|
|
@@ -132,7 +132,7 @@ This registers the fetched models before startup finishes.
|
|
|
132
132
|
```typescript
|
|
133
133
|
pi.registerProvider("my-llm", {
|
|
134
134
|
baseUrl: "https://api.my-llm.com/v1",
|
|
135
|
-
apiKey: "MY_LLM_API_KEY", // env var
|
|
135
|
+
apiKey: "$MY_LLM_API_KEY", // env var reference
|
|
136
136
|
api: "openai-completions", // which streaming API to use
|
|
137
137
|
models: [
|
|
138
138
|
{
|
|
@@ -155,6 +155,8 @@ pi.registerProvider("my-llm", {
|
|
|
155
155
|
|
|
156
156
|
When `models` is provided, it **replaces** all existing models for that provider.
|
|
157
157
|
|
|
158
|
+
`apiKey` and custom header values use the same config value syntax as `models.json`: `!command` at the start executes a command for the whole value, `$ENV_VAR` and `${ENV_VAR}` interpolate environment variables, `$$` emits a literal `$`, and `$!` emits a literal `!`.
|
|
159
|
+
|
|
158
160
|
## Unregister Provider
|
|
159
161
|
|
|
160
162
|
Use `pi.unregisterProvider(name)` to remove a provider that was previously registered via `pi.registerProvider(name, ...)`:
|
|
@@ -163,7 +165,7 @@ Use `pi.unregisterProvider(name)` to remove a provider that was previously regis
|
|
|
163
165
|
// Register
|
|
164
166
|
pi.registerProvider("my-llm", {
|
|
165
167
|
baseUrl: "https://api.my-llm.com/v1",
|
|
166
|
-
apiKey: "MY_LLM_API_KEY",
|
|
168
|
+
apiKey: "$MY_LLM_API_KEY",
|
|
167
169
|
api: "openai-completions",
|
|
168
170
|
models: [
|
|
169
171
|
{
|
|
@@ -230,6 +232,9 @@ models: [{
|
|
|
230
232
|
Use `openrouter` for OpenRouter-style `reasoning: { effort }` controls. Use `together` for Together-style `reasoning: { enabled }` controls; with `supportsReasoningEffort`, it also sends `reasoning_effort`. Use `qwen-chat-template` instead for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking`.
|
|
231
233
|
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user/assistant text content.
|
|
232
234
|
|
|
235
|
+
For Anthropic-compatible providers using `api: "anthropic-messages"`, set `compat.forceAdaptiveThinking: true` on models or providers whose upstream model requires adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`). Built-in adaptive Claude models set this automatically. Set `compat.allowEmptySignature: true` only for providers that emit empty thinking signatures and expect `signature: ""` on replay.
|
|
236
|
+
|
|
237
|
+
|
|
233
238
|
> Migration note: Mistral moved from `openai-completions` to `mistral-conversations`.
|
|
234
239
|
> Use `mistral-conversations` for native Mistral models.
|
|
235
240
|
> If you intentionally route Mistral-compatible/custom endpoints through `openai-completions`, set `compat` flags explicitly as needed.
|
|
@@ -241,7 +246,7 @@ If your provider expects `Authorization: Bearer <key>` but doesn't use a standar
|
|
|
241
246
|
```typescript
|
|
242
247
|
pi.registerProvider("custom-api", {
|
|
243
248
|
baseUrl: "https://api.example.com",
|
|
244
|
-
apiKey: "MY_API_KEY",
|
|
249
|
+
apiKey: "$MY_API_KEY",
|
|
245
250
|
authHeader: true, // adds Authorization: Bearer header
|
|
246
251
|
api: "openai-completions",
|
|
247
252
|
models: [...]
|
|
@@ -568,7 +573,7 @@ Register your stream function:
|
|
|
568
573
|
```typescript
|
|
569
574
|
pi.registerProvider("my-provider", {
|
|
570
575
|
baseUrl: "https://api.example.com",
|
|
571
|
-
apiKey: "MY_API_KEY",
|
|
576
|
+
apiKey: "$MY_API_KEY",
|
|
572
577
|
api: "my-custom-api",
|
|
573
578
|
models: [...],
|
|
574
579
|
streamSimple: streamMyProvider
|
|
@@ -605,7 +610,7 @@ interface ProviderConfig {
|
|
|
605
610
|
/** API endpoint URL. Required when defining models. */
|
|
606
611
|
baseUrl?: string;
|
|
607
612
|
|
|
608
|
-
/** API key or
|
|
613
|
+
/** API key literal, env interpolation ($ENV_VAR or ${ENV_VAR}), or !command. Required when defining models (unless oauth). */
|
|
609
614
|
apiKey?: string;
|
|
610
615
|
|
|
611
616
|
/** API type for streaming. Required at provider or model level when defining models. */
|
|
@@ -618,7 +623,7 @@ interface ProviderConfig {
|
|
|
618
623
|
options?: SimpleStreamOptions
|
|
619
624
|
) => AssistantMessageEventStream;
|
|
620
625
|
|
|
621
|
-
/** Custom headers to include in requests. Values
|
|
626
|
+
/** Custom headers to include in requests. Values use the same resolution syntax as apiKey. */
|
|
622
627
|
headers?: Record<string, string>;
|
|
623
628
|
|
|
624
629
|
/** If true, adds Authorization: Bearer header with the resolved API key. */
|
|
@@ -693,6 +698,14 @@ interface ProviderModelConfig {
|
|
|
693
698
|
requiresReasoningContentOnAssistantMessages?: boolean;
|
|
694
699
|
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template";
|
|
695
700
|
cacheControlFormat?: "anthropic";
|
|
701
|
+
// anthropic-messages
|
|
702
|
+
supportsEagerToolInputStreaming?: boolean;
|
|
703
|
+
supportsLongCacheRetention?: boolean;
|
|
704
|
+
sendSessionAffinityHeaders?: boolean;
|
|
705
|
+
supportsCacheControlOnTools?: boolean;
|
|
706
|
+
forceAdaptiveThinking?: boolean;
|
|
707
|
+
allowEmptySignature?: boolean;
|
|
708
|
+
|
|
696
709
|
};
|
|
697
710
|
}
|
|
698
711
|
```
|
package/docs/extensions.md
CHANGED
|
@@ -199,7 +199,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
199
199
|
|
|
200
200
|
pi.registerProvider("local-openai", {
|
|
201
201
|
baseUrl: "http://localhost:1234/v1",
|
|
202
|
-
apiKey: "LOCAL_OPENAI_API_KEY",
|
|
202
|
+
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
203
203
|
api: "openai-completions",
|
|
204
204
|
models: payload.data.map((model) => ({
|
|
205
205
|
id: model.id,
|
|
@@ -338,7 +338,7 @@ exit (Ctrl+C, Ctrl+D, SIGHUP, SIGTERM)
|
|
|
338
338
|
|
|
339
339
|
#### resources_discover
|
|
340
340
|
|
|
341
|
-
Fired after `session_start` so extensions can contribute additional skill, prompt, and theme paths.
|
|
341
|
+
Fired after `session_start` so extensions can contribute additional skill, rule, prompt, and theme paths.
|
|
342
342
|
The startup path uses `reason: "startup"`. Reload uses `reason: "reload"`.
|
|
343
343
|
|
|
344
344
|
```typescript
|
|
@@ -347,6 +347,7 @@ pi.on("resources_discover", async (event, _ctx) => {
|
|
|
347
347
|
// event.reason - "startup" | "reload"
|
|
348
348
|
return {
|
|
349
349
|
skillPaths: ["/path/to/skills"],
|
|
350
|
+
rulePaths: ["/path/to/rules"],
|
|
350
351
|
promptPaths: ["/path/to/prompts"],
|
|
351
352
|
themePaths: ["/path/to/themes"],
|
|
352
353
|
};
|
|
@@ -813,7 +814,7 @@ Fired when user input is received, after extension commands are checked but befo
|
|
|
813
814
|
**Processing order:**
|
|
814
815
|
1. Extension commands (`/cmd`) checked first - if found, handler runs and input event is skipped
|
|
815
816
|
2. `input` event fires - can intercept, transform, or handle
|
|
816
|
-
3. If not handled: skill commands (`/skill:name`) expanded to
|
|
817
|
+
3. If not handled: skill/rule commands (`/skill:name`, `/rule:name`) expanded to their content
|
|
817
818
|
4. If not handled: prompt templates (`/template`) expanded to template content
|
|
818
819
|
5. Agent processing begins (`before_agent_start`, etc.)
|
|
819
820
|
|
|
@@ -836,8 +837,8 @@ pi.on("input", async (event, ctx) => {
|
|
|
836
837
|
// Route by source: skip processing for extension-injected messages
|
|
837
838
|
if (event.source === "extension") return { action: "continue" };
|
|
838
839
|
|
|
839
|
-
// Intercept skill commands before expansion
|
|
840
|
-
if (event.text.startsWith("/skill:")) {
|
|
840
|
+
// Intercept skill/rule commands before expansion
|
|
841
|
+
if (event.text.startsWith("/skill:") || event.text.startsWith("/rule:")) {
|
|
841
842
|
// Could transform, block, or let pass through
|
|
842
843
|
}
|
|
843
844
|
|
|
@@ -1161,7 +1162,7 @@ Run the same reload flow as `/reload`.
|
|
|
1161
1162
|
|
|
1162
1163
|
```typescript
|
|
1163
1164
|
pi.registerCommand("reload-runtime", {
|
|
1164
|
-
description: "Reload extensions, skills, prompts, and themes",
|
|
1165
|
+
description: "Reload extensions, skills, rules, prompts, and themes",
|
|
1165
1166
|
handler: async (_args, ctx) => {
|
|
1166
1167
|
await ctx.reload();
|
|
1167
1168
|
return;
|
|
@@ -1189,7 +1190,7 @@ import { Type } from "typebox";
|
|
|
1189
1190
|
|
|
1190
1191
|
export default function (pi: ExtensionAPI) {
|
|
1191
1192
|
pi.registerCommand("reload-runtime", {
|
|
1192
|
-
description: "Reload extensions, skills, prompts, and themes",
|
|
1193
|
+
description: "Reload extensions, skills, rules, prompts, and themes",
|
|
1193
1194
|
handler: async (_args, ctx) => {
|
|
1194
1195
|
await ctx.reload();
|
|
1195
1196
|
return;
|
|
@@ -1199,7 +1200,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1199
1200
|
pi.registerTool({
|
|
1200
1201
|
name: "reload_runtime",
|
|
1201
1202
|
label: "Reload Runtime",
|
|
1202
|
-
description: "Reload extensions, skills, prompts, and themes",
|
|
1203
|
+
description: "Reload extensions, skills, rules, prompts, and themes",
|
|
1203
1204
|
parameters: Type.Object({}),
|
|
1204
1205
|
async execute() {
|
|
1205
1206
|
pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
@@ -1409,7 +1410,7 @@ pi.registerCommand("deploy", {
|
|
|
1409
1410
|
|
|
1410
1411
|
### pi.getCommands()
|
|
1411
1412
|
|
|
1412
|
-
Get the slash commands available for invocation via `prompt` in the current session. Includes extension commands, prompt templates, and
|
|
1413
|
+
Get the slash commands available for invocation via `prompt` in the current session. Includes extension commands, prompt templates, skill commands, and rule commands.
|
|
1413
1414
|
The list matches the RPC `get_commands` ordering: extensions first, then templates, then skills.
|
|
1414
1415
|
|
|
1415
1416
|
```typescript
|
|
@@ -1554,7 +1555,7 @@ If you need to discover models from a remote endpoint, prefer an async extension
|
|
|
1554
1555
|
pi.registerProvider("my-proxy", {
|
|
1555
1556
|
name: "My Proxy",
|
|
1556
1557
|
baseUrl: "https://proxy.example.com",
|
|
1557
|
-
apiKey: "PROXY_API_KEY", // env var
|
|
1558
|
+
apiKey: "$PROXY_API_KEY", // env var reference
|
|
1558
1559
|
api: "anthropic-messages",
|
|
1559
1560
|
models: [
|
|
1560
1561
|
{
|
|
@@ -1601,7 +1602,7 @@ pi.registerProvider("corporate-ai", {
|
|
|
1601
1602
|
**Config options:**
|
|
1602
1603
|
- `name` - Display name for the provider in UI such as `/login`.
|
|
1603
1604
|
- `baseUrl` - API endpoint URL. Required when defining models.
|
|
1604
|
-
- `apiKey` - API key
|
|
1605
|
+
- `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
|
|
1605
1606
|
- `api` - API type: `"anthropic-messages"`, `"openai-completions"`, `"openai-responses"`, etc.
|
|
1606
1607
|
- `headers` - Custom headers to include in requests.
|
|
1607
1608
|
- `authHeader` - If true, adds `Authorization: Bearer` header automatically.
|
|
@@ -2556,6 +2557,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2556
2557
|
| `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
|
|
2557
2558
|
| `trigger-compact.ts` | Trigger compaction manually | `compact()` |
|
|
2558
2559
|
| `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
|
|
2560
|
+
| `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
|
|
2559
2561
|
| `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
|
|
2560
2562
|
| **UI Components** |||
|
|
2561
2563
|
| `status-line.ts` | Footer status indicator | `setStatus`, session events |
|
package/docs/index.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pi Documentation
|
|
2
2
|
|
|
3
|
-
Pi is a minimal terminal coding harness. It is designed to stay small at the core while being extended through TypeScript extensions, skills, prompt templates, themes, and pi packages.
|
|
3
|
+
Pi is a minimal terminal coding harness. It is designed to stay small at the core while being extended through TypeScript extensions, skills, rules, prompt templates, themes, and pi packages.
|
|
4
4
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
@@ -50,9 +50,10 @@ For the full first-run flow, see [Quickstart](quickstart.md).
|
|
|
50
50
|
|
|
51
51
|
- [Extensions](extensions.md) - TypeScript modules for tools, commands, events, and custom UI.
|
|
52
52
|
- [Skills](skills.md) - Agent Skills for reusable on-demand capabilities.
|
|
53
|
+
- [Rules](rules.md) - on-demand mandatory constraints and policies.
|
|
53
54
|
- [Prompt templates](prompt-templates.md) - reusable prompts that expand from slash commands.
|
|
54
55
|
- [Themes](themes.md) - built-in and custom terminal themes.
|
|
55
|
-
- [Pi packages](packages.md) - bundle and share extensions, skills, prompts, and themes.
|
|
56
|
+
- [Pi packages](packages.md) - bundle and share extensions, skills, rules, prompts, and themes.
|
|
56
57
|
- [Custom models](models.md) - add model entries for supported provider APIs.
|
|
57
58
|
- [Custom providers](custom-provider.md) - implement custom APIs and OAuth flows.
|
|
58
59
|
|
package/docs/models.md
CHANGED
|
@@ -101,7 +101,7 @@ Use `google-generative-ai` with a `baseUrl` to add models from Google AI Studio,
|
|
|
101
101
|
"my-google": {
|
|
102
102
|
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
|
|
103
103
|
"api": "google-generative-ai",
|
|
104
|
-
"apiKey": "GEMINI_API_KEY",
|
|
104
|
+
"apiKey": "$GEMINI_API_KEY",
|
|
105
105
|
"models": [
|
|
106
106
|
{
|
|
107
107
|
"id": "gemma-4-31b-it",
|
|
@@ -143,22 +143,31 @@ Set `api` at provider level (default for all models) or model level (override pe
|
|
|
143
143
|
|
|
144
144
|
### Value Resolution
|
|
145
145
|
|
|
146
|
-
The `apiKey` and `headers` fields support
|
|
146
|
+
The `apiKey` and `headers` fields support command execution, environment interpolation, and literals:
|
|
147
147
|
|
|
148
|
-
- **Shell command:** `"!command"` executes and uses stdout
|
|
148
|
+
- **Shell command:** `"!command"` at the start executes the whole value as a command and uses stdout
|
|
149
149
|
```json
|
|
150
150
|
"apiKey": "!security find-generic-password -ws 'anthropic'"
|
|
151
151
|
"apiKey": "!op read 'op://vault/item/credential'"
|
|
152
152
|
```
|
|
153
|
-
- **Environment
|
|
153
|
+
- **Environment interpolation:** `"$ENV_VAR"` or `"${ENV_VAR}"` uses the value of the named variable. Interpolation works inside larger literals.
|
|
154
154
|
```json
|
|
155
|
-
"apiKey": "MY_API_KEY"
|
|
155
|
+
"apiKey": "$MY_API_KEY"
|
|
156
|
+
"apiKey": "${KEY_PREFIX}_${KEY_SUFFIX}"
|
|
157
|
+
```
|
|
158
|
+
`$FOO_BAR` is the variable `FOO_BAR`; use `${FOO}_BAR` when `BAR` is literal text. Missing environment variables make the value unresolved.
|
|
159
|
+
- **Escapes:** `"$$"` emits a literal `"$"`; `"$!"` emits a literal `"!"` without triggering command execution.
|
|
160
|
+
```json
|
|
161
|
+
"apiKey": "$$literal-dollar-prefix"
|
|
162
|
+
"apiKey": "$!literal-bang-prefix"
|
|
156
163
|
```
|
|
157
164
|
- **Literal value:** Used directly
|
|
158
165
|
```json
|
|
159
166
|
"apiKey": "sk-..."
|
|
160
167
|
```
|
|
161
168
|
|
|
169
|
+
Legacy uppercase env-var-like values such as `MY_API_KEY` are migrated to `$MY_API_KEY` on startup.
|
|
170
|
+
|
|
162
171
|
For `models.json`, shell commands are resolved at request time. pi intentionally does not apply built-in TTL, stale reuse, or recovery logic for arbitrary commands. Different commands need different caching and failure strategies, and pi cannot infer the right one.
|
|
163
172
|
|
|
164
173
|
If your command is slow, expensive, rate-limited, or should keep using a previous value on transient failures, wrap it in your own script or command that implements the caching or TTL behavior you want.
|
|
@@ -172,10 +181,10 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
|
|
|
172
181
|
"providers": {
|
|
173
182
|
"custom-proxy": {
|
|
174
183
|
"baseUrl": "https://proxy.example.com/v1",
|
|
175
|
-
"apiKey": "MY_API_KEY",
|
|
184
|
+
"apiKey": "$MY_API_KEY",
|
|
176
185
|
"api": "anthropic-messages",
|
|
177
186
|
"headers": {
|
|
178
|
-
"x-portkey-api-key": "PORTKEY_API_KEY",
|
|
187
|
+
"x-portkey-api-key": "$PORTKEY_API_KEY",
|
|
179
188
|
"x-secret": "!op read 'op://vault/item/secret'"
|
|
180
189
|
},
|
|
181
190
|
"models": [...]
|
|
@@ -268,7 +277,7 @@ To merge custom models into a built-in provider, include the `models` array:
|
|
|
268
277
|
"providers": {
|
|
269
278
|
"anthropic": {
|
|
270
279
|
"baseUrl": "https://my-proxy.example.com/v1",
|
|
271
|
-
"apiKey": "ANTHROPIC_API_KEY",
|
|
280
|
+
"apiKey": "$ANTHROPIC_API_KEY",
|
|
272
281
|
"api": "anthropic-messages",
|
|
273
282
|
"models": [...]
|
|
274
283
|
}
|
|
@@ -319,16 +328,24 @@ For providers or proxies using `api: "anthropic-messages"`, use `compat.supports
|
|
|
319
328
|
|
|
320
329
|
By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthropic-compatible backend rejects that field, set `supportsEagerToolInputStreaming` to `false`. Pi will omit `tools[].eager_input_streaming` and send the legacy `fine-grained-tool-streaming-2025-05-14` beta header for tool-enabled requests instead.
|
|
321
330
|
|
|
331
|
+
Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) instead of the legacy budget-based thinking payload. Built-in models set this automatically. For custom providers or aliases that route to those models, set `forceAdaptiveThinking` to `true`.
|
|
332
|
+
|
|
333
|
+
Some Anthropic-compatible providers emit thinking blocks with empty signatures and still expect them on replay. Set `allowEmptySignature` to `true` only for those providers; real Anthropic rejects empty thinking signatures.
|
|
334
|
+
|
|
335
|
+
|
|
322
336
|
```json
|
|
323
337
|
{
|
|
324
338
|
"providers": {
|
|
325
339
|
"anthropic-proxy": {
|
|
326
340
|
"baseUrl": "https://proxy.example.com",
|
|
327
341
|
"api": "anthropic-messages",
|
|
328
|
-
"apiKey": "ANTHROPIC_PROXY_KEY",
|
|
342
|
+
"apiKey": "$ANTHROPIC_PROXY_KEY",
|
|
329
343
|
"compat": {
|
|
330
344
|
"supportsEagerToolInputStreaming": false,
|
|
331
|
-
"supportsLongCacheRetention": true
|
|
345
|
+
"supportsLongCacheRetention": true,
|
|
346
|
+
"forceAdaptiveThinking": true,
|
|
347
|
+
"allowEmptySignature": true
|
|
348
|
+
|
|
332
349
|
},
|
|
333
350
|
"models": [
|
|
334
351
|
{
|
|
@@ -346,6 +363,11 @@ By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthro
|
|
|
346
363
|
|-------|-------------|
|
|
347
364
|
| `supportsEagerToolInputStreaming` | Whether the provider accepts per-tool `eager_input_streaming`. Default: `true`. Set to `false` to omit that field and use the legacy fine-grained tool streaming beta header on tool-enabled requests. |
|
|
348
365
|
| `supportsLongCacheRetention` | Whether the provider accepts Anthropic long cache retention (`cache_control.ttl: "1h"`) when cache retention is `long`. Default: `true`. |
|
|
366
|
+
| `sendSessionAffinityHeaders` | Whether to send `x-session-affinity` from the session id when caching is enabled. Default: auto-detected for known providers. |
|
|
367
|
+
| `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
|
|
368
|
+
| `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
|
|
369
|
+
| `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
|
|
370
|
+
|
|
349
371
|
|
|
350
372
|
## OpenAI Compatibility
|
|
351
373
|
|
|
@@ -399,7 +421,7 @@ Example:
|
|
|
399
421
|
"providers": {
|
|
400
422
|
"openrouter": {
|
|
401
423
|
"baseUrl": "https://openrouter.ai/api/v1",
|
|
402
|
-
"apiKey": "OPENROUTER_API_KEY",
|
|
424
|
+
"apiKey": "$OPENROUTER_API_KEY",
|
|
403
425
|
"api": "openai-completions",
|
|
404
426
|
"models": [
|
|
405
427
|
{
|
|
@@ -449,7 +471,7 @@ Vercel AI Gateway example:
|
|
|
449
471
|
"providers": {
|
|
450
472
|
"vercel-ai-gateway": {
|
|
451
473
|
"baseUrl": "https://ai-gateway.vercel.sh/v1",
|
|
452
|
-
"apiKey": "AI_GATEWAY_API_KEY",
|
|
474
|
+
"apiKey": "$AI_GATEWAY_API_KEY",
|
|
453
475
|
"api": "openai-completions",
|
|
454
476
|
"models": [
|
|
455
477
|
{
|
package/docs/packages.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
> pi can help you create pi packages. Ask it to bundle your extensions, skills, prompt templates, or themes.
|
|
1
|
+
> pi can help you create pi packages. Ask it to bundle your extensions, skills, rules, prompt templates, or themes.
|
|
2
2
|
|
|
3
3
|
# Pi Packages
|
|
4
4
|
|
|
5
|
-
Pi packages bundle extensions, skills, prompt templates, and themes so you can share them through npm or git. A package can declare resources in `package.json` under the `pi` key, or use conventional directories.
|
|
5
|
+
Pi packages bundle extensions, skills, rules, prompt templates, and themes so you can share them through npm or git. A package can declare resources in `package.json` under the `pi` key, or use conventional directories.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
|
@@ -28,8 +28,8 @@ pi install ./relative/path/to/package
|
|
|
28
28
|
|
|
29
29
|
pi remove npm:@foo/bar
|
|
30
30
|
pi list # show installed packages from settings
|
|
31
|
-
pi update # update pi and
|
|
32
|
-
pi update --extensions # update
|
|
31
|
+
pi update # update pi, update packages, and reconcile pinned git refs
|
|
32
|
+
pi update --extensions # update packages and reconcile pinned git refs only
|
|
33
33
|
pi update --self # update pi only
|
|
34
34
|
pi update --self --force # reinstall pi even if current
|
|
35
35
|
pi update npm:@foo/bar # update one package
|
|
@@ -85,9 +85,10 @@ ssh://git@github.com/user/repo@v1
|
|
|
85
85
|
- HTTPS and SSH URLs are both supported.
|
|
86
86
|
- SSH URLs use your configured SSH keys automatically (respects `~/.ssh/config`).
|
|
87
87
|
- For non-interactive runs (for example CI), you can set `GIT_TERMINAL_PROMPT=0` to disable credential prompts and set `GIT_SSH_COMMAND` (for example `ssh -o BatchMode=yes -o ConnectTimeout=5`) to fail fast.
|
|
88
|
-
- Refs are pinned tags or commits
|
|
88
|
+
- Refs are pinned tags or commits. `pi update` and `pi update --extensions` do not move them to newer refs, but they do reconcile an existing clone to the configured ref.
|
|
89
|
+
- Use `pi install git:host/user/repo@new-ref` to update settings and move an existing package to a new pinned ref.
|
|
89
90
|
- Cloned to `~/.pi/agent/git/<host>/<path>` (global) or `.pi/git/<host>/<path>` (project).
|
|
90
|
-
-
|
|
91
|
+
- When reconciliation changes the checkout, pi resets and cleans the clone, then runs `npm install` if `package.json` exists.
|
|
91
92
|
|
|
92
93
|
**SSH examples:**
|
|
93
94
|
```bash
|
|
@@ -121,6 +122,7 @@ Add a `pi` manifest to `package.json` or use conventional directories. Include t
|
|
|
121
122
|
"pi": {
|
|
122
123
|
"extensions": ["./extensions"],
|
|
123
124
|
"skills": ["./skills"],
|
|
125
|
+
"rules": ["./rules"],
|
|
124
126
|
"prompts": ["./prompts"],
|
|
125
127
|
"themes": ["./themes"]
|
|
126
128
|
}
|
|
@@ -158,12 +160,13 @@ If no `pi` manifest is present, pi auto-discovers resources from these directori
|
|
|
158
160
|
|
|
159
161
|
- `extensions/` loads `.ts` and `.js` files
|
|
160
162
|
- `skills/` recursively finds `SKILL.md` folders and loads top-level `.md` files as skills
|
|
163
|
+
- `rules/` recursively finds `RULES.md` folders and loads top-level `.md` files as rules
|
|
161
164
|
- `prompts/` loads `.md` files
|
|
162
165
|
- `themes/` loads `.json` files
|
|
163
166
|
|
|
164
167
|
## Dependencies
|
|
165
168
|
|
|
166
|
-
Third party runtime dependencies belong in `dependencies` in `package.json`. Dependencies that do not register extensions, skills, prompt templates, or themes also belong in `dependencies`. When pi installs a package from npm or git, it runs `npm install`, so those dependencies are installed automatically.
|
|
169
|
+
Third party runtime dependencies belong in `dependencies` in `package.json`. Dependencies that do not register extensions, skills, rules, prompt templates, or themes also belong in `dependencies`. When pi installs a package from npm or git, it runs `npm install`, so those dependencies are installed automatically.
|
|
167
170
|
|
|
168
171
|
Pi bundles core packages for extensions and skills. If you import any of these, list them in `peerDependencies` with a `"*"` range and do not bundle them: `@fleetagent/pi-ai`, `@fleetagent/pi-agent-core`, `@fleetagent/pi-coding-agent`, `@fleetagent/pi-tui`, `typebox`.
|
|
169
172
|
|
|
@@ -214,7 +217,7 @@ Filter what a package loads using the object form in settings:
|
|
|
214
217
|
|
|
215
218
|
## Enable and Disable Resources
|
|
216
219
|
|
|
217
|
-
Use `pi config` to enable or disable extensions, skills, prompt templates, and themes from installed packages and local directories. Works for both global (`~/.pi/agent`) and project (`.pi/`) scopes.
|
|
220
|
+
Use `pi config` to enable or disable extensions, skills, rules, prompt templates, and themes from installed packages and local directories. Works for both global (`~/.pi/agent`) and project (`.pi/`) scopes.
|
|
218
221
|
|
|
219
222
|
## Scope and Deduplication
|
|
220
223
|
|
package/docs/providers.md
CHANGED
|
@@ -101,23 +101,31 @@ The file is created with `0600` permissions (user read/write only). Auth file cr
|
|
|
101
101
|
|
|
102
102
|
### Key Resolution
|
|
103
103
|
|
|
104
|
-
The `key` field supports
|
|
104
|
+
The `key` field supports command execution, environment interpolation, and literals:
|
|
105
105
|
|
|
106
|
-
- **Shell command:** `"!command"` executes and uses stdout (cached for process lifetime)
|
|
106
|
+
- **Shell command:** `"!command"` at the start executes the whole value as a command and uses stdout (cached for process lifetime)
|
|
107
107
|
```json
|
|
108
108
|
{ "type": "api_key", "key": "!security find-generic-password -ws 'anthropic'" }
|
|
109
109
|
{ "type": "api_key", "key": "!op read 'op://vault/item/credential'" }
|
|
110
110
|
```
|
|
111
|
-
- **Environment
|
|
111
|
+
- **Environment interpolation:** `"$ENV_VAR"` or `"${ENV_VAR}"` uses the value of the named variable. Interpolation works inside larger literals.
|
|
112
112
|
```json
|
|
113
|
-
{ "type": "api_key", "key": "MY_ANTHROPIC_KEY" }
|
|
113
|
+
{ "type": "api_key", "key": "$MY_ANTHROPIC_KEY" }
|
|
114
|
+
{ "type": "api_key", "key": "${KEY_PREFIX}_${KEY_SUFFIX}" }
|
|
115
|
+
```
|
|
116
|
+
`$FOO_BAR` is the variable `FOO_BAR`; use `${FOO}_BAR` when `BAR` is literal text. Missing environment variables make the value unresolved.
|
|
117
|
+
- **Escapes:** `"$$"` emits a literal `"$"`; `"$!"` emits a literal `"!"` without triggering command execution.
|
|
118
|
+
```json
|
|
119
|
+
{ "type": "api_key", "key": "$$literal-dollar-prefix" }
|
|
120
|
+
{ "type": "api_key", "key": "$!literal-bang-prefix" }
|
|
114
121
|
```
|
|
115
122
|
- **Literal value:** Used directly
|
|
116
123
|
```json
|
|
117
124
|
{ "type": "api_key", "key": "sk-ant-..." }
|
|
125
|
+
{ "type": "api_key", "key": "public" }
|
|
118
126
|
```
|
|
119
127
|
|
|
120
|
-
OAuth credentials are also stored here after `/login` and managed automatically.
|
|
128
|
+
Legacy uppercase env-var-like values such as `MY_API_KEY` are migrated to `$MY_API_KEY` on startup. OAuth credentials are also stored here after `/login` and managed automatically.
|
|
121
129
|
|
|
122
130
|
## Cloud Providers
|
|
123
131
|
|
package/docs/quickstart.md
CHANGED
|
@@ -159,6 +159,6 @@ Use `--mode json` for JSON event output or `--mode rpc` for process integration.
|
|
|
159
159
|
- [Providers](providers.md) - authentication and model setup.
|
|
160
160
|
- [Settings](settings.md) - global and project configuration.
|
|
161
161
|
- [Keybindings](keybindings.md) - shortcuts and customization.
|
|
162
|
-
- [Pi Packages](packages.md) - install shared extensions, skills, prompts, and themes.
|
|
162
|
+
- [Pi Packages](packages.md) - install shared extensions, skills, rules, prompts, and themes.
|
|
163
163
|
|
|
164
164
|
Platform notes: [Windows](windows.md), [Termux](termux.md), [tmux](tmux.md), [Terminal setup](terminal-setup.md), [Shell aliases](shell-aliases.md).
|
package/docs/rpc.md
CHANGED
|
@@ -700,7 +700,7 @@ The current session name is available via `get_state` in the `sessionName` field
|
|
|
700
700
|
|
|
701
701
|
#### get_commands
|
|
702
702
|
|
|
703
|
-
Get available commands (extension commands, prompt templates, and
|
|
703
|
+
Get available commands (extension commands, prompt templates, skills, and rules). These can be invoked via the `prompt` command by prefixing with `/`.
|
|
704
704
|
|
|
705
705
|
```json
|
|
706
706
|
{"type": "get_commands"}
|
|
@@ -716,7 +716,8 @@ Response:
|
|
|
716
716
|
"commands": [
|
|
717
717
|
{"name": "session-name", "description": "Set or clear session name", "source": "extension", "path": "/home/user/.pi/agent/extensions/session.ts"},
|
|
718
718
|
{"name": "fix-tests", "description": "Fix failing tests", "source": "prompt", "location": "project", "path": "/home/user/myproject/.pi/agent/prompts/fix-tests.md"},
|
|
719
|
-
{"name": "skill:brave-search", "description": "Web search via Brave API", "source": "skill", "location": "user", "path": "/home/user/.pi/agent/skills/brave-search/SKILL.md"}
|
|
719
|
+
{"name": "skill:brave-search", "description": "Web search via Brave API", "source": "skill", "location": "user", "path": "/home/user/.pi/agent/skills/brave-search/SKILL.md"},
|
|
720
|
+
{"name": "rule:typescript", "description": "Mandatory TypeScript rules", "source": "rule", "location": "project", "path": "/home/user/myproject/.pi/rules/typescript/RULES.md"}
|
|
720
721
|
]
|
|
721
722
|
}
|
|
722
723
|
}
|
|
@@ -729,6 +730,7 @@ Each command has:
|
|
|
729
730
|
- `"extension"`: Registered via `pi.registerCommand()` in an extension
|
|
730
731
|
- `"prompt"`: Loaded from a prompt template `.md` file
|
|
731
732
|
- `"skill"`: Loaded from a skill directory (name is prefixed with `skill:`)
|
|
733
|
+
- `"rule"`: Loaded from a rule directory (name is prefixed with `rule:`)
|
|
732
734
|
- `location`: Where it was loaded from (optional, not present for extensions):
|
|
733
735
|
- `"user"`: User-level (`~/.pi/agent/`)
|
|
734
736
|
- `"project"`: Project-level (`./.pi/agent/`)
|
package/docs/rules.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Rules
|
|
2
|
+
|
|
3
|
+
Rules are on-demand, mandatory instruction files. Use them for constraints and policies that must apply when the current task or files match the rule description.
|
|
4
|
+
|
|
5
|
+
Rules use progressive disclosure like skills: pi lists available rules in the system prompt, and the agent loads the full file only when applicable.
|
|
6
|
+
|
|
7
|
+
## Locations
|
|
8
|
+
|
|
9
|
+
Pi loads rules from:
|
|
10
|
+
|
|
11
|
+
- Global:
|
|
12
|
+
- `~/.pi/agent/rules/`
|
|
13
|
+
- `~/.agents/rules/`
|
|
14
|
+
- Project:
|
|
15
|
+
- `.pi/rules/`
|
|
16
|
+
- `.agents/rules/` in `cwd` and ancestor directories (up to git repo root, or filesystem root when not in a repo)
|
|
17
|
+
- Packages: `rules/` directories or `pi.rules` entries in `package.json`
|
|
18
|
+
- Settings: `rules` array with files or directories
|
|
19
|
+
- CLI: `--rule <path>` (repeatable, additive even with `--no-rules`)
|
|
20
|
+
|
|
21
|
+
Discovery rules:
|
|
22
|
+
|
|
23
|
+
- In `~/.pi/agent/rules/` and `.pi/rules/`, direct root `.md` files are discovered as individual rules
|
|
24
|
+
- In all rule locations, directories containing `RULES.md` are discovered recursively
|
|
25
|
+
- In `~/.agents/rules/` and project `.agents/rules/`, root `.md` files are ignored
|
|
26
|
+
|
|
27
|
+
Disable discovery with `--no-rules` (explicit `--rule` paths still load).
|
|
28
|
+
|
|
29
|
+
## How Rules Work
|
|
30
|
+
|
|
31
|
+
1. At startup, pi scans rule locations and extracts names and descriptions
|
|
32
|
+
2. The system prompt includes available rules in XML format
|
|
33
|
+
3. When a task or file matches, the agent uses `read` to load the full `RULES.md`
|
|
34
|
+
4. Applicable rules are mandatory and constrain normal behavior and skills
|
|
35
|
+
|
|
36
|
+
Only descriptions are always in context. Full instructions load on demand.
|
|
37
|
+
|
|
38
|
+
## Rule Commands
|
|
39
|
+
|
|
40
|
+
Rules register as `/rule:name` commands when skill commands are enabled:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
/rule:typescript # Load the rule
|
|
44
|
+
/rule:naming-conventions use for new files
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Arguments after the command are appended to the rule content as user text.
|
|
48
|
+
|
|
49
|
+
## Rule Structure
|
|
50
|
+
|
|
51
|
+
A rule is a directory with a `RULES.md` file. Everything else is freeform.
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
typescript/
|
|
55
|
+
├── RULES.md
|
|
56
|
+
└── references/
|
|
57
|
+
└── examples.md
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### RULES.md Format
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
---
|
|
64
|
+
name: typescript
|
|
65
|
+
description: Mandatory TypeScript rules. Load before editing *.ts or *.tsx files.
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# TypeScript Rules
|
|
69
|
+
|
|
70
|
+
- No `any` unless absolutely necessary.
|
|
71
|
+
- Use top-level imports only.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Use relative paths from the rule directory:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
See [examples](references/examples.md).
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Frontmatter
|
|
81
|
+
|
|
82
|
+
| Field | Required | Description |
|
|
83
|
+
|-------|----------|-------------|
|
|
84
|
+
| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. Falls back to parent directory name. |
|
|
85
|
+
| `description` | Yes | Max 1024 chars. Defines when the rule applies. |
|
|
86
|
+
| `disable-model-invocation` | No | When `true`, the rule is hidden from the system prompt. Users must use `/rule:name`. |
|
|
87
|
+
|
|
88
|
+
## Description Best Practices
|
|
89
|
+
|
|
90
|
+
The description determines when the agent loads the rule. Write applicability, not capability.
|
|
91
|
+
|
|
92
|
+
Good:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
description: Mandatory TypeScript rules. Load before editing *.ts or *.tsx files.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Poor:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
description: TypeScript help.
|
|
102
|
+
```
|