pi-multi-agent-skill 0.0.0-stage → 0.2.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 +147 -2
- package/package.json +32 -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 +218 -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 +57 -0
- package/skills/multi-agent/references/troubleshooting.md +59 -0
- package/skills/multi-agent/scripts/multi_agent.py +2100 -0
|
@@ -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:`. Extensions that have a non-interactive mode run in
|
|
78
|
+
it (see `state.md`), so tool calls that need a person fail without opening a
|
|
79
|
+
dialog. The agent is told not to retry them and to report what it could not
|
|
80
|
+
do in its final message.
|
|
81
|
+
|
|
82
|
+
## Nesting
|
|
83
|
+
|
|
84
|
+
An agent can start agents of its own. `PI_MULTI_AGENT_DEPTH` counts the depth:
|
|
85
|
+
0 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
|
+
`PI_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
|
+
`PI_MULTI_AGENT_MAX_DEPTH` from the environment of the user's agent.
|
|
90
|
+
|
|
91
|
+
`PI_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.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Profiles
|
|
2
|
+
|
|
3
|
+
A profile sets an agent's system prompt, model, thinking level and tools. It
|
|
4
|
+
is a Markdown file with frontmatter; the body after the frontmatter is the
|
|
5
|
+
profile's prompt.
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
---
|
|
9
|
+
description: Reviews a diff for correctness bugs.
|
|
10
|
+
model: anthropic/claude-sonnet-5
|
|
11
|
+
thinking: high
|
|
12
|
+
tools: read, grep, find, ls, bash
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You review code changes. Report each bug with its file, line and a failing
|
|
16
|
+
scenario.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Where profiles come from
|
|
20
|
+
|
|
21
|
+
Profiles are looked up in three directories, from highest to lowest priority:
|
|
22
|
+
|
|
23
|
+
1. `<cwd>/.pi/agents/*.md` (project), where `<cwd>` is the agent's working
|
|
24
|
+
directory
|
|
25
|
+
2. `$PI_CODING_AGENT_DIR/agents/*.md`, default `~/.pi/agent/agents/` (user)
|
|
26
|
+
3. `profiles/*.md` in this skill's directory (built-in)
|
|
27
|
+
|
|
28
|
+
Names are matched case-insensitively. When several directories define the
|
|
29
|
+
same name, the file from the highest directory is used as a whole; fields are
|
|
30
|
+
never merged across files. To change one field of a built-in profile, copy the
|
|
31
|
+
whole file and edit the copy. A profile with `enabled: false` hides its name,
|
|
32
|
+
including lower profiles of that name.
|
|
33
|
+
|
|
34
|
+
A job keeps the settings it was created with. Editing a profile affects new
|
|
35
|
+
jobs only, not `resume` of an existing one.
|
|
36
|
+
|
|
37
|
+
## Fields
|
|
38
|
+
|
|
39
|
+
| Field | Default | Effect |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `name` | file name without `.md` | Profile name. |
|
|
42
|
+
| `description` | `name` | Shown by `profiles`. |
|
|
43
|
+
| `model` | the caller's model | Passed to `pi --model`. |
|
|
44
|
+
| `thinking` | the caller's thinking level | Passed to `pi --thinking`. |
|
|
45
|
+
| `tools` | pi's default tool selection | Passed to `pi --tools`. |
|
|
46
|
+
| `disallowed_tools` | none | Passed to `pi --exclude-tools`. |
|
|
47
|
+
| `prompt_mode` | `append` | `append` or `replace`; see below. |
|
|
48
|
+
| `enabled` | `true` | `false` hides the profile. |
|
|
49
|
+
|
|
50
|
+
Unknown fields are ignored. The parser reads `key: value` lines, quoted
|
|
51
|
+
strings, `true`/`false` and `[a, b]` lists, and skips comments and indented
|
|
52
|
+
lines; it does not support nested YAML.
|
|
53
|
+
|
|
54
|
+
## Model and thinking level
|
|
55
|
+
|
|
56
|
+
For each of the two, the first value found wins: the `run` option, the profile
|
|
57
|
+
field, the caller's current setting, then pi's configured default. The
|
|
58
|
+
caller's settings come from the `PI_PROVIDER`, `PI_MODEL` and
|
|
59
|
+
`PI_REASONING_LEVEL` variables that pi sets for the commands it runs.
|
|
60
|
+
|
|
61
|
+
## Tools
|
|
62
|
+
|
|
63
|
+
`tools` and `disallowed_tools` accept a comma-separated list or `[a, b]`. The
|
|
64
|
+
entries are passed to pi verbatim as `--tools` and `--exclude-tools`; see pi's
|
|
65
|
+
documentation of those options for the patterns they accept and which tools
|
|
66
|
+
they keep.
|
|
67
|
+
|
|
68
|
+
## System prompt
|
|
69
|
+
|
|
70
|
+
With `prompt_mode: append`, the profile's body is passed to pi with
|
|
71
|
+
`--append-system-prompt`, so it is added to the system prompt pi builds as
|
|
72
|
+
usual. With `prompt_mode: replace`, the body is passed with `--system-prompt`
|
|
73
|
+
and pi also gets `--no-context-files`. Any other value makes `run` fail.
|
|
74
|
+
|
|
75
|
+
Every agent also receives a short block that tells it its job name, that only
|
|
76
|
+
its final message is read, and that no person can approve blocked tool calls.
|
|
77
|
+
This block is passed with `--append-system-prompt` in both modes, so pi does
|
|
78
|
+
not load `APPEND_SYSTEM.md` files for agents; put text that agents need in a
|
|
79
|
+
profile's body.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# State
|
|
2
|
+
|
|
3
|
+
## Locations
|
|
4
|
+
|
|
5
|
+
Job directories are in
|
|
6
|
+
`$XDG_STATE_HOME/pi-multi-agent/<project>/jobs/<name>/` (default
|
|
7
|
+
`~/.local/state`). `<project>` is the project's directory with every character
|
|
8
|
+
other than a letter or digit replaced by `-` and the leading `-` removed, so
|
|
9
|
+
`/home/me/app` becomes `home-me-app`.
|
|
10
|
+
|
|
11
|
+
A running job's runner listens on a Unix socket in
|
|
12
|
+
`$XDG_STATE_HOME/pi-multi-agent/sockets/`, which `steer`, `abort` and `kill`
|
|
13
|
+
connect to. Conversations are pi session files in
|
|
14
|
+
`$PI_CODING_AGENT_DIR/multi-agent-sessions/<project>/` (default
|
|
15
|
+
`~/.pi/agent/`), so they stay out of pi's `/resume` list.
|
|
16
|
+
|
|
17
|
+
## Job files
|
|
18
|
+
|
|
19
|
+
| File | Content |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `job.json` | Launch settings: profile, pi arguments, cwd, parent job, depth, run mode, timeout. |
|
|
22
|
+
| `prompt.txt` | Prompt of the latest run. |
|
|
23
|
+
| `system-prompt.md` | The profile's prompt, when it replaces pi's system prompt. |
|
|
24
|
+
| `append-prompt.md` | Text added to pi's system prompt: the profile's prompt in append mode, then the multi-agent block. |
|
|
25
|
+
| `status` | Status of the latest run; final once `exit_code` exists. |
|
|
26
|
+
| `lock` | Held by the job's runner for as long as it runs. The job is running exactly while this lock is held. |
|
|
27
|
+
| `started_at`, `ended_at` | UTC timestamps of the latest run. |
|
|
28
|
+
| `runs` | Number of runs. |
|
|
29
|
+
| `exit_code` | Exit code of the latest run, written last. A run without it that is no longer running has `died`. |
|
|
30
|
+
| `output.txt` | Result text of the latest run; empty if that run produced none. |
|
|
31
|
+
| `model` | Model that wrote the latest message. |
|
|
32
|
+
| `stderr.txt` | pi's stderr for the latest run. |
|
|
33
|
+
| `progress.log` | The lines `peek` prints, across runs. |
|
|
34
|
+
| `usage.json` | Token and cost totals across runs. |
|
|
35
|
+
| `runner.log` | Traceback when the runner itself fails. |
|
|
36
|
+
|
|
37
|
+
Starting a run clears the previous run's result, end time and model, so these
|
|
38
|
+
files always describe the latest run.
|
|
39
|
+
|
|
40
|
+
## Reading a conversation
|
|
41
|
+
|
|
42
|
+
To read a finished job's whole conversation in interactive pi, run the
|
|
43
|
+
`session_cmd` that `status` prints. Do not open it while the job is running,
|
|
44
|
+
because two processes would then write the same session file.
|
|
45
|
+
|
|
46
|
+
## The agent's environment
|
|
47
|
+
|
|
48
|
+
The script starts the program in `PI_MULTI_AGENT_PI_BIN` (default `pi`). An
|
|
49
|
+
agent inherits the environment of the command that started it, plus:
|
|
50
|
+
|
|
51
|
+
| Variable | Value |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `PI_MULTI_AGENT_JOB` | The agent's job directory. |
|
|
54
|
+
| `PI_MULTI_AGENT_DEPTH` | The agent's nesting depth; see `lifecycle.md`. |
|
|
55
|
+
| `PI_MINIMAL_PERMISSION_SYSTEM_NONINTERACTIVE` | `1`, so that extension never waits for an approval. |
|
|
56
|
+
| `PI_REQUEST_USER_INPUT_NONINTERACTIVE` | `1`, so that extension never asks the user a question. |
|
|
57
|
+
| `PWD` | The agent's working directory. |
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Job status
|
|
4
|
+
|
|
5
|
+
- **Status `failed` with `pi exited before the run finished`.** pi stopped
|
|
6
|
+
during start-up or the run. The output holds the end of pi's stderr; the
|
|
7
|
+
whole log is in the job's `stderr.txt`. A model or tool name that pi rejects
|
|
8
|
+
causes this.
|
|
9
|
+
- **Status `failed` with `the runner failed`.** The script itself hit an
|
|
10
|
+
error. The traceback is in the job's `runner.log`.
|
|
11
|
+
- **Status `died`.** The runner was killed without a chance to record a
|
|
12
|
+
result. The agent's pi process exits by itself, usually within a second,
|
|
13
|
+
but commands it started can survive; look for them with `ps` if the agent
|
|
14
|
+
was running a long command. `peek` shows how far it got; `resume`
|
|
15
|
+
continues the conversation. Wait a few seconds before you `resume` a job
|
|
16
|
+
that has just died, so its old pi has exited and does not write the
|
|
17
|
+
conversation at the same time as the new one.
|
|
18
|
+
- **An agent reports that a tool call needs approval.** Agents cannot ask a
|
|
19
|
+
person. Run that step yourself, or tell the user what was blocked.
|
|
20
|
+
- **A job lingers after its caller is gone.** Background jobs outlive their
|
|
21
|
+
caller by design. Stop them with `kill NAME`, or `kill --all` when the user
|
|
22
|
+
asks.
|
|
23
|
+
|
|
24
|
+
## Command errors
|
|
25
|
+
|
|
26
|
+
- **`job is not running; use resume`.** The run has ended or is ending.
|
|
27
|
+
`resume` the job with a new prompt instead of steering it.
|
|
28
|
+
- **`job NAME already exists in this project`.** Pick another `--name`.
|
|
29
|
+
The error shows the existing job's status and age. Use `resume` or `rm`
|
|
30
|
+
only for a job you started or the user asked about.
|
|
31
|
+
- **`job NAME is running` from `resume` or `rm`.** The job's runner is
|
|
32
|
+
still alive, or another command was starting the job at the same moment.
|
|
33
|
+
`wait` for it, or `kill` it first.
|
|
34
|
+
- **`unknown profile: P (available: ...)`.** No enabled profile has that name
|
|
35
|
+
in the agent's working directory; the message lists the ones that exist.
|
|
36
|
+
- **`--fork needs PI_SESSION_FILE`.** The command does not run inside pi, so
|
|
37
|
+
there is no conversation to copy. Drop `--fork` and write a self-contained
|
|
38
|
+
prompt.
|
|
39
|
+
- **`cannot start an agent: ... PI_MULTI_AGENT_MAX_DEPTH`.** The caller is too
|
|
40
|
+
deep in a chain of agents. Do the work directly.
|
|
41
|
+
- **`the runner of job NAME is not responding`.** The runner did not answer
|
|
42
|
+
`kill` within 10 seconds, or did not exit within 20 seconds after it
|
|
43
|
+
answered. The message ends with a `pkill` command that stops that runner;
|
|
44
|
+
run it, then wait a few seconds before you `resume` the job (see `died`).
|
|
45
|
+
- **`the job's working directory no longer exists`.** `resume` runs the
|
|
46
|
+
agent in the directory the job was started in. Start a new job instead.
|
|
47
|
+
- **`job NAME exists in several projects`.** Run the command from the
|
|
48
|
+
directory where the job was started.
|
|
49
|
+
|
|
50
|
+
## Environment
|
|
51
|
+
|
|
52
|
+
- **`cannot find the pi program`.** Set `PI_MULTI_AGENT_PI_BIN` to the command
|
|
53
|
+
that starts pi, such as `pi-bolt`, or ask the user which one they use.
|
|
54
|
+
- **`flock does not work on ...`.** The state directory is on a file system
|
|
55
|
+
without working file locks, such as some NFS or SMB mounts. Set
|
|
56
|
+
`XDG_STATE_HOME` to a directory on a local file system.
|
|
57
|
+
- **`the socket path for this job is too long`.** The socket path under
|
|
58
|
+
`XDG_STATE_HOME` exceeds the system's limit for Unix sockets (about 100
|
|
59
|
+
bytes). Set `XDG_STATE_HOME` to a shorter path.
|