pi-squire 0.14.0 → 0.15.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 +116 -1
- package/README.md +179 -70
- package/package.json +3 -3
- package/src/agents.ts +361 -111
- package/src/child.ts +72 -21
- package/src/index.ts +242 -66
- package/src/navigator.ts +1 -1
- package/src/new-delegate.ts +17 -8
- package/src/result-sessions.ts +39 -0
- package/src/results.ts +2 -0
- package/src/resume-checks.ts +45 -12
- package/src/resume.ts +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,108 @@ follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.15.0] - 2026-10-30
|
|
10
|
+
|
|
11
|
+
### Breaking
|
|
12
|
+
|
|
13
|
+
- Agents move to one file per agent in the agents folders Pi agent tooling
|
|
14
|
+
shares: `<agent dir>/agents/<name>.md` and, when the project is trusted,
|
|
15
|
+
`<cwd>/.pi/agents/<name>.md`, which replaces a global file of the same name.
|
|
16
|
+
`<agent dir>/squire/agents/<name>/AGENT.md` is no longer read; while that
|
|
17
|
+
folder exists, a warning says so. `squire/delegation_prompt.md` stays where
|
|
18
|
+
it is.
|
|
19
|
+
- The body is now wrapped in `<agent_instructions>` lines by default
|
|
20
|
+
(`prompt_mode: append`). `prompt_mode: replace` builds the delegate's prompt
|
|
21
|
+
exactly as before.
|
|
22
|
+
- `exclude-tools` is removed: a file that still has it gets a warning and the
|
|
23
|
+
field is ignored, so the delegate's tools follow the usual rules (its
|
|
24
|
+
`tools` line, or the parent session's active tools when there is none, plus
|
|
25
|
+
the `delegateTools` setting) with nothing taken off. List the delegate's
|
|
26
|
+
tools in `tools` instead.
|
|
27
|
+
- A `model` or `fallback` entry the model registry does not know is no longer
|
|
28
|
+
skipped for the next candidate: it goes to the child's `--model` unchanged,
|
|
29
|
+
and Pi reports it if it cannot resolve it.
|
|
30
|
+
- A delegate whose agent has no `tools` field now gets the parent session's
|
|
31
|
+
active tools when the launch or resume starts, passed as `--tools`, instead
|
|
32
|
+
of Pi's default tools. An empty `tools` field (`tools:` or `tools: []`) now
|
|
33
|
+
means no tools except the `delegateTools` setting, and `--no-tools` when that
|
|
34
|
+
is empty too; it used to mean the parent's tools.
|
|
35
|
+
- A delegate now gets exactly its selected tools, MCP tools included. Pi
|
|
36
|
+
kept every MCP tool registered, callable from `codemode` and loadable by
|
|
37
|
+
`tool_search`, unless a `--tools` entry started with `mcp__`; pi-squire now
|
|
38
|
+
adds the entry `mcp__`, which names no tool, to a list with no such entry,
|
|
39
|
+
so an MCP tool reaches a delegate only when its tools (or the parent's, for
|
|
40
|
+
an agent without `tools`) name or match it. Name a server's tools, such as
|
|
41
|
+
`mcp__docs__*`, to keep them. Tests changed with it: the argv tests in
|
|
42
|
+
`test/agent-files.test.ts`, `test/delegate.test.ts` and
|
|
43
|
+
`test/resume.test.ts` now expect the extra `mcp__` entry.
|
|
44
|
+
- Migration: move each `<agent dir>/squire/agents/<name>/AGENT.md` to
|
|
45
|
+
`<agent dir>/agents/<name>.md`; add `prompt_mode: replace` to keep today's
|
|
46
|
+
prompt; replace `exclude-tools: a, b` with a `tools` line naming the tools
|
|
47
|
+
the delegate should have.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- An agent whose file is invalid is disabled: it is left out of the roster
|
|
52
|
+
and of the `delegate` tool's description, a warning names the file and the
|
|
53
|
+
reason when the session starts (and before a run, for a file that turns
|
|
54
|
+
invalid meanwhile), and a call or resume that names it is refused with that
|
|
55
|
+
reason instead of "no agent named".
|
|
56
|
+
- Every agent field is optional: `description` defaults to the name, an absent
|
|
57
|
+
`model` or `thinking` runs on the parent session's current model or level,
|
|
58
|
+
and an unknown `thinking` is dropped with a warning instead of leaving the
|
|
59
|
+
agent out. `model` and `fallback` entries may be aliases such as `sonnet`,
|
|
60
|
+
each resolving to one model; a `*` pattern makes the file invalid, so the
|
|
61
|
+
agent is disabled. A body may be empty.
|
|
62
|
+
- New agent fields: `display_name` (shown on the delegate card, in
|
|
63
|
+
`/delegates` and in the window title; it may hold only ASCII letters,
|
|
64
|
+
digits, `-` and `_`, and any other value, a space, `#`, `.`, a non-ASCII
|
|
65
|
+
letter or an empty value among them, makes the file invalid, so the agent is
|
|
66
|
+
disabled), `enabled: false` (leaves the agent
|
|
67
|
+
out; a project file hides a global agent of the same name), `locked` (`true`
|
|
68
|
+
or a list of `model` and `thinking`: a call or resume that passes a locked
|
|
69
|
+
field runs on the agent's value, and the result says which agent locked
|
|
70
|
+
which field; passing the agent's own value is the same as passing nothing,
|
|
71
|
+
so its fallbacks still apply; a resume runs a locked field on the file's
|
|
72
|
+
current value, not on what the delegate last ran on) and `prompt_mode`.
|
|
73
|
+
Keys pi-squire does not use, such as `max_turns` or another extension's
|
|
74
|
+
policy, are ignored without a warning.
|
|
75
|
+
- The `delegateTools` setting in `<agent dir>/squire/settings.json`: tool
|
|
76
|
+
names or `*` patterns added to every delegate's tools, from its agent's
|
|
77
|
+
`tools` or the parent's, for the tools a `message:*` provider gives a
|
|
78
|
+
delegate to reach its parent. Empty by default.
|
|
79
|
+
- A `tools` line of only `-name` entries (`tools: -bash, -write`) gives the
|
|
80
|
+
delegate the parent session's tools less those (a `-name` entry may be a `*`
|
|
81
|
+
pattern), then the `delegateTools` setting. A `+name` entry, or tool names
|
|
82
|
+
and `-name` entries mixed, make the agent file invalid, so the agent is
|
|
83
|
+
disabled. pi-squire always passes the child a plain `--tools` list.
|
|
84
|
+
- A `delegateTools` entry that starts with `+` or `-`, or holds a comma,
|
|
85
|
+
refuses every launch and resume with an error naming the settings file,
|
|
86
|
+
before the task is sent or a window opens.
|
|
87
|
+
- A `tools` or `fallback` YAML list entry holding a comma, such as
|
|
88
|
+
`tools: ["read,-bash"]`, makes the agent file invalid, so the agent is
|
|
89
|
+
disabled with a warning naming the file and the reason. A comma-separated
|
|
90
|
+
line (`tools: read, bash`) and a list of single names still work.
|
|
91
|
+
- A resume without `thinking`, for an agent that does not lock it, now runs
|
|
92
|
+
on the level the delegate last ran on, read from its session (the last
|
|
93
|
+
thinking-level change on the active branch, such as a change the user made
|
|
94
|
+
in the delegate's window or a clamp to a new model), instead of the level
|
|
95
|
+
recorded when the delegation started; the recorded level remains the
|
|
96
|
+
fallback when the session has none.
|
|
97
|
+
- A tool that only an agent's own `extensions` register reaches its delegate
|
|
98
|
+
only when the agent's `tools` list or the `delegateTools` setting names (or
|
|
99
|
+
matches) it. With no `tools` field, or only `-name` entries, the baseline
|
|
100
|
+
is the parent session's active tools alone; pi-squire never loads an
|
|
101
|
+
agent's extensions in the parent. (An unreleased change on this branch had
|
|
102
|
+
loaded them in the parent to add their tools to that baseline; its tests in
|
|
103
|
+
`test/agent-files.test.ts` and `test/pi-tools.test.ts` now pin this rule
|
|
104
|
+
instead.)
|
|
105
|
+
- A running delegate that hits a usage limit now resolves a `fallback` entry
|
|
106
|
+
that is an alias or bare id (such as `sonnet`) to one model with Pi's
|
|
107
|
+
`--model` resolver, in the listed order, instead of skipping every entry
|
|
108
|
+
that is not an exact `provider/id`. Each model is tried once, never the one
|
|
109
|
+
that just failed.
|
|
110
|
+
|
|
9
111
|
## [0.14.0] - 2026-10-27
|
|
10
112
|
|
|
11
113
|
### Removed
|
|
@@ -29,6 +131,18 @@ follows [Semantic Versioning](https://semver.org/).
|
|
|
29
131
|
test that the poll runs only while a delegation does; `test/tmux.test.ts` no
|
|
30
132
|
longer tests `popup` and `closePopup`, and `test/popup-parent.ts` and the
|
|
31
133
|
fake's popup support are gone.
|
|
134
|
+
- Tests changed with the agent files: the harness writes `agents/<name>.md`
|
|
135
|
+
and the retired fixture to `squire/agents/<name>/AGENT.md`; prompt
|
|
136
|
+
assertions expect the `<agent_instructions>` wrapper; the roster, empty-roster
|
|
137
|
+
and malformed-file tests in `test/delegate.test.ts` and `test/tools.test.ts`
|
|
138
|
+
follow the optional fields and new location; the fallback render test skips
|
|
139
|
+
a model without credentials rather than an unknown one; the `display_name`
|
|
140
|
+
test names its agent `Code_Reviewer-2`, since a space is no longer accepted;
|
|
141
|
+
and `test/exclude-tools.test.ts` becomes `test/agent-files.test.ts`.
|
|
142
|
+
- Tests changed with tools inheritance: the test that pinned an empty `tools`
|
|
143
|
+
field as the parent's tools now pins it as no tools; the argv tests in
|
|
144
|
+
`test/delegate.test.ts` expect the parent's tools as `--tools`; and an
|
|
145
|
+
invalid `delegateTools` now refuses an agent without a `tools` field too.
|
|
32
146
|
|
|
33
147
|
## [0.13.1] - 2026-10-27
|
|
34
148
|
|
|
@@ -544,7 +658,8 @@ author's dotfiles; the changes below are against that copy.
|
|
|
544
658
|
|
|
545
659
|
- The published file list includes `child.ts`, which `index.ts` imports.
|
|
546
660
|
|
|
547
|
-
[Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.
|
|
661
|
+
[Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.15.0...HEAD
|
|
662
|
+
[0.15.0]: https://github.com/gvanderclay/pi-squire/compare/v0.14.0...v0.15.0
|
|
548
663
|
[0.14.0]: https://github.com/gvanderclay/pi-squire/compare/v0.13.1...v0.14.0
|
|
549
664
|
[0.13.1]: https://github.com/gvanderclay/pi-squire/compare/v0.13.0...v0.13.1
|
|
550
665
|
[0.13.0]: https://github.com/gvanderclay/pi-squire/compare/v0.12.0...v0.13.0
|
package/README.md
CHANGED
|
@@ -46,22 +46,24 @@ The package has no runtime dependencies and no build step.
|
|
|
46
46
|
|
|
47
47
|
The package ships no agents, so create one first. `<agent dir>` is Pi's agent
|
|
48
48
|
directory: `~/.pi/agent`, or `PI_CODING_AGENT_DIR` when that is set. Save this
|
|
49
|
-
as `<agent dir>/
|
|
50
|
-
|
|
49
|
+
as `<agent dir>/agents/scout.md`, replacing `provider/model-id` with a model
|
|
50
|
+
your Pi can use:
|
|
51
51
|
|
|
52
52
|
```markdown
|
|
53
53
|
---
|
|
54
54
|
description: Looks things up and answers in one message
|
|
55
55
|
model: provider/model-id
|
|
56
56
|
thinking: medium
|
|
57
|
-
|
|
57
|
+
tools: read, grep, find, ls
|
|
58
58
|
---
|
|
59
59
|
|
|
60
60
|
You research one question at a time and answer concisely, citing the files
|
|
61
61
|
you read.
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Every field is optional: without `model` and `thinking` the delegate runs on
|
|
65
|
+
your session's, and without `tools` it has your session's tools (see
|
|
66
|
+
[Agents](#agents)). The roster is read at call time, so no reload is needed. Delegation guidance
|
|
65
67
|
for the parent is optional: save Markdown as
|
|
66
68
|
`<agent dir>/squire/delegation_prompt.md`, and it is read before each run.
|
|
67
69
|
Then, from a Pi session running in tmux, hand it a task:
|
|
@@ -92,7 +94,8 @@ or opened.
|
|
|
92
94
|
## How a delegation works
|
|
93
95
|
|
|
94
96
|
`/delegate <agent> [--model <provider/id>] [--thinking <level>] [--label <name>] [--cwd <dir> | --worktree <branch> [--worktree-source <dir>] [--worktree-base <commit-ish>]] [--auto-exit | --no-auto-exit] <task…>`
|
|
95
|
-
reads the agent from `<agent dir>/
|
|
97
|
+
reads the agent from `<agent dir>/agents/<name>.md` (or a trusted project's
|
|
98
|
+
`.pi/agents/<name>.md`; see [Agents](#agents)), writes
|
|
96
99
|
the task to the delegate's inbox through `message:send`, emits
|
|
97
100
|
`session:launch` so other extensions can shape the launch, then opens a
|
|
98
101
|
detached window running the parent's own Pi in the parent's working directory,
|
|
@@ -102,7 +105,8 @@ prompt reaches the child as a path to a private file under the system
|
|
|
102
105
|
temporary folder, not as text on the command line.
|
|
103
106
|
|
|
104
107
|
- The window and the child's Pi session share one name: `<agent>-<label>`, or
|
|
105
|
-
`<agent>-<first 8 characters of the id>` without a label
|
|
108
|
+
`<agent>-<first 8 characters of the id>` without a label, where `<agent>` is
|
|
109
|
+
the agent's `display_name` when it has one. A label is at most
|
|
106
110
|
32 letters, digits, `_` or `-`, starting with a letter or digit. A `-` joins
|
|
107
111
|
it rather than `:`, since tmux reads `:` in a target as session and window.
|
|
108
112
|
- Labels need not be unique. The delegation id stays the handle for
|
|
@@ -183,7 +187,9 @@ with an error naming the file, before the task is sent or a window opens.
|
|
|
183
187
|
|
|
184
188
|
Delegate windows sit out of your way, so reach them from the parent. `/delegates`
|
|
185
189
|
(or `alt+shift+d`) opens a panel of the delegations whose window is open: running,
|
|
186
|
-
or done with auto-exit off, newest first.
|
|
190
|
+
or done with auto-exit off, newest first. Each row shows the delegate's name,
|
|
191
|
+
its agent (the agent's `display_name` when it had one), its state and its
|
|
192
|
+
window. The model has no tool for any of this.
|
|
187
193
|
|
|
188
194
|
| Key | Does |
|
|
189
195
|
|---|---|
|
|
@@ -404,49 +410,123 @@ be read or written also refuses the launch; nothing is granted by default.
|
|
|
404
410
|
|
|
405
411
|
## Agents
|
|
406
412
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
`tools`
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
`
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
413
|
+
An agent is one Markdown file, `<name>.md`, in the agents folders Pi agent
|
|
414
|
+
tooling shares; the file name without `.md` is the agent's name (letters,
|
|
415
|
+
digits, `_` or `-`). The roster is read at call time, so a new or edited file
|
|
416
|
+
is usable without a reload.
|
|
417
|
+
|
|
418
|
+
- `<agent dir>/agents/<name>.md` holds the global agents.
|
|
419
|
+
- `<cwd>/.pi/agents/<name>.md` holds a project's agents, read only when Pi
|
|
420
|
+
reports the parent's project as trusted. A project file replaces the global
|
|
421
|
+
file of the same name. In an untrusted project only the global agents load,
|
|
422
|
+
so a cloned repository cannot change a delegate's prompt, model or tools.
|
|
423
|
+
|
|
424
|
+
The body is the delegate's instructions, appended to Pi's own prompt; it
|
|
425
|
+
reaches the child as a path to a private file under the system temporary
|
|
426
|
+
folder, so the text stays off the command line. Every frontmatter field is
|
|
427
|
+
optional, and the [first-use example](#first-use) is a complete agent file:
|
|
428
|
+
|
|
429
|
+
| Field | Meaning |
|
|
430
|
+
| --- | --- |
|
|
431
|
+
| `description` | Shown in the roster and the `delegate` tool's description. Defaults to the name. |
|
|
432
|
+
| `display_name` | Shown instead of the name on the delegate card, in `/delegates` and in the window title (`<display_name>-<label>`). The agent is still called by its name. It may hold only ASCII letters, digits, `-` and `_`; any other value (a space, `#`, `.`, a non-ASCII letter, or an empty value) makes the file invalid, so the agent is disabled. |
|
|
433
|
+
| `model` | One model: `provider/id` or an alias such as `sonnet`, passed to the child's `--model` unchanged, so Pi resolves it to one model. A `*` pattern makes the file invalid. Absent means the parent session's current model. |
|
|
434
|
+
| `thinking` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` or `max`. Absent means the parent session's level; an unknown value is dropped with a warning and the parent's level applies. Pi clamps the level to the model. |
|
|
435
|
+
| `tools` | The delegate's tools (see below): tool names for exactly those, or only `-name` entries for the parent session's current tools less those. Absent means the parent session's current tools; empty (`tools:` or `tools: []`) means no tools except the `delegateTools` setting. MCP tools follow the selection like any other, and a tool of the agent's own `extensions` reaches the delegate only when `tools` or `delegateTools` names it. |
|
|
436
|
+
| `extensions` | Extension paths only this agent's delegate loads (see below). |
|
|
437
|
+
| `fallback` | Models to try, in order, when `model` is usage-limited (see [Usage limits](#usage-limits)). Each entry is one model, like `model`; a `*` pattern, or a YAML list entry holding a comma, makes the file invalid. A comma-separated line (`fallback: a, b`) is two entries. |
|
|
438
|
+
| `auto-exit` | `true` or `false`, default `true`; see [Auto-exit](#auto-exit). |
|
|
439
|
+
| `prompt_mode` | `append` (the default) wraps the body in `<agent_instructions>` and `</agent_instructions>` lines; `replace` adds the body unwrapped. An empty body adds nothing either way. |
|
|
440
|
+
| `enabled` | `false` leaves the agent out. A project file with `enabled: false` hides a global agent of the same name in that project. |
|
|
441
|
+
| `locked` | `true`, or a list of `model` and `thinking`. A call to `delegate`, `/delegate` or a resume that passes a locked field does not get it: the agent's value is used (the parent's when the file sets none) and the result says which agent locked which field. Passing the agent's own value is the same as passing nothing: no notice, and its fallbacks still apply. A resume of a locked field runs on the file's value as it is now, not on what the delegate last ran on. `true` locks the fields the file sets. |
|
|
442
|
+
|
|
443
|
+
Any other key, such as `max_turns`, `inherit_context`, `run_in_background` or
|
|
444
|
+
a permission policy for another extension, is ignored without a warning and
|
|
445
|
+
left for whatever else reads the file. `exclude-tools` is no longer read; a
|
|
446
|
+
file that still has it gets a warning (use `tools` instead).
|
|
447
|
+
|
|
448
|
+
`tools` lists the delegate's tools as a comma-separated or YAML list
|
|
449
|
+
(`tools: read, grep` or `tools: [read, grep]`). Each entry of a YAML list
|
|
450
|
+
names one tool: an entry holding a comma, such as `tools: ["read,-bash"]`,
|
|
451
|
+
makes the file invalid. pi-squire works out the delegate's whole selection
|
|
452
|
+
itself and always passes the child a plain list, `--tools read,grep`, which Pi
|
|
453
|
+
treats as the whole selection, extension tools included; entries may be `*`
|
|
454
|
+
patterns. It never passes Pi `+name` or `-name` entries. MCP tools follow the
|
|
455
|
+
list like any other tool: an MCP tool (`mcp__<server>__<tool>`, or one of the
|
|
456
|
+
MCP resource tools) that no entry names or matches is not registered in the
|
|
457
|
+
delegate at all, so it is neither declared nor callable from `codemode` nor
|
|
458
|
+
loadable by `tool_search`, whatever its exposure. Pi filters MCP tools by
|
|
459
|
+
`--tools` only once an entry starts with `mcp__`, so when the list has no
|
|
460
|
+
such entry pi-squire adds the entry `mcp__`, which names no tool; an empty
|
|
461
|
+
selection is `--no-tools`, which removes MCP tools too. To give a delegate an
|
|
462
|
+
MCP server's tools, name them, for example `mcp__docs__*`. An extension that
|
|
463
|
+
turns tools on at run time can still add only tools the list allows. Names
|
|
464
|
+
are not checked against the parent's tools, since a tool from one of the
|
|
465
|
+
agent's own `extensions` exists only in the child.
|
|
466
|
+
|
|
467
|
+
- No `tools` field: the delegate gets the parent session's tools as they are
|
|
468
|
+
when the launch (or resume) starts, the tools active there then, passed as
|
|
469
|
+
`--tools`, plus the `delegateTools` entries. A parent limited to `read`
|
|
470
|
+
gives such a delegate only `read`.
|
|
471
|
+
- An empty `tools` field, `tools:` or `tools: []`: the delegate gets no tools
|
|
472
|
+
except the `delegateTools` entries. With none of those either, it starts
|
|
473
|
+
with `--no-tools`.
|
|
474
|
+
- A `tools` list of tool names: exactly those tools, plus the
|
|
475
|
+
`delegateTools` entries.
|
|
476
|
+
- A `tools` list of only `-name` entries (`tools: -bash, -write`): the
|
|
477
|
+
parent's tools, as with no `tools` field, less those, plus the
|
|
478
|
+
`delegateTools` entries. A `-name` entry may be a `*` pattern
|
|
479
|
+
(`-mcp__docs__*`).
|
|
480
|
+
- A `+name` entry, or tool names and `-name` entries in one list, make the
|
|
481
|
+
file invalid, and the agent is disabled (see below).
|
|
482
|
+
|
|
483
|
+
The tools the agent's own `extensions` register are never in the parent's
|
|
484
|
+
tools, and pi-squire does not load those extensions in the parent to find
|
|
485
|
+
them. Such a tool reaches the delegate only when a plain `tools` list or the
|
|
486
|
+
`delegateTools` setting names it (or matches it with a `*` pattern); with no
|
|
487
|
+
`tools` field, or only `-name` entries, the delegate does not get it.
|
|
488
|
+
|
|
489
|
+
The delegation tools (`delegate`, `delegation_status`, `delegation_close`,
|
|
490
|
+
`delegation_resume`) are never passed and never available in a delegate:
|
|
491
|
+
pi-squire registers none of them there.
|
|
492
|
+
|
|
493
|
+
The delegate's result reaches the parent through the `message:*` provider's
|
|
494
|
+
reply when its run settles, not through a tool, so a short `tools` list cannot
|
|
495
|
+
stop it answering. To let a delegate message its parent mid-task, whatever its
|
|
496
|
+
`tools`, list the tools your `message:*` provider gives a session for that in
|
|
497
|
+
the `delegateTools` setting, in `<agent dir>/squire/settings.json` beside
|
|
498
|
+
`windowPlacement` and `worktreeRoot`:
|
|
499
|
+
|
|
500
|
+
```json
|
|
501
|
+
{ "delegateTools": ["<tool or pattern>"] }
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Each entry, a tool name or `*` pattern, is added to every delegate's tools,
|
|
505
|
+
whether they come from its agent's `tools` or from the parent (after any
|
|
506
|
+
`-name` entries are taken off), and passed to `--tools` unchanged. The setting
|
|
507
|
+
is empty by default, is read at each launch and resume, and a value that is
|
|
508
|
+
not a list of names, or an entry that holds a comma or starts with `+` or
|
|
509
|
+
`-`, refuses every launch with an error naming the file, before the task is sent or a window
|
|
510
|
+
opens; it does not disable agents one by one.
|
|
437
511
|
|
|
438
512
|
`extensions` lists extension paths only this agent's delegate loads, as a
|
|
439
513
|
comma-separated or YAML list. Each reaches the child as a repeated
|
|
440
514
|
`-e <absolute path>`, on top of its normal extensions, so pi-squire and the
|
|
441
515
|
`message:*` provider still load and the result still reaches the parent. `~`
|
|
442
516
|
and `~/` expand to the home directory and a relative path resolves against the
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
`fallback`
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
517
|
+
folder holding the agent file. A path that does not exist when the roster is
|
|
518
|
+
read leaves the agent out, with a warning.
|
|
519
|
+
|
|
520
|
+
A `model` or `fallback` entry that is an exact `provider/id` in Pi's registry
|
|
521
|
+
is checked as before: a model without credentials or with an active
|
|
522
|
+
usage-limit mark is skipped for the next candidate. Anything else, such as an
|
|
523
|
+
alias, goes to the child's `--model` unchanged, and Pi resolves it to one
|
|
524
|
+
model; if Pi cannot, the child's Pi reports the error and its window closes
|
|
525
|
+
without a result. When a running delegate moves to a fallback after a usage
|
|
526
|
+
limit, it resolves each entry the way Pi resolves `--model`: an exact
|
|
527
|
+
`provider/id`, or a bare id or alias such as `sonnet`, to one model, in the
|
|
528
|
+
order the entries are listed. No entry may be a `*` pattern: a `model` or
|
|
529
|
+
`fallback` entry with `*` makes the file invalid, and the agent is disabled.
|
|
450
530
|
|
|
451
531
|
The body is followed by one fixed final-message line and a paragraph naming the
|
|
452
532
|
parent session's address. The delegate's task arrives as a message from that
|
|
@@ -454,19 +534,32 @@ session, and that message and every later one from the same address are
|
|
|
454
534
|
instructions to follow as given. Other sessions are colleagues: the delegate
|
|
455
535
|
may answer them, but checks with the parent before doing work the parent did
|
|
456
536
|
not ask for. The paragraph names no provider, package or tool, so it holds
|
|
457
|
-
whatever `message:*` provider delivers the task.
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
`
|
|
463
|
-
not
|
|
464
|
-
|
|
537
|
+
whatever `message:*` provider delivers the task. `prompt_mode: replace` builds
|
|
538
|
+
the prompt exactly as every delegate was built before `prompt_mode` existed.
|
|
539
|
+
|
|
540
|
+
An agent file that cannot be used is invalid, and its agent is disabled:
|
|
541
|
+
frontmatter that is not readable YAML or not a set of fields, an `enabled` or
|
|
542
|
+
`auto-exit` that is not `true` or `false`, a `tools` or `extensions` that is
|
|
543
|
+
not a list, a `tools` list with a `+name` entry or with tool names and `-name`
|
|
544
|
+
entries mixed, a `tools` or `fallback` YAML list entry holding a comma, a
|
|
545
|
+
`model` or `fallback` entry with a `*` pattern, or an extension path that
|
|
546
|
+
does not exist. A disabled agent is left
|
|
547
|
+
out of the roster and of the `delegate` tool's description, so the model never
|
|
548
|
+
picks it, and a warning names the file and the reason when the session starts
|
|
549
|
+
(and before a run, when a file turns invalid while the session runs). A call
|
|
550
|
+
or resume that names it anyway is refused with that reason. A
|
|
551
|
+
field that cannot be used (a `fallback` that is not a list, an unknown
|
|
552
|
+
`thinking`, `prompt_mode` or `locked` entry) is dropped with a warning and the
|
|
553
|
+
agent still loads. While the retired `<agent dir>/squire/agents/` folder
|
|
554
|
+
exists, a warning says to move each `<name>/AGENT.md` to
|
|
555
|
+
`<agent dir>/agents/<name>.md`. With no agents at all, `/delegate` says how to
|
|
465
556
|
add one.
|
|
466
557
|
|
|
467
558
|
## Configuration
|
|
468
559
|
|
|
469
|
-
`<agent dir>/squire/` holds the
|
|
560
|
+
`<agent dir>/squire/` holds the optional parent guidance file and
|
|
561
|
+
`settings.json` (`windowPlacement`, `worktreeRoot` and `delegateTools`); the
|
|
562
|
+
agents live in `<agent dir>/agents/` (see [Agents](#agents)).
|
|
470
563
|
`delegation_prompt.md` is Markdown, inserted unchanged as the
|
|
471
564
|
`squire_parent_delegation` system-prompt section before each new run, including
|
|
472
565
|
a run started by an idle delegate result. It is not a conversation or user
|
|
@@ -482,7 +575,7 @@ policy.
|
|
|
482
575
|
|
|
483
576
|
Refresh happens before a new run, not before every model request in a tool
|
|
484
577
|
loop, and the extension does not watch the filesystem. `pi-squire` reads no
|
|
485
|
-
|
|
578
|
+
environment variable of its own. `PI_DELEGATE_PARENT` and `PI_DELEGATE_AUTO_EXIT` are set
|
|
486
579
|
for the child, never read as configuration by the parent. The window starts
|
|
487
580
|
with the tmux server's environment plus only these from the parent:
|
|
488
581
|
`PI_CODING_AGENT_DIR`, `PI_CODING_AGENT_SESSION_DIR` (when the parent has it
|
|
@@ -493,7 +586,8 @@ it to skip a dialog or confirmation instead of waiting on one, and any other
|
|
|
493
586
|
runner that starts Pi unattended can set it too. Anything else the
|
|
494
587
|
parent process has, such as a `CLAUDE_CONFIG_DIR` set by a shell alias,
|
|
495
588
|
reaches the child only through a `session:launch` contributor. `--model` and
|
|
496
|
-
`--thinking` override the agent's defaults for one call,
|
|
589
|
+
`--thinking` override the agent's defaults for one call, unless the agent
|
|
590
|
+
locks them (see [Agents](#agents)), and an unknown value
|
|
497
591
|
is refused with close matches, and so is a model with no configured
|
|
498
592
|
credentials. An API key that exists only as an environment variable in the
|
|
499
593
|
parent's shell does not reach the delegate, so log in through Pi or make the
|
|
@@ -513,11 +607,13 @@ session's delegation records. None of them is registered inside a delegate.
|
|
|
513
607
|
| `delegation_resume` | `id`, `task`, optional `model`, `thinking` and `auto_exit` | Reopens an exited delegate's own session in a new window with a follow-up task, and returns the new delegation's id at once (see [Resuming a delegation](#resuming-a-delegation)). |
|
|
514
608
|
|
|
515
609
|
The `delegate` tool's description lists the current roster, one line per agent:
|
|
516
|
-
its name, description, default model
|
|
517
|
-
and its
|
|
610
|
+
its name and any display name, description, default model (or this session's)
|
|
611
|
+
and fallbacks, thinking, auto-exit when it is off, its tools (`no tools` for
|
|
612
|
+
an empty `tools` field, `this session's except …` for `-name` entries) and the
|
|
613
|
+
fields it locks.
|
|
518
614
|
|
|
519
615
|
```text
|
|
520
|
-
- scout — Read-only recon (default provider/model-id, thinking low, auto-exit off,
|
|
616
|
+
- scout "Recon" — Read-only recon (default provider/model-id, thinking low, auto-exit off, tools: read/grep, locked: model)
|
|
521
617
|
```
|
|
522
618
|
|
|
523
619
|
The model picks an agent from these lines without reading files. The
|
|
@@ -529,9 +625,9 @@ merely to wait; a substantive follow-up remains fine. The description is
|
|
|
529
625
|
rebuilt at session start and before each new run when the exposed roster
|
|
530
626
|
changes, so an edit, addition or removal shows up in the run being prepared,
|
|
531
627
|
including a run woken by an idle delegate result. Unchanged metadata is not
|
|
532
|
-
re-registered.
|
|
533
|
-
|
|
534
|
-
|
|
628
|
+
re-registered. The description built while extensions load lists only the
|
|
629
|
+
global agents, since the project's trust is known only once the session
|
|
630
|
+
starts. The roster itself is still read at call time, and an
|
|
535
631
|
unknown agent, model or thinking level is refused with close matches and
|
|
536
632
|
nothing starts.
|
|
537
633
|
|
|
@@ -647,8 +743,9 @@ The launch also passes the candidates after the chosen one to the delegate as
|
|
|
647
743
|
`PI_DELEGATE_FALLBACK` (none for an explicit model). When a delegate's run
|
|
648
744
|
ends on a usage limit, it switches its session to the first of them that has
|
|
649
745
|
credentials and is not marked, adds a message saying so, and continues the
|
|
650
|
-
task there, so work done so far is kept.
|
|
651
|
-
|
|
746
|
+
task there, so work done so far is kept. An alias resolves to one model, as
|
|
747
|
+
it would in Pi's `--model`. Each model is tried once, never the one that just
|
|
748
|
+
failed; when none is left, the run fails as before. A `done` result from such a delegate
|
|
652
749
|
carries the `Usage limit:` line too, saying it finished on a fallback.
|
|
653
750
|
|
|
654
751
|
Before a launch, pi-squire also reads the OpenCode Go quota for a paid
|
|
@@ -897,7 +994,8 @@ and it resumes as the command does.
|
|
|
897
994
|
delegate instead) and tmux can be asked; no window with its id and name still
|
|
898
995
|
runs a program (an exited one is killed first; a window that merely shares the
|
|
899
996
|
name is ignored); its session file is found and the working directory in the
|
|
900
|
-
file's header still exists; its agent is still in the roster
|
|
997
|
+
file's header still exists; its agent is still in the roster and not disabled
|
|
998
|
+
(a disabled agent's refusal names its file and the reason); and no other
|
|
901
999
|
resume of it is under way. A delegate whose window was killed mid-turn can be
|
|
902
1000
|
resumed.
|
|
903
1001
|
- A removed working directory, a removed managed worktree included, makes a
|
|
@@ -908,9 +1006,17 @@ and it resumes as the command does.
|
|
|
908
1006
|
- Without `model` it continues on the model the delegate finished on, moving to
|
|
909
1007
|
its agent's fallbacks when that one is unavailable or marked (see
|
|
910
1008
|
[Usage limits](#usage-limits)). An explicit `model` is used alone and refused
|
|
911
|
-
rather than substituted. `thinking`
|
|
912
|
-
|
|
913
|
-
|
|
1009
|
+
rather than substituted. Without `thinking` it continues on the level the
|
|
1010
|
+
delegate last ran on: the last thinking-level change on its session's
|
|
1011
|
+
active branch (Pi records one at start, one per change, and one when a
|
|
1012
|
+
model change clamps the level), or the delegation's recorded level when
|
|
1013
|
+
the session has none. `auto_exit` defaults to the delegation's own. A
|
|
1014
|
+
field the agent locks is the exception: it runs on the
|
|
1015
|
+
agent file's current `model` (then its fallbacks, even when the delegate had
|
|
1016
|
+
moved to a fallback) or `thinking`, a value passed for it is not used, with
|
|
1017
|
+
a notice, and passing the file's own value is the same as passing nothing. The agent's prompt, tools and extensions are those of the
|
|
1018
|
+
roster now, and an agent without a `tools` field gets the parent's tools as
|
|
1019
|
+
they are at the resume.
|
|
914
1020
|
- `session:launch` is emitted as for any launch, with the same payload.
|
|
915
1021
|
- Not detected: a Pi process you opened yourself on the same session outside
|
|
916
1022
|
pi-squire's window. Close it before resuming.
|
|
@@ -934,7 +1040,7 @@ the window is open (see [Resuming a delegation](#resuming-a-delegation)).
|
|
|
934
1040
|
| --- | --- |
|
|
935
1041
|
| `args` | the child `pi`'s complete argument list, launcher first |
|
|
936
1042
|
| `env` | the child's environment, as `KEY`/`value` pairs |
|
|
937
|
-
| `agent` | the agent's name, as in `<agent dir>/
|
|
1043
|
+
| `agent` | the agent's name, as in `<agent dir>/agents/<name>.md` or `<cwd>/.pi/agents/<name>.md` (never its `display_name`); read it, do not change it |
|
|
938
1044
|
| `cwd` | the directory the window opens in, the parent's or the resolved `--cwd`; read it, do not change it |
|
|
939
1045
|
| `toolCallId` | the ID of the `delegate` or `delegation_resume` tool call that started the launch; absent when started from the `/delegate` or `/delegate-resume` command; read it, do not change it |
|
|
940
1046
|
|
|
@@ -1047,8 +1153,11 @@ Other extensions may rely on:
|
|
|
1047
1153
|
- the `/delegates` command and its `alt+shift+d` shortcut, and `/delegate-open <id>` with its
|
|
1048
1154
|
`--switch` and `--peek` flags;
|
|
1049
1155
|
- the `[delegate]` result text and the closed-without-a-result text;
|
|
1050
|
-
-
|
|
1051
|
-
`<agent dir>/
|
|
1156
|
+
- the agent file's frontmatter keys and its locations,
|
|
1157
|
+
`<agent dir>/agents/<name>.md` and, in a trusted project,
|
|
1158
|
+
`<cwd>/.pi/agents/<name>.md`;
|
|
1159
|
+
- the `delegateTools`, `windowPlacement` and `worktreeRoot` settings in
|
|
1160
|
+
`<agent dir>/squire/settings.json`;
|
|
1052
1161
|
- the optional `<agent dir>/squire/delegation_prompt.md` file and the
|
|
1053
1162
|
`squire_parent_delegation` system-prompt section;
|
|
1054
1163
|
- the child environment variables `PI_DELEGATE_PARENT`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-squire",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Starts a delegate Pi session in a background tmux window, sends it the task over message:*, and shows the parent its result",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@earendil-works/pi-ai": "1.3.0",
|
|
55
55
|
"@earendil-works/pi-coding-agent": "1.3.0",
|
|
56
56
|
"@earendil-works/pi-tui": "1.3.0",
|
|
57
|
-
"@types/node": "26.6.
|
|
58
|
-
"typebox": "1.3
|
|
57
|
+
"@types/node": "26.6.5",
|
|
58
|
+
"typebox": "1.4.3",
|
|
59
59
|
"typescript": "7.0.2"
|
|
60
60
|
}
|
|
61
61
|
}
|