summaryrefslogtreecommitdiff
path: root/README.md
blob: 6841ed96abb4efbe3748853c889baf5922b2ffa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# panto-subagents

Delegation and workflows for [Pantograph](https://github.com/travisp/pantograph).
The `subagents` extension lets a primary agent start specialized child agents,
run several at once, and continue their conversations later.

## Install

```toml
[extensions]
rocks = ["panto-subagents"]
```

For a local checkout, use `paths = ["/path/to/panto-subagents"]` instead. A
`paths` entry loads the code but installs nothing, so put the dependencies below
in panto's own rocks tree first:

```sh
TREE="$(echo ~/.local/share/panto/rocks/lua-*)"
luarocks --lua-version 5.4 --tree "$TREE" install toml2lua
luarocks --lua-version 5.4 --tree "$TREE" install api7-lua-tinyyaml
```

(Every rock here is pure Lua, so any LuaRocks targeting Lua 5.4 can populate
panto's tree. A `rocks` entry needs none of this — panto installs dependencies
with the rock.)

### Dependencies

Panto installs the rock's dependencies with it:

- **api7-lua-tinyyaml** parses profile frontmatter. Pure Lua, nothing to
  install alongside it. It covers a subset of YAML — every quoting, escaping
  and block-scalar form profiles use, but not anchors/aliases (flagged with a
  warning rather than silently misread) and not plain multi-line scalars
  (a parse warning). Full-spec `lyaml` was the alternative, rejected because
  binding the system libyaml makes the rock fail to build wherever that
  library is absent.
- **toml2lua** reads the layered `config.toml` at activation and TOML workflows
  afterwards. Pure Lua, nothing to install; without it activation fails.
- **luv** backs profile and workflow discovery. Panto already ships it.

Structured workflow output is validated against its JSON Schema by a built-in
validator covering the schema subset those results use. Installing the
`jsonschema` rock switches validation over to it; that rock needs a system PCRE,
so it is not a declared dependency.

## Configuration

At most five children run concurrently by default; additional children queue.
Override the limit in any layered `config.toml` (later layers win):

```toml
[subagents]
max_concurrent = 10
```

`max_concurrent` must be a positive integer.

## Agent profiles

Agents are Markdown files with YAML frontmatter:

```markdown
---
name: reviewer
description: Reviews changes for correctness and missing tests
model: anthropic:sonnet
reasoning: high
---

You are a focused code reviewer. Report only concrete findings.
```

Profiles are loaded recursively from `agents/` beneath every Panto config
layer, lowest precedence first: the built-in base layer,
`${XDG_CONFIG_HOME:-$HOME/.config}/panto/`, `.panto/`, and `.panto/local/`.

A more local profile overrides an earlier one with the same name. `name` defaults to
the filename. `model` and `reasoning` are optional; each value follows the same
precedence: tool call, then profile, then the primary agent. Models use full
`provider:model` names.

## Delegation

The primary uses `subagents.run` to start a child from a profile:

```lua
subagents.run {
  agent = "reviewer",
  prompt = "Review the authentication changes.",
}
```

A one-off child can instead take an inline system prompt, without a saved
profile:

```lua
subagents.run {
  system_prompt = "You are a focused code reviewer.",
  prompt = "Review the authentication changes.",
}
```

`agent`, `system_prompt`, and `id` are mutually exclusive.

Every started child returns an ID. Passing it back resumes the same
conversation, including after restarting Panto and resuming the primary:

```lua
subagents.run {
  id = "0198...",
  prompt = "Now focus on the missing tests.",
}
```

Children start a fresh conversation with the fixed child-role instruction and
their profile prompt; the primary's system prompt and conversation are not
copied. They share its workspace and tools except for `subagents.*`.

Multiple calls in one tool batch run concurrently. Their tagged assistant and
tool activity is visible in the TUI while they work. Child conversations are
stored as normal JSONL sessions beneath their owning primary session, so they
remain resumable without appearing in the user's `/resume` picker. A child ID
cannot be resumed from another primary conversation.

`subagents.models` provides bounded search and validation for configured
providers, models, and model-specific reasoning levels without placing the
entire model catalog in every tool prompt.

## Workflows

TOML workflows define fixed dependency graphs. They are loaded from
`workflows/` beneath the same config layers as profiles, then exposed as
`/workflow:<name>` commands. Ready steps
run concurrently; each dependent step receives its predecessors' labeled
outputs. The workflow reports its terminal steps, or exactly the steps a
top-level `output = ["id", ...]` array names, in that order.

The Lua workflow API handles dynamic branching and fan-out. `subagents.lua`
starts model-authored workflows in a restricted environment and returns a
session-scoped workflow ID immediately. Work continues on Pantograph's event
loop; completion wakes the primary, and later calls can inspect field-read-only
records through `subagents.workflows[id]`, including named child status and
outputs. While one is live the extension emits balanced `background_work_start`
and `background_work_end` events, allowing lifecycle integrations to remain
busy across the primary turn boundary. Every `ctx:agent` needs a workflow-unique
`name`, and the callback must return the workflow's string result.

The same read-only workflow records are exposed to other extensions as
`panto.ext.workflows`. Extensions can iterate this table or look up an ID; each
record has `id`, `status`, `result`, `error`, and `agents`, and a `status` of
`running` identifies in-flight background work. Fields are read-only, but
`workflow:cancel()` requests cancellation for every running agent and
`workflow.agents[name]:cancel()` requests cancellation for one; both return
true only while their target is running.

Inline `agents` remain scoped to workflows started by that tool call. The API
can await one job or a group and supports one-turn workers whose validated tool
input is their structured result. Persistent TOML workflows remain the simpler
fixed-DAG surface.

## Development

[mise](https://mise.jdx.dev) provides Lua 5.4 and LuaRocks:

```sh
mise run deps    # install the rocks into ./.rocks (gitignored)
mise run check   # run the specs against that tree
```

Without mise, install the same rocks with any LuaRocks targeting Lua
5.4 and run `lua spec/run.lua` from the repo root. `panto lua spec/run.lua` runs
the suite inside panto's own interpreter and rocks tree, skipping whatever cases
that tree has no rock for.

The specs are plain Lua asserts — no framework. `spec/run.lua` loads every
`spec/test_*.lua`, each of which returns an ordered array of `{ name, function }`
cases. A case asserts and returns nothing to pass, or returns `"skip", reason`
when an optional rock is missing; skips do not fail the run. `spec/fake_ext.lua`
is a scriptable stand-in for the `panto.ext` host seam: it queues the result each
spawned child settles with, records every spawn spec, tool, and command the
extension produced, and settles awaits synchronously.

See [DESIGN.md](DESIGN.md) for the runtime and persistence design.