pi-multi-agent-skill 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +101 -2
- package/package.json +30 -4
- package/skills/multi-agent/SKILL.md +140 -0
- package/skills/multi-agent/profiles/Explore.md +34 -0
- package/skills/multi-agent/profiles/general-purpose.md +3 -0
- package/skills/multi-agent/references/commands.md +214 -0
- package/skills/multi-agent/references/lifecycle.md +92 -0
- package/skills/multi-agent/references/profiles.md +79 -0
- package/skills/multi-agent/references/state.md +55 -0
- package/skills/multi-agent/references/troubleshooting.md +56 -0
- package/skills/multi-agent/scripts/multi_agent.py +2054 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Milan Glacier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pi-multi-agent-skill
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A minimal, lightweight multi-agent skill and CLI for [pi](https://pi.dev). It
|
|
4
|
+
needs no extension and adds no tools. Your agent starts other agents, runs
|
|
5
|
+
them in parallel or in the background, and waits for, steers, stops or
|
|
6
|
+
resumes them. Any harness or agent that has a shell can use it.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Small token cost.** A subagent extension adds its tool definitions to
|
|
11
|
+
every request, whether or not your agent delegates anything. With this
|
|
12
|
+
skill, your agent's context holds only the skill's description, a few
|
|
13
|
+
dozen tokens, until it decides to delegate. Then it loads SKILL.md, which
|
|
14
|
+
is about 1.2K tokens and is all it needs for a fully working multi-agent
|
|
15
|
+
setup. The details of each command stay in separate references that it
|
|
16
|
+
reads only when needed.
|
|
17
|
+
- **Everything a subagent tool does, without the tool.** Your agent gets the
|
|
18
|
+
same controls a dedicated extension would give it: start agents, wait for
|
|
19
|
+
them, `steer` one with a correction, `abort` it and keep what it has so
|
|
20
|
+
far, `resume` a finished job with a follow-up task, and see what each job
|
|
21
|
+
is doing. You can run the same commands yourself from a terminal.
|
|
22
|
+
- **Parallel and background agents.** Run a quick question in the
|
|
23
|
+
foreground, or start several jobs at once and collect their results later.
|
|
24
|
+
- **Stops when you stop.** A foreground agent ends when the command that
|
|
25
|
+
started it ends: press Esc, cancel the tool call or close the session, and
|
|
26
|
+
the agent and the commands it was running stop with it, at every level of
|
|
27
|
+
nesting. Background jobs keep running until they finish or time out.
|
|
28
|
+
- **Your full pi setup.** Each agent loads the same extensions, MCP servers,
|
|
29
|
+
skills and settings as an interactive pi, and uses your model unless its
|
|
30
|
+
profile picks another.
|
|
31
|
+
- **Profiles.** They work as in other subagent tools: each one sets an
|
|
32
|
+
agent's system prompt, model, thinking level and tools.
|
|
33
|
+
- **Fork your conversation.** `--fork` hands the agent everything you have
|
|
34
|
+
discussed so far, for tasks that need that context.
|
|
35
|
+
- **Works outside pi.** Claude Code, Codex or any other agent with a shell
|
|
36
|
+
can run the same commands to delegate work to pi agents.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
Install the skill as a pi package from npm:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pi install npm:pi-multi-agent-skill
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or install directly from GitHub:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pi install git:github.com/milanglacier/pi-multi-agent-skill
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
You can also install the skill with the open skills CLI:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx skills install milanglacier/pi-multi-agent-skill --global --agent pi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The CLI copies the skill to `~/.agents/skills/multi-agent`, which pi reads.
|
|
59
|
+
You can also link it into pi's skills directory yourself:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ln -s "$PWD/skills/multi-agent" ~/.pi/agent/skills/multi-agent
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Requirements: pi and Python 3.9 or later. Nothing else to install.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
Your agent drives the skill on its own, but the commands also work by hand:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
multi_agent.py run --profile Explore "Where is the retry policy defined?"
|
|
73
|
+
multi_agent.py run --background --name review "Review the error handling in src/server/"
|
|
74
|
+
multi_agent.py wait review --timeout 120
|
|
75
|
+
multi_agent.py steer review "Skip generated files"
|
|
76
|
+
multi_agent.py resume review "Now check the client side"
|
|
77
|
+
multi_agent.py list
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
See [`skills/multi-agent/references/`](skills/multi-agent/references/) for
|
|
81
|
+
every command and option, how jobs start and stop, the profile format, where
|
|
82
|
+
state is kept and troubleshooting.
|
|
83
|
+
|
|
84
|
+
## Tests
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
python3 -m unittest discover tests
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The tests use an offline stand-in for pi, so they call no model.
|
|
91
|
+
|
|
92
|
+
## Releases
|
|
93
|
+
|
|
94
|
+
Set the version in `package.json`, commit it, and push a matching tag such
|
|
95
|
+
as `v0.1.1`. The GitHub workflow runs the tests and publishes to npm.
|
|
96
|
+
Prerelease versions use the `next` npm tag; stable versions use `latest`.
|
|
97
|
+
The npm trusted publisher is `milanglacier/pi-multi-agent-skill` with the
|
|
98
|
+
workflow filename `publish.yml` and permission to publish directly.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-multi-agent-skill",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A minimal multi-agent skill+cli for pi. It adds no extension or tools, so it uses only a few dozen tokens of the context window until the main agent delegates, yet it gives the same controls as a subagent extension. Background agents keep running after the session closes, and any later session can collect their results.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Milan Glacier",
|
|
7
|
+
"homepage": "https://github.com/milanglacier/pi-multi-agent-skill#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/milanglacier/pi-multi-agent-skill.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/milanglacier/pi-multi-agent-skill/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"pi-package",
|
|
17
|
+
"pi",
|
|
18
|
+
"agent-skill",
|
|
19
|
+
"multi-agent"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
"skills/multi-agent/SKILL.md",
|
|
23
|
+
"skills/multi-agent/profiles/*.md",
|
|
24
|
+
"skills/multi-agent/references/*.md",
|
|
25
|
+
"skills/multi-agent/scripts/*.py",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"pi": {
|
|
30
|
+
"skills": ["./skills"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: multi-agent
|
|
3
|
+
description: Start other pi agents and delegate work to them. Use it when a task benefits from a multi-agent workflow, such as splitting work across agents, running it in parallel or in the background, or keeping a side task out of your own context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Multi-agent
|
|
7
|
+
|
|
8
|
+
This skill starts other agents and manages each one as a named job. An agent
|
|
9
|
+
does not see your conversation unless you start it with `--fork`, and you see
|
|
10
|
+
only its final message.
|
|
11
|
+
|
|
12
|
+
`SKILL_DIR` below is the directory that contains this SKILL.md. Every command
|
|
13
|
+
has the form:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" <command> ...
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Pick a profile
|
|
20
|
+
|
|
21
|
+
A profile sets an agent's system prompt, model, thinking level and tools. Run
|
|
22
|
+
this once per session to see the available profiles:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" profiles
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
There are two built-in profiles. `general-purpose` (the default) has your
|
|
29
|
+
tools and settings. `Explore` is a read-only search agent. Pass a profile
|
|
30
|
+
with `--profile NAME`.
|
|
31
|
+
|
|
32
|
+
## Run an agent
|
|
33
|
+
|
|
34
|
+
For a short single task, run it in the foreground. The command blocks until
|
|
35
|
+
the agent finishes and prints its result:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" run --profile Explore "Where is the retry policy for HTTP calls defined?"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Pass a prompt longer than one line through `-` and a heredoc:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" run --name auth-review - <<'EOF'
|
|
45
|
+
Read src/auth/ and list every place that ...
|
|
46
|
+
EOF
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Write prompts that are self-contained: give the goal, the relevant paths and
|
|
50
|
+
what the answer should contain. When the task builds on your conversation so
|
|
51
|
+
far, add `--fork` instead: the agent starts from a copy of it.
|
|
52
|
+
|
|
53
|
+
For a long task, or several tasks in parallel:
|
|
54
|
+
|
|
55
|
+
- If your harness has a tool that runs a shell command in the background, run
|
|
56
|
+
the foreground `run` command with it. The job then stops when your session
|
|
57
|
+
ends. The command prints `multi-agent: started job NAME` first; use that
|
|
58
|
+
name for `steer` and `abort`. If the tool can wake you on each output line,
|
|
59
|
+
turn that off and wait for the command to exit. If the tool has its own
|
|
60
|
+
timeout, see "Timeouts" below.
|
|
61
|
+
- Otherwise, or when the work must continue after your session ends, add
|
|
62
|
+
`--background`. The command prints the job name and returns at once. A
|
|
63
|
+
background job runs until it finishes or reaches its timeout (one hour by
|
|
64
|
+
default). Tell the user the job's name.
|
|
65
|
+
- Never put the command in the background with `&`; use `--background`.
|
|
66
|
+
|
|
67
|
+
Run only as many jobs at once as the task needs.
|
|
68
|
+
|
|
69
|
+
## Timeouts
|
|
70
|
+
|
|
71
|
+
- A foreground `run` or `resume` has no timeout unless you pass
|
|
72
|
+
`--timeout S`. It stops when the agent finishes or when the command ends,
|
|
73
|
+
for example when your tool call is cancelled or your session ends.
|
|
74
|
+
- A `--background` job stops after one hour unless you pass `--timeout S`.
|
|
75
|
+
`--timeout 0` removes the limit.
|
|
76
|
+
- When a background tool of your harness runs the foreground command and the
|
|
77
|
+
tool has its own timeout, pass a shorter `--timeout`, leaving a grace
|
|
78
|
+
period so the job stops the agent and records its result before the tool
|
|
79
|
+
kills it. If you disable the tool's timeout instead, the job runs until
|
|
80
|
+
the agent finishes or your session ends.
|
|
81
|
+
|
|
82
|
+
## Wait for a result
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" wait NAME --timeout 120
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Exit code 2 means the job is still running; run the same command again in a
|
|
89
|
+
new tool call. Wait for one job per tool call and do not chain several `wait`
|
|
90
|
+
commands in one call: a message that steers you arrives only after your
|
|
91
|
+
current tool call returns.
|
|
92
|
+
|
|
93
|
+
The output is the agent's final message followed by a `--- multi-agent ---`
|
|
94
|
+
footer. The footer is for you. Report the agent's findings to the user in your
|
|
95
|
+
own words.
|
|
96
|
+
|
|
97
|
+
Exit code 0 means the job ended with status `done`; 1 means it ended another
|
|
98
|
+
way (`failed`, `aborted`, `timeout`, `killed`, `died`), and the output says
|
|
99
|
+
why.
|
|
100
|
+
|
|
101
|
+
## Correct or continue a job
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" steer NAME "Skip the tests directory"
|
|
105
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" abort NAME
|
|
106
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" kill NAME
|
|
107
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" resume NAME "Now check the callers too"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `steer` adds a message that the agent reads before its next step.
|
|
111
|
+
- `abort` stops the agent and keeps its last message as the result.
|
|
112
|
+
- `kill` stops a job that does not respond to `abort`.
|
|
113
|
+
- `resume` continues a finished job's conversation with a new prompt.
|
|
114
|
+
|
|
115
|
+
`kill --all` stops every running job of the current project. Use it only when
|
|
116
|
+
the user asks.
|
|
117
|
+
|
|
118
|
+
## Inspect jobs
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" list
|
|
122
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" status NAME
|
|
123
|
+
python3 "$SKILL_DIR/scripts/multi_agent.py" peek NAME
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`peek` shows the job's recent tool calls.
|
|
127
|
+
|
|
128
|
+
## References
|
|
129
|
+
|
|
130
|
+
The `references/` directory next to this file has the details. Read a file
|
|
131
|
+
only when you need it:
|
|
132
|
+
|
|
133
|
+
- `commands.md`: every command and option, output formats and exit codes.
|
|
134
|
+
- `lifecycle.md`: statuses, how a run stops, foreground and background
|
|
135
|
+
lifetime, timeouts, dialogs and nesting.
|
|
136
|
+
- `profiles.md`: writing a profile, where profiles are looked up, and how the
|
|
137
|
+
model, tools and system prompt are chosen.
|
|
138
|
+
- `state.md`: where jobs and conversations are stored, and the agent's
|
|
139
|
+
environment.
|
|
140
|
+
- `troubleshooting.md`: error messages and what to do about them.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Fast read-only search agent for locating code. Use it to find files by pattern (eg. \"src/components/**/*.tsx\"), grep for symbols or keywords (eg. \"API endpoints\"), or answer \"where is X defined / which files reference Y.\" Do NOT use it for code review, design-doc auditing, cross-file consistency checks, or open-ended analysis — it reads excerpts rather than whole files and will miss content past its read window. When calling, specify search breadth: \"quick\" for a single targeted lookup, \"medium\" for moderate exploration, or \"very thorough\" to search across multiple locations and naming conventions."
|
|
3
|
+
tools: read, bash, grep, find, ls
|
|
4
|
+
prompt_mode: replace
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS
|
|
8
|
+
You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
9
|
+
Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools.
|
|
10
|
+
|
|
11
|
+
You are STRICTLY PROHIBITED from:
|
|
12
|
+
- Creating new files
|
|
13
|
+
- Modifying existing files
|
|
14
|
+
- Deleting files
|
|
15
|
+
- Moving or copying files
|
|
16
|
+
- Creating temporary files anywhere, including /tmp
|
|
17
|
+
- Using redirect operators (>, >>, |) or heredocs to write to files
|
|
18
|
+
- Running ANY commands that change system state
|
|
19
|
+
|
|
20
|
+
Use Bash ONLY for read-only operations: ls, git status, git log, git diff, find, cat, head, tail.
|
|
21
|
+
|
|
22
|
+
# Tool Usage
|
|
23
|
+
- Use the find tool for file pattern matching (NOT the bash find command)
|
|
24
|
+
- Use the grep tool for content search (NOT bash grep/rg command)
|
|
25
|
+
- Use the read tool for reading files (NOT bash cat/head/tail)
|
|
26
|
+
- Use Bash ONLY for read-only operations
|
|
27
|
+
- Make independent tool calls in parallel for efficiency
|
|
28
|
+
- Adapt search approach based on thoroughness level specified
|
|
29
|
+
|
|
30
|
+
# Output
|
|
31
|
+
- Use absolute file paths in all references
|
|
32
|
+
- Report findings as regular messages
|
|
33
|
+
- Do not use emojis
|
|
34
|
+
- Be thorough and precise
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Commands
|
|
2
|
+
|
|
3
|
+
Every command runs as `python3 "$SKILL_DIR/scripts/multi_agent.py" <command>`.
|
|
4
|
+
A PROMPT or MESSAGE of `-` is read from stdin, without its trailing newlines.
|
|
5
|
+
An empty prompt or message is a usage error. `--help` prints a usage summary.
|
|
6
|
+
|
|
7
|
+
| Command | What it does |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `run [options] (PROMPT \| -)` | Start a new job. |
|
|
10
|
+
| `resume NAME [--background] [--timeout S] (PROMPT \| -)` | Start a new run of a finished job, in the same conversation. |
|
|
11
|
+
| `wait NAME [--timeout S]` | Block until the job is no longer running, then print its result. |
|
|
12
|
+
| `result NAME` | Print the result of a job that is not running. |
|
|
13
|
+
| `steer NAME (MESSAGE \| -)` | Give a running agent a message to read before its next step. |
|
|
14
|
+
| `abort NAME` | Ask a running agent to stop, keeping its last message as the result. |
|
|
15
|
+
| `kill NAME` / `kill --all` | Stop one job, or every running job of the current project. |
|
|
16
|
+
| `status NAME` | Print the job's settings and state. |
|
|
17
|
+
| `peek NAME [-n N]` | Print the last N lines (default 20) of the job's progress log. |
|
|
18
|
+
| `list [--all]` | List the jobs of the current project. |
|
|
19
|
+
| `profiles` | List the available profiles. |
|
|
20
|
+
| `rm NAME` | Delete a job that is not running, with its conversation. |
|
|
21
|
+
|
|
22
|
+
## Projects and job names
|
|
23
|
+
|
|
24
|
+
A job belongs to the project of the directory where `run` was called. `run`,
|
|
25
|
+
`list` and `kill --all` work on the current directory's project only.
|
|
26
|
+
|
|
27
|
+
The other commands look for NAME in the current project first. If the project
|
|
28
|
+
has no job of that name, they search every project and use the job when
|
|
29
|
+
exactly one project has it, so they also work from another directory. When
|
|
30
|
+
several projects have a job of that name, the command fails and lists them;
|
|
31
|
+
run it from the job's project.
|
|
32
|
+
|
|
33
|
+
## run
|
|
34
|
+
|
|
35
|
+
| Option | Meaning |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `--profile P` | Profile name, matched case-insensitively. Default `general-purpose`. |
|
|
38
|
+
| `--name N` | Job name. Default: the profile name in lowercase, `-`, and 4 hex digits, such as `explore-3f9a`. |
|
|
39
|
+
| `--background` | Return as soon as the job has started. |
|
|
40
|
+
| `--timeout S` | Wall-clock limit for the run in seconds. Default 3600 for a background run and no limit for a foreground run. `0` means no limit. |
|
|
41
|
+
| `--fork` | Start the agent from a copy of the caller's conversation. |
|
|
42
|
+
| `--model M` | Model pattern passed to `pi --model`. |
|
|
43
|
+
| `--thinking L` | Thinking level passed to `pi --thinking`. |
|
|
44
|
+
| `--cwd DIR` | Working directory for the agent, relative to the current directory. Default: the current directory. |
|
|
45
|
+
|
|
46
|
+
A job name contains letters, digits, `.`, `_` and `-`, starts and ends with a
|
|
47
|
+
letter or digit, and has at most 64 characters. `run` refuses a name that
|
|
48
|
+
already exists in the project; `resume` that job, pick another name, or `rm`
|
|
49
|
+
the old job first.
|
|
50
|
+
|
|
51
|
+
`--cwd` changes where the agent works and where project profiles are looked
|
|
52
|
+
up (`DIR/.pi/agents/`). The job still belongs to the current directory's
|
|
53
|
+
project.
|
|
54
|
+
|
|
55
|
+
`--fork` copies the conversation in `$PI_SESSION_FILE`, which pi sets for the
|
|
56
|
+
commands it runs. It fails when that variable is unset or the file does not
|
|
57
|
+
exist. Only the job's first run starts from the copy; later runs continue the
|
|
58
|
+
job's own conversation.
|
|
59
|
+
|
|
60
|
+
When `--model` and `--thinking` are omitted, the profile and then the caller's
|
|
61
|
+
settings decide; see `profiles.md`.
|
|
62
|
+
|
|
63
|
+
A foreground `run` writes `multi-agent: started job NAME` to stderr as soon as
|
|
64
|
+
the job starts, then blocks and prints the result when the run ends. If the
|
|
65
|
+
command receives SIGINT, SIGTERM or SIGHUP, the job stops with status `killed`
|
|
66
|
+
and the command still prints the result. A second signal ends the command at
|
|
67
|
+
once.
|
|
68
|
+
|
|
69
|
+
A background `run` prints the following and exits with code 0. `timeout_s`
|
|
70
|
+
is `none` when the run has no limit.
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
job: explore-3f9a
|
|
74
|
+
status: running
|
|
75
|
+
timeout_s: 3600
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## resume
|
|
79
|
+
|
|
80
|
+
`resume` starts a new run of a job that is not running. The agent continues
|
|
81
|
+
the job's conversation, with the profile, model, thinking level, tools, system
|
|
82
|
+
prompt and working directory that the job was created with. Editing the
|
|
83
|
+
profile afterwards does not change an existing job.
|
|
84
|
+
|
|
85
|
+
Only `--background` and `--timeout` can be given. They apply to the new run
|
|
86
|
+
alone and have the same defaults as for `run`, so a resumed run does not
|
|
87
|
+
inherit the previous run's timeout. Output is the same as for `run`.
|
|
88
|
+
|
|
89
|
+
The job's status, result and duration always describe its latest run. If the
|
|
90
|
+
job has no saved conversation, for example because pi failed during start-up,
|
|
91
|
+
`resume` prints a note to stderr and the agent starts a new conversation.
|
|
92
|
+
|
|
93
|
+
## wait and result
|
|
94
|
+
|
|
95
|
+
`wait` blocks until the job is no longer running and prints its result.
|
|
96
|
+
Without `--timeout` it waits as long as the job runs. When `--timeout`
|
|
97
|
+
expires first, it prints the following and exits with code 2; the
|
|
98
|
+
`last_progress` line is missing when the progress log is empty.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
job: explore-3f9a
|
|
102
|
+
status: running
|
|
103
|
+
waited_s: 120
|
|
104
|
+
last_progress: 14:02:11 grep retry policy
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`result` prints the result of a job that is not running and fails with `job
|
|
108
|
+
NAME is still running; use wait` otherwise.
|
|
109
|
+
|
|
110
|
+
`run` in the foreground, `wait` and `result` print the result as the agent's
|
|
111
|
+
final message followed by a footer:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
<final assistant text>
|
|
115
|
+
|
|
116
|
+
--- multi-agent ---
|
|
117
|
+
name: explore-3f9a
|
|
118
|
+
status: done
|
|
119
|
+
profile: Explore
|
|
120
|
+
model: anthropic/claude-sonnet-5
|
|
121
|
+
duration_s: 84
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The text is `(no output)` when the run produced none. For a `failed` run it
|
|
125
|
+
ends with an `error:` line. `model` is the model that wrote the latest
|
|
126
|
+
message, or the requested model when none did, or `(pi default)` when no
|
|
127
|
+
model was requested. `duration_s` covers the latest run. `lifecycle.md`
|
|
128
|
+
explains what the text holds for each status.
|
|
129
|
+
|
|
130
|
+
## steer
|
|
131
|
+
|
|
132
|
+
`steer` sends a message to the running agent, which reads it before its next
|
|
133
|
+
step. It prints `job: NAME` and `steer: queued` once pi has accepted the
|
|
134
|
+
message, and the message appears in the progress log. It fails with `job is
|
|
135
|
+
not running; use resume` when the run has ended or is ending.
|
|
136
|
+
|
|
137
|
+
## abort
|
|
138
|
+
|
|
139
|
+
`abort` asks the agent to stop and prints `job: NAME` and `abort: requested`
|
|
140
|
+
without waiting for it. Steering messages that the agent has not read yet are
|
|
141
|
+
discarded. The run ends with status `aborted`; use `wait` to get the result.
|
|
142
|
+
`abort` fails with `job is not running; use resume` when the run has ended or
|
|
143
|
+
is ending.
|
|
144
|
+
|
|
145
|
+
## kill
|
|
146
|
+
|
|
147
|
+
`kill NAME` stops the run at once and returns after the job's runner has
|
|
148
|
+
exited, which takes at most about 20 seconds. It prints the job name and the
|
|
149
|
+
status the run ended with:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
job: explore-3f9a
|
|
153
|
+
status: killed
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
When the run had already ended, or was ending on its own, `kill` changes
|
|
157
|
+
nothing, prints that status followed by `(not running)`, and exits with code
|
|
158
|
+
0.
|
|
159
|
+
|
|
160
|
+
`kill --all` stops every running job of the current project in parallel and
|
|
161
|
+
prints one such block per job. For a job it could not stop, the block has an
|
|
162
|
+
`error:` line instead of the status, and the command exits with code 1. With
|
|
163
|
+
no running job it prints `no running jobs in this project`.
|
|
164
|
+
|
|
165
|
+
## status
|
|
166
|
+
|
|
167
|
+
`status` prints `key: value` lines: `name`, `status`, `mode` (`foreground` or
|
|
168
|
+
`background`), `profile`, `model`, `parent`, `cwd`, `started_at`, `ended_at`,
|
|
169
|
+
`runs`, `exit_code`, `output_file`, `session_file` and `session_cmd`. A `-`
|
|
170
|
+
marks a missing value. Timestamps are UTC and describe the latest run.
|
|
171
|
+
|
|
172
|
+
`session_cmd` opens the job's conversation in interactive pi. While the job
|
|
173
|
+
runs, `status` adds a `note:` line as a reminder not to open it yet, because
|
|
174
|
+
two processes would then write the same conversation file.
|
|
175
|
+
|
|
176
|
+
## peek
|
|
177
|
+
|
|
178
|
+
`peek` prints the last N lines of the job's progress log, which spans all of
|
|
179
|
+
its runs. Each line starts with the local time. The log records each run's
|
|
180
|
+
start and end, every tool call with a short excerpt of its main argument,
|
|
181
|
+
retries, compactions, cancelled dialogs (`denied:`), steering messages, abort
|
|
182
|
+
requests and timeouts. It does not hold the agent's text; read that with
|
|
183
|
+
`wait` or `result`.
|
|
184
|
+
|
|
185
|
+
## list
|
|
186
|
+
|
|
187
|
+
`list` prints a table with the columns `NAME`, `STATUS`, `MODE`, `PARENT` and
|
|
188
|
+
`AGE`, oldest first. It shows running jobs and jobs that ended in the last 24
|
|
189
|
+
hours; `--all` shows every job of the project. `AGE` is the time since the
|
|
190
|
+
run started for a running job and since it ended otherwise. `PARENT` is the
|
|
191
|
+
job that started this one, or `-`.
|
|
192
|
+
|
|
193
|
+
## profiles
|
|
194
|
+
|
|
195
|
+
`profiles` lists each enabled profile with its description and source file.
|
|
196
|
+
It looks up project profiles in the current directory.
|
|
197
|
+
|
|
198
|
+
## rm
|
|
199
|
+
|
|
200
|
+
`rm` deletes a job that is not running: its state directory and its
|
|
201
|
+
conversation file. It prints `removed: NAME` and fails with `job NAME is
|
|
202
|
+
running; kill it first` while the job runs.
|
|
203
|
+
|
|
204
|
+
## Exit codes
|
|
205
|
+
|
|
206
|
+
| Code | Meaning |
|
|
207
|
+
|---|---|
|
|
208
|
+
| 0 | The job ended with status `done`, or the command succeeded. |
|
|
209
|
+
| 1 | The job ended with another status, or the command failed. |
|
|
210
|
+
| 2 | `wait` timed out and the job is still running. |
|
|
211
|
+
| 64 | Usage error, such as an unknown option or a missing prompt. |
|
|
212
|
+
|
|
213
|
+
The job's status decides the exit code of a foreground `run` or `resume`, of
|
|
214
|
+
`wait` and of `result`. The other commands exit with 0 when they succeed.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Job lifecycle
|
|
2
|
+
|
|
3
|
+
A job is a named agent and its conversation. `run` creates the job and starts
|
|
4
|
+
its first run; each `resume` starts another run in the same conversation. A
|
|
5
|
+
job has at most one run at a time, and its status describes the latest run.
|
|
6
|
+
|
|
7
|
+
## Statuses
|
|
8
|
+
|
|
9
|
+
| Status | Meaning | Result text |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `running` | The agent is working. | — |
|
|
12
|
+
| `done` | The agent finished its turn. | Its final message. |
|
|
13
|
+
| `failed` | The run could not finish; see below. | The agent's last message, if any, then an `error:` line. |
|
|
14
|
+
| `aborted` | `abort` stopped the agent, or something else aborted its turn. | Its last message. |
|
|
15
|
+
| `timeout` | The run reached its `--timeout`. | Its last message. |
|
|
16
|
+
| `killed` | `kill`, a signal to the job's runner, or the end of a foreground command stopped the run. | Its last message. |
|
|
17
|
+
| `died` | The job's runner ended without recording a result, for example after a SIGKILL. | None; the result reads `(no output)`. |
|
|
18
|
+
|
|
19
|
+
A run ends as `failed` when the model returns an error after pi's own retries,
|
|
20
|
+
pi rejects the prompt, pi cannot start, or pi exits during the run. In the
|
|
21
|
+
last case the result holds the end of pi's stderr. A model or tool name that
|
|
22
|
+
pi rejects is a common cause.
|
|
23
|
+
|
|
24
|
+
"Last message" is the text of the agent's latest message in this run. It is
|
|
25
|
+
empty when that message had only tool calls, or when the run stopped before
|
|
26
|
+
the agent wrote anything; the result then reads `(no output)`. A message cut
|
|
27
|
+
short by an abort keeps the text written before it.
|
|
28
|
+
|
|
29
|
+
A prompt that pi handles by itself without starting the agent, such as an
|
|
30
|
+
extension command, ends the run at once as `done` with no output.
|
|
31
|
+
|
|
32
|
+
## How a run stops
|
|
33
|
+
|
|
34
|
+
- **The agent finishes.** The status is `done`, or `failed` if its last
|
|
35
|
+
message was an error.
|
|
36
|
+
- **`abort`.** Steering messages that the agent has not read are discarded and
|
|
37
|
+
pi is asked to abort the current turn. The agent gets 30 seconds to wind
|
|
38
|
+
down; after that the run is stopped anyway. The status is `aborted`.
|
|
39
|
+
- **Timeout.** The limit counts from the start of the run. When it is
|
|
40
|
+
reached, the run is aborted as above and ends as `timeout`.
|
|
41
|
+
- **`kill`, a signal, or the end of a foreground command.** The run stops at
|
|
42
|
+
once without the 30-second wind-down. The status is `killed`.
|
|
43
|
+
|
|
44
|
+
In every case pi is shut down cleanly: it gets 10 seconds to exit, then
|
|
45
|
+
SIGTERM, then SIGKILL 5 seconds later. A run that hits its timeout can
|
|
46
|
+
therefore take up to 45 seconds to end. `steer` and `abort` fail with `job is
|
|
47
|
+
not running; use resume` as soon as the run has started to end.
|
|
48
|
+
|
|
49
|
+
## Foreground and background runs
|
|
50
|
+
|
|
51
|
+
Every run is driven by its own runner process, detached from the caller's
|
|
52
|
+
terminal and process group.
|
|
53
|
+
|
|
54
|
+
- A foreground run is tied to the command that started it. Whatever ends that
|
|
55
|
+
command, SIGKILL included, stops the agent and the commands it was running.
|
|
56
|
+
On SIGINT, SIGTERM or SIGHUP the command waits for the run to stop and
|
|
57
|
+
prints its result; a second signal ends it at once. A foreground run started
|
|
58
|
+
by another agent is tied to that agent's command in the same way, so a chain
|
|
59
|
+
of foreground runs stops together.
|
|
60
|
+
- A background run keeps going after its caller ends, until it finishes,
|
|
61
|
+
reaches its timeout, or is stopped with `kill`.
|
|
62
|
+
- If a runner is killed with SIGKILL, its job's status becomes `died` at once.
|
|
63
|
+
The agent's pi process usually exits within a second, but commands the agent
|
|
64
|
+
was running may keep running.
|
|
65
|
+
|
|
66
|
+
## Timeouts
|
|
67
|
+
|
|
68
|
+
A timeout applies to one run. `run` and `resume` default to 3600 seconds in
|
|
69
|
+
the background and to no limit in the foreground; `--timeout 0` removes the
|
|
70
|
+
limit, and fractional seconds are allowed. A timeout does not carry over to
|
|
71
|
+
the next run.
|
|
72
|
+
|
|
73
|
+
## Dialogs and approvals
|
|
74
|
+
|
|
75
|
+
No person watches an agent. When an extension inside the agent opens a dialog
|
|
76
|
+
(select, confirm, input or editor), it is cancelled at once and logged in the
|
|
77
|
+
progress log as `denied:`. The pi-minimal-permission-system extension, if
|
|
78
|
+
installed, runs in its non-interactive mode, so tool calls that need approval
|
|
79
|
+
are blocked. The agent is told not to retry them and to report what it could not do in its final
|
|
80
|
+
message.
|
|
81
|
+
|
|
82
|
+
## Nesting
|
|
83
|
+
|
|
84
|
+
An agent can start agents of its own. `MULTI_AGENT_DEPTH` counts the depth: 0
|
|
85
|
+
or unset for the user's agent, 1 for an agent it started, and so on. `run` and
|
|
86
|
+
`resume` refuse to start when the caller's depth is at least
|
|
87
|
+
`MULTI_AGENT_MAX_DEPTH` (default 2), so by default the user's agent and its
|
|
88
|
+
agents can delegate, and their agents cannot. Agents inherit
|
|
89
|
+
`MULTI_AGENT_MAX_DEPTH` from the environment of the user's agent.
|
|
90
|
+
|
|
91
|
+
`MULTI_AGENT_JOB` holds the job directory of the agent that is running.
|
|
92
|
+
`status` and `list` use it to show the job that started each job.
|