docs: add Trellis planning and project specs
This commit is contained in:
67
.pi/skills/trellis-channel/SKILL.md
Normal file
67
.pi/skills/trellis-channel/SKILL.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: trellis-channel
|
||||
description: Use Trellis channel for live multi-agent collaboration, spawned workers, cross-agent review, progress inspection, forum channels, and channel log debugging.
|
||||
---
|
||||
|
||||
# trellis-channel
|
||||
|
||||
`trellis channel` is the local multi-agent collaboration runtime. Reach for it when agents need to talk through a durable event log, when a worker should be spawned as a peer process, when an in-flight worker needs interrupt / debugging, or when feedback should be recorded on a durable `--type forum` channel.
|
||||
|
||||
Typical user signals: "和 codex/claude 讨论", "brainstorm with another agent", "spawn an implement/check worker", "let agent review", "open an issue board / changelog forum", "look at this thread", "channel is stuck / no output", "progress was truncated", "how do I write that channel command".
|
||||
|
||||
This skill is an index. Load only the reference file for the current job — do not preload all of them.
|
||||
|
||||
## First Commands
|
||||
|
||||
```bash
|
||||
trellis --version
|
||||
trellis channel --help
|
||||
trellis channel list --all
|
||||
trellis channel list --scope global --all
|
||||
```
|
||||
|
||||
If the user names a channel or thread, inspect it before asking for background:
|
||||
|
||||
```bash
|
||||
trellis channel forum <board> --scope global
|
||||
trellis channel thread <board> <thread> --scope global
|
||||
trellis channel context list <board> --scope global --thread <thread>
|
||||
```
|
||||
|
||||
## Route By User Intent
|
||||
|
||||
| User intent | Read |
|
||||
|---|---|
|
||||
| "和 codex/claude 讨论一下", "brainstorm with another agent" | `references/workflows.md` |
|
||||
| "派一个 implement/check agent", "让 agent review", "spawn a worker" | `references/workflows.md`, then `references/workers.md` |
|
||||
| "开 issue 区 / topic 群 / changelog / board", "make a forum" | `references/forum.md` |
|
||||
| "看看这个 thread / linked context", "inspect a thread" | `references/forum.md` |
|
||||
| "channel 卡住了 / 没输出 / progress 被截断", "worker stalled" | `references/progress-debugging.md` |
|
||||
| "具体命令怎么写", "what flags does X take" | `references/command-reference.md` |
|
||||
|
||||
## Core Rules
|
||||
|
||||
- New forum channels use `--type forum`. A `thread` is one item inside a forum channel.
|
||||
- Use `--context-file` / `--context-raw` and `trellis channel context add/delete/list`. `--linked-context-*` is deprecated terminology.
|
||||
- Use `--stdin` or `--text-file` for long messages. Do not put long mixed Chinese/English text in the positional shell argument.
|
||||
- Pretty `messages` output is an operator dashboard and may truncate progress. Use `--raw` for audit.
|
||||
- `--as` is the speaker or worker handle, depending on the command. Use explicit, stable names when multiple agents or sessions are involved.
|
||||
- `--scope project` (default) operates on the current cwd's project bucket; `--scope global` operates on the shared `__global__` bucket. Pick scope deliberately — a global board is invisible from project listings unless `--scope global` is passed.
|
||||
- For brainstorm, do multiple pressure-test rounds. One answer plus one confirmation is review, not brainstorm.
|
||||
- **Dispatcher wait pattern**: use `--kind done` / `--kind turn_finished` (trellis-emitted system events), NOT a user `--tag` as the completion signal. CLI help lists `phase_done` / `question` as `--tag` examples but only `interrupt` is a reserved tag with hardcoded trellis behavior; the others are opaque user labels. Relying on a worker to run `send --tag <my_signal>` is unreliable — LLM workers commonly write the tag string into prose instead of running the actual CLI command. See `references/command-reference.md` "tag vs kind".
|
||||
- Forum channels are event-sourced. Do not parse `events.jsonl` first; use `forum`, `thread`, `messages --thread`, and `context list`.
|
||||
- `@mindfoldhq/trellis-core` owns reusable channel/thread state, event append, seq allocation, context/title projection, reducers, and task helpers. The CLI owns flags, terminal rendering, prompts, worker lifecycle, and process exits.
|
||||
|
||||
## Reference Files
|
||||
|
||||
- `references/workflows.md` — canonical collaboration patterns A–F (peer brainstorm, spawned review, dispatch-and-wait, forum issue capture, interrupt-and-redirect, one-shot run).
|
||||
- `references/forum.md` — forum channels, context, title, rename, changelog forums, thread filtering.
|
||||
- `references/workers.md` — spawn, agent cards, context injection (`--file` / `--jsonl`), interrupts, kill semantics.
|
||||
- `references/progress-debugging.md` — progress/raw inspection, stalled worker diagnosis, OOM guard, exit codes.
|
||||
- `references/command-reference.md` — current CLI command reference (every subcommand, every flag, output conventions, scope/type model).
|
||||
|
||||
## Not For
|
||||
|
||||
- One static review where a markdown file and prompt are enough.
|
||||
- Replacing normal tool calls with self-logging.
|
||||
- Long-term memory retrieval. Use durable forum channels for actionable issues, and `trellis mem` (the `trellis-session-insight` skill) for session/history search.
|
||||
480
.pi/skills/trellis-channel/references/command-reference.md
Normal file
480
.pi/skills/trellis-channel/references/command-reference.md
Normal file
@@ -0,0 +1,480 @@
|
||||
# Command Reference
|
||||
|
||||
Authoritative current command reference for `trellis channel` subcommands,
|
||||
validated against the source in `packages/cli/src/commands/channel/`
|
||||
(`index.ts` Commander wiring and each subcommand handler).
|
||||
|
||||
Every subcommand accepts `--scope <project|global>` unless noted; `project`
|
||||
is the default and resolves against the current cwd's project bucket.
|
||||
|
||||
## Top-level
|
||||
|
||||
```
|
||||
trellis channel <subcommand>
|
||||
```
|
||||
|
||||
> Multi-agent collaboration runtime — spawn / coordinate / interrupt worker
|
||||
> agents through a shared event log.
|
||||
|
||||
---
|
||||
|
||||
## Create / List
|
||||
|
||||
### `create <name>`
|
||||
|
||||
```bash
|
||||
trellis channel create <name>
|
||||
[--scope project|global] # default: project
|
||||
[--type chat|forum] # default: chat
|
||||
[--task <path>] # associated Trellis task dir
|
||||
[--project <slug>]
|
||||
[--labels a,b,c]
|
||||
[--description <text>] # stable channel description
|
||||
[--context-file <abs-path>] ... # repeatable
|
||||
[--context-raw <text>] ... # repeatable
|
||||
[--linked-context-file <abs-path>] # [deprecated alias]
|
||||
[--linked-context-raw <text>] # [deprecated alias]
|
||||
[--cwd <path>] # recorded in create event
|
||||
[--by <agent>] # default: main
|
||||
[--force] # overwrite existing channel
|
||||
[--ephemeral] # hide from default list, prunable
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Appends a `create` event; immutable `type` (cannot mutate forum↔chat after).
|
||||
- `--ephemeral` channels are hidden from `channel list` by default and are
|
||||
the sweep target for `channel prune --ephemeral`.
|
||||
- `--linked-context-*` are folded into `--context-*`; emit a deprecation
|
||||
notice when used.
|
||||
|
||||
### `list`
|
||||
|
||||
```bash
|
||||
trellis channel list
|
||||
[--scope project|global]
|
||||
[--json]
|
||||
[--project <slug>] # substring match on task field
|
||||
[--all] # include ephemeral (suffix '*')
|
||||
[--all-projects] # scan every project bucket
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Default scope: current cwd's project. `--all-projects` scans every bucket.
|
||||
- Pretty mode prints `NAME WORKERS EVENTS LAST KIND TYPE TASK`, sorted by
|
||||
recency, with a footer noting hidden ephemeral count.
|
||||
- `--json` switches to a JSON array.
|
||||
|
||||
---
|
||||
|
||||
## Chat Messages
|
||||
|
||||
### `send <name> [text]`
|
||||
|
||||
```bash
|
||||
trellis channel send <name> [text]
|
||||
--as <agent> # REQUIRED — author
|
||||
[--scope project|global]
|
||||
[--to <agents,csv>] # default: broadcast
|
||||
[--stdin | --text-file <path>] # body from stdin or file
|
||||
[--delivery-mode appendOnly|requireKnownWorker|requireRunningWorker]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Body precedence: positional `[text]` → `--stdin` → `--text-file`.
|
||||
- `--to` with one entry stores a string; multiple stores an array; omitted
|
||||
means broadcast.
|
||||
- `--delivery-mode` selects targeted-delivery validation:
|
||||
- `appendOnly` (default-ish — just record),
|
||||
- `requireKnownWorker` (the named target must have a `spawned` event),
|
||||
- `requireRunningWorker` (the worker must currently be live).
|
||||
- Prints the appended event as one JSON line on stdout.
|
||||
|
||||
> **Note:** `send` has **no** `--tag` and **no** `--kind` flag. See
|
||||
> [`tag-vs-kind`](#tag-vs-kind--how-event-shape-is-actually-controlled) below.
|
||||
|
||||
### `messages <name>`
|
||||
|
||||
```bash
|
||||
trellis channel messages <name>
|
||||
[--scope project|global]
|
||||
[--raw] # one JSON event per line
|
||||
[--follow] # stream new events
|
||||
[--last <N>] # last N matching events
|
||||
[--since <seq>] # seq > N
|
||||
[--kind <kind>] # one of CHANNEL_EVENT_KINDS
|
||||
[--from <csv>] # author filter
|
||||
[--to <target>] # routing target filter
|
||||
[--thread <key>] # forum-only
|
||||
[--action <thread-action>] # forum-only
|
||||
[--no-progress] # hide progress events
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Auto-detects forum channels: with no filters it renders the thread board
|
||||
instead of the event stream. `--thread` / `--action` are forum-only and
|
||||
error against chat channels.
|
||||
- `--kind` is validated against `CHANNEL_EVENT_KINDS` (single value, not
|
||||
CSV — that's the `wait` side).
|
||||
|
||||
### `wait <name>`
|
||||
|
||||
```bash
|
||||
trellis channel wait <name>
|
||||
--as <agent> # REQUIRED — self for filter ctx
|
||||
[--scope project|global]
|
||||
[--timeout <Ns|Nm|Nh|Nms>] # parsed by parseDuration
|
||||
[--from <a,b>] # author CSV
|
||||
[--kind <k1,k2>] # CSV, OR semantics
|
||||
[--thread <key>] # forum filter
|
||||
[--action <thread-action>] # forum filter
|
||||
[--to <target>] # default: own agent (broadcast + me)
|
||||
[--include-progress] # also wake on progress events
|
||||
[--all] # require every --from to match
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Streams matching events as JSON, one per line.
|
||||
- Default `--to` filter is the caller's own agent (broadcast events still
|
||||
match — broadcast + explicit-to-me).
|
||||
- `--all` requires `--from` and blocks until every listed agent has produced
|
||||
a matching event.
|
||||
- **Timeout exits 124** and prints `timeout: still waiting on ...` to stderr
|
||||
when `--all` was in play.
|
||||
|
||||
---
|
||||
|
||||
## tag-vs-kind — how event shape is actually controlled
|
||||
|
||||
There is **no `--tag` flag** anywhere in the v0.6.0 channel CLI; `--kind` is
|
||||
not a legacy alias for any `--tag` flag.
|
||||
|
||||
Concrete model in the current source:
|
||||
|
||||
- `--kind` is the only event-type filter, and it is constrained to the
|
||||
trellis-emitted whitelist (`CHANNEL_EVENT_KINDS` in
|
||||
`packages/core/src/channel/internal/store/events.ts`):
|
||||
- `create`, `join`, `leave`, `message`, `thread`, `context`, `channel`,
|
||||
`spawned`, `killed`, `respawned`, `progress`, `done`, `error`,
|
||||
`waiting`, `awake`, `undeliverable`, `interrupt_requested`,
|
||||
`turn_started`, `turn_finished`, `interrupted`, `supervisor_warning`
|
||||
- Passing anything else throws
|
||||
`Invalid --kind '<x>'. Must be one of: …`.
|
||||
- `--kind` lives on `wait` (CSV, OR semantics) and `messages` (single
|
||||
value). `send` and `run` cannot emit a custom kind — every `send` writes
|
||||
a `message` event.
|
||||
- Mid-turn worker abort is **not** a tag. It is the dedicated
|
||||
`channel interrupt` command, which appends an `interrupt_requested` /
|
||||
`interrupted` pair and provider-level interrupts the worker.
|
||||
|
||||
Practical rule for dispatchers waiting on workers:
|
||||
|
||||
- Use `--kind done,turn_finished` for "worker finished a turn" — these are
|
||||
system events that the supervisor fires automatically. Do not depend on
|
||||
the worker LLM remembering to emit any custom signal.
|
||||
- Use `trellis channel interrupt` (the command) only when you actually want
|
||||
mid-turn abort behavior.
|
||||
- Do **not** invent user-side tags as completion signals. There is no
|
||||
`--tag` filter; a worker writing a custom string into its final message
|
||||
is just text inside a `message` event and cannot be matched by `wait`.
|
||||
|
||||
Long bodies always go through stdin or a file:
|
||||
|
||||
```bash
|
||||
trellis channel send T --as A --stdin < /tmp/message.md
|
||||
trellis channel send T --as A --text-file /tmp/message.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interrupt
|
||||
|
||||
### `interrupt <name> [text]`
|
||||
|
||||
```bash
|
||||
trellis channel interrupt <name> [text]
|
||||
--as <agent> # REQUIRED — caller
|
||||
--to <agent> # REQUIRED — target worker
|
||||
[--scope project|global]
|
||||
[--stdin | --text-file <path>]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Appends an `interrupt` event with `reason: "user"` and a replacement
|
||||
instruction body; supervisor performs provider-level interrupt where
|
||||
supported (Claude `/interrupt`, Codex turn cancel).
|
||||
- Prints the appended event JSON on stdout.
|
||||
|
||||
---
|
||||
|
||||
## Workers
|
||||
|
||||
### `spawn <name>`
|
||||
|
||||
```bash
|
||||
trellis channel spawn <name>
|
||||
[--scope project|global]
|
||||
[--agent <agent-name>] # loads .trellis/agents/<name>.md
|
||||
[--provider claude|codex] # overrides agent file
|
||||
[--as <worker-name>] # default: agent name
|
||||
[--cwd <path>]
|
||||
[--model <id>]
|
||||
[--resume <id>] # session/thread id resume
|
||||
[--timeout <Ns|Nm|Nh>] # auto-kill after duration
|
||||
[--warn-before <Ns|Nm|Nh>] # supervisor_warning lead time
|
||||
# default 5m, 0ms disables
|
||||
[--file <path>] ... # glob, repeatable; inject content
|
||||
[--jsonl <path>] ... # Trellis manifest, repeatable
|
||||
[--by <agent>] # spawn-event author
|
||||
# default: TRELLIS_CHANNEL_AS env or 'main'
|
||||
[--inbox-policy explicitOnly|broadcastAndExplicit]
|
||||
# default explicitOnly
|
||||
[--idle-timeout <Ns|Nm|Nh>] # OOM-guard idle TTL
|
||||
# default 5m, 0 disables
|
||||
[--max-live-workers <n>] # spawn-time live-worker budget
|
||||
# default 6, 0 disables
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Provider is validated against the adapter registry
|
||||
(`packages/cli/src/commands/channel/adapters/`); current: `claude`,
|
||||
`codex`.
|
||||
- Worker stays inbox-idle until the first `send --to <worker>`.
|
||||
- Records a `spawned` event with `pid`, `provider`, `agent`, `files`,
|
||||
`manifests`.
|
||||
- OOM-guard precedence: CLI flag → env var
|
||||
(`TRELLIS_CHANNEL_WORKER_IDLE_TIMEOUT`,
|
||||
`TRELLIS_CHANNEL_MAX_LIVE_WORKERS`) →
|
||||
`.trellis/config.yaml#channel.worker_guard` → built-in defaults.
|
||||
|
||||
### `run [name]`
|
||||
|
||||
```bash
|
||||
trellis channel run [name?]
|
||||
[--agent <name>]
|
||||
[--provider claude|codex]
|
||||
[--as <worker-name>]
|
||||
[--cwd <path>]
|
||||
[--model <id>]
|
||||
[--file <path>] ... # repeatable, glob
|
||||
[--jsonl <path>] ... # repeatable
|
||||
[--message <text> | --message-file <path> | --stdin]
|
||||
[--timeout <Ns|Nm|Nh>] # default 5m
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- One-shot. Auto-generates `run-<hex>` if `name` omitted.
|
||||
- Creates an ephemeral channel (`createMode=run`), spawns a single worker,
|
||||
sends the prompt, waits for `done`, prints the final assistant text to
|
||||
stdout, then removes the channel on success. On failure the channel is
|
||||
kept for inspection and exit code is 1.
|
||||
|
||||
> `run` has **no** `--tag` flag. Completion is detected via the `done`
|
||||
> event the supervisor emits.
|
||||
|
||||
### `kill <name>`
|
||||
|
||||
```bash
|
||||
trellis channel kill <name>
|
||||
--as <agent> # REQUIRED — worker agent name
|
||||
[--scope project|global]
|
||||
[--force] # SIGKILL immediately
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Default path: SIGTERM → 8 s grace → SIGKILL escalation; the CLI writes a
|
||||
`killed` event when SIGKILL was needed so the log stays truthful.
|
||||
- Cleans `pid`, `worker-pid`, `config`, `spawnlock` sidecar files; keeps
|
||||
`log`, `session-id`, `thread-id` for forensics / resume.
|
||||
|
||||
### `rm <name>`
|
||||
|
||||
```bash
|
||||
trellis channel rm <name>
|
||||
[--scope project|global]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Kills any live workers, then deletes the entire channel directory.
|
||||
- Prints `Removed channel '<name>'`.
|
||||
|
||||
### `prune`
|
||||
|
||||
```bash
|
||||
trellis channel prune
|
||||
[--scope project|global] # omitted: scan every project
|
||||
[--all | --empty | --idle <Ns|Nm|Nh|Nd> | --ephemeral] # mutually exclusive
|
||||
[--yes] # actually delete (default: dry-run)
|
||||
[--dry-run] # default true; redundant with default
|
||||
[--keep <names,csv>] # exclusion list
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Filter flags are mutually exclusive — error otherwise.
|
||||
- Default is dry-run; `--yes` flips to real delete.
|
||||
- Without `--scope`, scans **every** project bucket (intentional, repo-wide
|
||||
cleanup); with `--scope project|global`, limited to that bucket.
|
||||
- Live-worker channels are always skipped regardless of filter.
|
||||
- Output: per-candidate line `name last-ts (reason)` plus a final summary.
|
||||
|
||||
---
|
||||
|
||||
## Forum Channels
|
||||
|
||||
### `post <name> <action>`
|
||||
|
||||
```bash
|
||||
trellis channel post <name> <action>
|
||||
--as <agent> # REQUIRED
|
||||
[--scope project|global]
|
||||
[--thread <key>] # required except action=opened
|
||||
[--title <text>]
|
||||
[--text <text> | --stdin | --text-file <path>]
|
||||
[--description <text>] # stable thread description
|
||||
[--status <status>]
|
||||
[--labels a,b] # REPLACES thread labels
|
||||
[--assignees a,b] # REPLACES assignees
|
||||
[--summary <text>]
|
||||
[--context-file <abs-path>] ...
|
||||
[--context-raw <text>] ...
|
||||
[--linked-context-file <abs-path>] # [deprecated alias]
|
||||
[--linked-context-raw <text>] # [deprecated alias]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- `<action>` is free-form on the CLI surface; conventional values include
|
||||
`opened`, `comment`, `status`, `labels`, `assignees`, `summary`,
|
||||
`processed`.
|
||||
- `action=rename` is rejected — use `thread rename` instead.
|
||||
- `--labels` / `--assignees` are replace-semantics, not append.
|
||||
- Output: appended event JSON on stdout.
|
||||
|
||||
### `forum <name>`
|
||||
|
||||
```bash
|
||||
trellis channel forum <name>
|
||||
[--scope project|global]
|
||||
[--status <status>]
|
||||
[--raw]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Lists threads (reduced state). `--status` filters by current thread
|
||||
status. `--raw` prints one JSON per thread.
|
||||
|
||||
### `thread <name> <thread>` / `thread rename`
|
||||
|
||||
```bash
|
||||
trellis channel thread <name> <thread-key>
|
||||
[--scope project|global]
|
||||
[--raw]
|
||||
|
||||
trellis channel thread rename <name> <old-thread> <new-thread>
|
||||
--as <agent> # REQUIRED
|
||||
[--scope project|global]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- `thread <name> <key>` shows one thread's timeline:
|
||||
header `<thread> [<status>] <title>`, then description / labels /
|
||||
assignees / summary / timeline lines. `--raw` switches to raw events.
|
||||
- `thread rename` is the only mutation; `post --action rename` is rejected.
|
||||
|
||||
---
|
||||
|
||||
## Context / Title
|
||||
|
||||
### `context add` / `context delete` / `context list`
|
||||
|
||||
```bash
|
||||
trellis channel context add <name>
|
||||
[--as <agent>] # default: main
|
||||
[--scope project|global]
|
||||
[--thread <key>] # thread-level instead of channel-level
|
||||
[--file <abs-path>] ... # repeatable
|
||||
[--raw <text>] ... # repeatable
|
||||
# at least one of --file or --raw
|
||||
|
||||
trellis channel context delete <name>
|
||||
[--as <agent>] # default: main
|
||||
[--scope project|global]
|
||||
[--thread <key>]
|
||||
[--file <abs-path>] ...
|
||||
[--raw <text>] ...
|
||||
|
||||
trellis channel context list <name>
|
||||
[--scope project|global]
|
||||
[--thread <key>]
|
||||
[--raw] # one JSON entry per line
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- `add` / `delete` append a `context` event and print the event JSON.
|
||||
- `list` projects current context entries; pretty output is
|
||||
`file <path>` / `raw <truncated text>` lines, `(no context)` when empty.
|
||||
|
||||
### `title set <name>` / `title clear <name>`
|
||||
|
||||
```bash
|
||||
trellis channel title set <name>
|
||||
--title <text> # REQUIRED
|
||||
[--as <agent>] # default: main
|
||||
[--scope project|global]
|
||||
|
||||
trellis channel title clear <name>
|
||||
[--as <agent>] # default: main
|
||||
[--scope project|global]
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Appends a `title` event projecting a stable display title onto the
|
||||
channel. Output: event JSON.
|
||||
|
||||
---
|
||||
|
||||
## Hidden / Internal
|
||||
|
||||
| Command | Purpose |
|
||||
|---|---|
|
||||
| `channel __supervisor <channel> <worker> <config>` | Forked entry point invoked by `spawn`. Do not invoke directly. |
|
||||
| `channel __parse-trace <adapter> <file>` | Dev helper — replays a recorded stream-json / wire trace through the matching adapter and prints the resulting channel events. Adapter is validated against the provider registry. |
|
||||
|
||||
---
|
||||
|
||||
## Event Model
|
||||
|
||||
`CHANNEL_EVENT_KINDS` (whitelist enforced by `parseChannelKind`):
|
||||
|
||||
`create`, `join`, `leave`, `message`, `thread`, `context`, `channel`,
|
||||
`spawned`, `killed`, `respawned`, `progress`, `done`, `error`, `waiting`,
|
||||
`awake`, `undeliverable`, `interrupt_requested`, `turn_started`,
|
||||
`turn_finished`, `interrupted`, `supervisor_warning`.
|
||||
|
||||
`MEANINGFUL_EVENT_KINDS` (default-visible subset used by `wait` /
|
||||
`messages` when no explicit `--kind` is given):
|
||||
|
||||
`create`, `join`, `leave`, `message`, `thread`, `context`, `channel`,
|
||||
`spawned`, `killed`, `respawned`, `done`, `error`.
|
||||
|
||||
Non-meaningful kinds (e.g. `progress`, `waiting`, `awake`,
|
||||
`supervisor_warning`, the `turn_*` / `interrupt*` set) still flow through
|
||||
the store; opt in via `--kind` or `--include-progress`.
|
||||
|
||||
Forum channels are event-sourced; use the CLI reducers
|
||||
(`forum`, `thread`, `context list`) for state projection.
|
||||
|
||||
---
|
||||
|
||||
## Output Conventions
|
||||
|
||||
- **Mutations** (`send`, `interrupt`, `post`, `context add/delete`,
|
||||
`title set/clear`, `thread rename`) print the appended event as one JSON
|
||||
line on **stdout**.
|
||||
- **Streaming reads** (`wait`, `messages --follow`) print one JSON event
|
||||
per line on stdout.
|
||||
- **Pretty reads** (`list`, `messages`, `forum`, `thread`, `context list`)
|
||||
print colored, padded tables / timelines.
|
||||
- **`run`** prints only the final assistant text on stdout (so callers can
|
||||
pipe); diagnostic notes go to stderr.
|
||||
- **Errors** go through `chalk.red("Error:")` to stderr and `exit 1`.
|
||||
- **`wait` timeout** specifically exits **124**.
|
||||
|
||||
233
.pi/skills/trellis-channel/references/forum.md
Normal file
233
.pi/skills/trellis-channel/references/forum.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# Forum Channels
|
||||
|
||||
Forum channels are durable, topic-style channels. They are created with
|
||||
`--type forum` at channel-creation time and are immutable after that. They are
|
||||
not normal chat streams: the default read path is
|
||||
**forum summary -> one thread timeline -> current context**.
|
||||
|
||||
## Forum vs Regular Channel
|
||||
|
||||
A channel's type is set with `--type` on `channel create` and never changes:
|
||||
|
||||
- `chat` (default) — flat message timeline. `channel messages` always renders
|
||||
the event stream. Forum-only flags such as `--thread` and `--action` are
|
||||
rejected here.
|
||||
- `forum` — thread-oriented. `channel messages` without filters renders a
|
||||
thread-board summary instead of raw events. The `post`, `forum`, `thread`,
|
||||
and `thread rename` subcommands only apply to forum channels.
|
||||
|
||||
Both types share the same scope model (`--scope project` is the default;
|
||||
`--scope global` puts the channel in the cross-project bucket).
|
||||
|
||||
## Create A Forum Channel
|
||||
|
||||
```bash
|
||||
trellis channel create design-feedback \
|
||||
--type forum \
|
||||
--scope global \
|
||||
--description "Cross-project design feedback board." \
|
||||
--context-raw "One thread per design topic; close when resolved." \
|
||||
--by main
|
||||
```
|
||||
|
||||
Use `--scope project` for a board scoped to one repo, `--scope global` for a
|
||||
cross-project board.
|
||||
|
||||
## Threads: Open, Comment, Status, Summary
|
||||
|
||||
Threads live inside a forum channel. Each thread is identified by a stable
|
||||
`--thread <key>` (lowercase kebab-case is conventional). The first action on
|
||||
a thread is `opened`; everything afterwards uses the same `--thread` key.
|
||||
|
||||
```bash
|
||||
trellis channel post design-feedback opened \
|
||||
--scope global \
|
||||
--as main \
|
||||
--thread login-empty-state \
|
||||
--title "Empty state on the login screen" \
|
||||
--description "Track design feedback for the new login empty state." \
|
||||
--labels design,login \
|
||||
--context-raw "Spotted during the 0.4 release review." \
|
||||
--text-file /tmp/thread-open.md
|
||||
|
||||
trellis channel post design-feedback comment \
|
||||
--scope global \
|
||||
--as reviewer \
|
||||
--thread login-empty-state \
|
||||
--text-file /tmp/review.md
|
||||
|
||||
trellis channel post design-feedback status \
|
||||
--scope global \
|
||||
--as main \
|
||||
--thread login-empty-state \
|
||||
--status closed
|
||||
|
||||
trellis channel post design-feedback summary \
|
||||
--scope global \
|
||||
--as main \
|
||||
--thread login-empty-state \
|
||||
--summary "Adopted the option-B layout; ticket TRELLIS-123 owns the fix."
|
||||
```
|
||||
|
||||
Key distinctions:
|
||||
|
||||
- `--description` is the **durable** thread description (the answer to "what
|
||||
is this thread about?"). It is set on `opened` and edited by re-running
|
||||
`post` with `--description`.
|
||||
- `--text` / `--stdin` / `--text-file` is the **event body** — the comment or
|
||||
payload attached to this specific timeline entry.
|
||||
- `--labels` and `--assignees` are CSV and **replace** the current value; they
|
||||
do not append.
|
||||
- `--summary` is the rolling thread summary. Setting it on `status closed` is
|
||||
the standard way to mark a thread resolved with context.
|
||||
|
||||
`--thread` is required for every action except `opened` (where it is also
|
||||
required in practice — there is no anonymous thread).
|
||||
|
||||
## Read A Forum
|
||||
|
||||
```bash
|
||||
trellis channel messages design-feedback --scope global
|
||||
trellis channel forum design-feedback --scope global --status open
|
||||
trellis channel thread design-feedback login-empty-state --scope global
|
||||
trellis channel messages design-feedback --scope global --raw --thread login-empty-state
|
||||
```
|
||||
|
||||
If a peer says "I commented on the forum", run `channel forum` first to see
|
||||
which thread changed, then drill into that thread with `channel thread <name>
|
||||
<thread>`. Do not jump straight to ad-hoc `events.jsonl` parsing.
|
||||
|
||||
## Context
|
||||
|
||||
Context entries are durable background that should always be in scope when
|
||||
reading a channel or a thread. They are **not** timeline events; they are
|
||||
projected separately and replayed for every reader.
|
||||
|
||||
Use the `context` subcommands. The legacy `--linked-context-file` /
|
||||
`--linked-context-raw` flags on `create` and `post` are deprecated aliases
|
||||
that fold into the canonical `--context-file` / `--context-raw`.
|
||||
|
||||
### Add Context
|
||||
|
||||
```bash
|
||||
# Channel-level context (whole forum)
|
||||
trellis channel context add design-feedback \
|
||||
--scope global \
|
||||
--raw "Upstream feedback board; please link tasks before opening threads."
|
||||
|
||||
# Thread-level context (one thread)
|
||||
trellis channel context add design-feedback \
|
||||
--scope global \
|
||||
--thread login-empty-state \
|
||||
--file "$PWD/.trellis/tasks/05-13-login-redesign/design.md"
|
||||
```
|
||||
|
||||
- `--thread <key>` switches between channel-level and thread-level context.
|
||||
- `--file` paths **must be absolute**; relative paths are rejected.
|
||||
- `--raw` is plain text inline content.
|
||||
- Both flags are repeatable; at least one is required for `add` / `delete`.
|
||||
- `--as <agent>` records authorship; defaults to `main`.
|
||||
|
||||
### List Context
|
||||
|
||||
```bash
|
||||
trellis channel context list design-feedback --scope global
|
||||
trellis channel context list design-feedback --scope global --thread login-empty-state --raw
|
||||
```
|
||||
|
||||
`--raw` on `list` emits one JSON entry per line (useful for piping); without
|
||||
it you get a human-readable `file <path>` / `raw <truncated text>` listing.
|
||||
An empty store prints `(no context)`.
|
||||
|
||||
### Delete Context
|
||||
|
||||
```bash
|
||||
trellis channel context delete design-feedback \
|
||||
--scope global \
|
||||
--thread login-empty-state \
|
||||
--raw "stale note"
|
||||
```
|
||||
|
||||
You delete by **value**, not by id: pass the same `--file` or `--raw` value
|
||||
that was added. Repeat the flag to delete multiple entries in one call.
|
||||
|
||||
### Reading Order
|
||||
|
||||
When reading a thread, work top-down:
|
||||
|
||||
1. Thread `description` (the durable "what is this about").
|
||||
2. Context entries (channel-level + thread-level).
|
||||
3. Timeline (`opened`, `comment`, `status`, `summary`).
|
||||
|
||||
If a context file is missing or unreadable, state that explicitly and
|
||||
continue with the remaining data — do not fabricate the content.
|
||||
|
||||
## Title Projection
|
||||
|
||||
`title` projects a stable display title onto the channel without renaming the
|
||||
storage address. The channel `name` you pass to every command stays the same.
|
||||
|
||||
```bash
|
||||
trellis channel title set design-feedback \
|
||||
--scope global \
|
||||
--title "Design feedback board"
|
||||
|
||||
trellis channel title clear design-feedback --scope global
|
||||
```
|
||||
|
||||
- `title set` requires `--title`.
|
||||
- `--as <agent>` records authorship; defaults to `main`.
|
||||
- This is a presentation-layer change. Tooling and scripts keep using the
|
||||
original channel name.
|
||||
|
||||
## Thread Rename
|
||||
|
||||
`thread rename` is the correction path when a thread was opened with the
|
||||
wrong key (typo, wrong slug convention, etc.). Threads do not support hard
|
||||
deletion — rename is the supported corrective action.
|
||||
|
||||
```bash
|
||||
trellis channel thread rename design-feedback old-key new-key \
|
||||
--scope global \
|
||||
--as main
|
||||
```
|
||||
|
||||
- `--as <agent>` is **required**.
|
||||
- `post <name> rename` is rejected — you must use `thread rename`.
|
||||
|
||||
## Deletion Discipline
|
||||
|
||||
Do not model single-comment deletion or hard thread deletion as normal
|
||||
workflow. Forum threads are append-only collaboration history. To correct
|
||||
state, use:
|
||||
|
||||
- `post ... status` to mark a thread closed / blocked / etc.
|
||||
- `post ... summary` to record the resolution.
|
||||
- `post ... --labels` to re-label (replaces the set).
|
||||
- `thread rename` to correct a bad thread key.
|
||||
|
||||
## Internal Changelog Pattern
|
||||
|
||||
A common use of a global forum channel is an internal release / runtime
|
||||
changelog. One thread per notable change keeps history searchable:
|
||||
|
||||
```bash
|
||||
trellis channel create release-notes \
|
||||
--type forum \
|
||||
--scope global \
|
||||
--description "Internal release and runtime changelog." \
|
||||
--context-raw "One thread per notable change; close when shipped." \
|
||||
--by main
|
||||
|
||||
trellis channel post release-notes opened \
|
||||
--scope global \
|
||||
--as main \
|
||||
--thread release-2026-q1 \
|
||||
--title "Channel threads and forum UX in 0.6" \
|
||||
--description "Forum channel UX shipped in the 0.6 line." \
|
||||
--labels channel,release \
|
||||
--text-file /tmp/release-notes.md
|
||||
```
|
||||
|
||||
Use stable, descriptive thread keys (e.g. `release-2026-q1`,
|
||||
`runtime-event-schema-change`) so later readers can find them by name.
|
||||
226
.pi/skills/trellis-channel/references/progress-debugging.md
Normal file
226
.pi/skills/trellis-channel/references/progress-debugging.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Progress And Debugging
|
||||
|
||||
Pretty output is for operators. Raw output is the audit log. Subcommands
|
||||
(`forum`, `thread`, `messages`, `context`) are the audit *interface* — reach
|
||||
for them before grepping `events.jsonl` by hand.
|
||||
|
||||
## Pretty vs `--raw`
|
||||
|
||||
`trellis channel messages <channel>` renders a compact, human-readable view:
|
||||
timestamps, identities, kind, and a short body. It is meant for operators
|
||||
scanning a channel, not for diagnostics.
|
||||
|
||||
Pretty output can and will truncate:
|
||||
|
||||
- long progress deltas (`text_delta`, partial tool args)
|
||||
- tool names and command lines
|
||||
- multi-line status fields and structured `detail` blobs
|
||||
- forum thread titles past the column budget
|
||||
|
||||
When something looks "off" — a worker appears stuck, a progress line ends
|
||||
mid-word, an action field shows `...` — switch to `--raw`. Raw mode emits
|
||||
one JSON event per line exactly as it lives in `events.jsonl`, so nothing
|
||||
is dropped.
|
||||
|
||||
```bash
|
||||
# Pretty (operator view)
|
||||
trellis channel messages <channel> --kind done --last 10
|
||||
trellis channel messages <channel> --kind error --last 10
|
||||
|
||||
# Raw (diagnostic view) — one JSON per line
|
||||
trellis channel messages <channel> --raw --kind progress --last 20
|
||||
trellis channel messages <channel> --raw --last 50
|
||||
```
|
||||
|
||||
Rule of thumb: never diagnose a worker from a truncated progress line.
|
||||
|
||||
### Rebuild Streaming Text
|
||||
|
||||
To reconstruct what a model actually streamed during a turn, concatenate
|
||||
`detail.text_delta` from progress events:
|
||||
|
||||
```bash
|
||||
trellis channel messages <channel> --raw --kind progress --last 80 \
|
||||
| python3 -c 'import json,sys; [print((json.loads(l).get("detail") or {}).get("text_delta",""), end="") for l in sys.stdin if l.strip()]'
|
||||
```
|
||||
|
||||
## Stalled Worker Diagnosis
|
||||
|
||||
Symptom: `trellis channel list` shows the worker as running, but no new
|
||||
events appear in `messages` and `wait` keeps timing out.
|
||||
|
||||
Triage order:
|
||||
|
||||
1. **Locate the channel files.** Use `list --all --all-projects` if you are
|
||||
not sure which bucket the channel lives in.
|
||||
|
||||
```bash
|
||||
trellis channel list --all --all-projects
|
||||
CHAN=~/.trellis/channels/<bucket>/<channel>
|
||||
```
|
||||
|
||||
2. **Confirm the supervisor and worker PIDs are alive.**
|
||||
|
||||
```bash
|
||||
cat "$CHAN/<worker>.pid" # supervisor PID
|
||||
cat "$CHAN/<worker>.worker-pid" # actual CLI subprocess PID
|
||||
ps -p "$(cat "$CHAN/<worker>.pid")"
|
||||
ps -p "$(cat "$CHAN/<worker>.worker-pid")"
|
||||
```
|
||||
|
||||
If the supervisor PID is gone but the channel still lists the worker,
|
||||
you have a ghost entry — clean it with
|
||||
`trellis channel kill <name> --as <worker> --force`.
|
||||
|
||||
3. **Tail the worker log.** This is the canonical place to see provider /
|
||||
MCP / tool startup output that never makes it onto the channel.
|
||||
|
||||
```bash
|
||||
tail -f "$CHAN/<worker>.log"
|
||||
```
|
||||
|
||||
4. **Check the last raw events.** A worker that emitted `progress` but no
|
||||
`message`/`done` is usually mid-stream or blocked on a tool call:
|
||||
|
||||
```bash
|
||||
trellis channel messages <channel> --raw --last 50
|
||||
```
|
||||
|
||||
Common "alive but silent" causes:
|
||||
|
||||
- Provider cold start before the first token (long, but eventually moves).
|
||||
- A blocking MCP server during startup — visible in the worker log.
|
||||
- Worker is waiting for a tool result whose subprocess hung.
|
||||
- Prompt is huge / model is rate-limited; check provider-side errors in the
|
||||
worker log.
|
||||
|
||||
## Progress Event Interpretation
|
||||
|
||||
A `progress` event represents an in-flight piece of work. Its shape varies
|
||||
by `action` field, but the load-bearing fields are always under `detail`:
|
||||
|
||||
- `detail.text_delta` — incremental model output (concatenate across events
|
||||
to rebuild the streamed reply).
|
||||
- `detail.tool_name`, `detail.tool_input` — tool call about to run or
|
||||
currently running.
|
||||
- `detail.status` — short string used by long-running actions
|
||||
(`starting`, `running`, `flushing`, `done`).
|
||||
- `detail.action` — semantic label (e.g. `status` for thread heartbeats).
|
||||
|
||||
Progress events are **noisy** by design. `wait` ignores them unless you
|
||||
pass `--include-progress`. When you do want to see them, prefer:
|
||||
|
||||
```bash
|
||||
trellis channel messages <channel> --raw --kind progress --last 80
|
||||
```
|
||||
|
||||
A stream that emits progress at a steady cadence but never closes with
|
||||
`done`/`error`/`message` is the classic shape of a hung tool call —
|
||||
inspect the worker log for the subprocess.
|
||||
|
||||
## Wait Semantics (Quick Reference)
|
||||
|
||||
`channel wait` watches `events.jsonl` from EOF and wakes on:
|
||||
|
||||
- `message`
|
||||
- `done`
|
||||
- `error`
|
||||
- `killed`
|
||||
- `progress` only with `--include-progress`
|
||||
|
||||
Useful filters:
|
||||
|
||||
```bash
|
||||
trellis channel wait T --as main --from check --kind done --timeout 15m
|
||||
trellis channel wait T --as main --from check,check-cx --kind done --all --timeout 15m
|
||||
trellis channel wait T --as worker --tag interrupt --timeout 1h
|
||||
trellis channel wait T --as main --thread release-note --action status --timeout 10m
|
||||
```
|
||||
|
||||
Exit codes: `0` matched, `124` timeout, `1`/`2` errors. On `wait --all`
|
||||
timeout, stderr names the workers still missing.
|
||||
|
||||
## Auditing `events.jsonl` — Use Subcommands, Not `grep`
|
||||
|
||||
Every channel persists its full history at `$CHAN/events.jsonl`. It is
|
||||
tempting to `tail` / `grep` / `jq` this file directly during debugging.
|
||||
Don't make it a habit, and **never** do it for forum channels.
|
||||
|
||||
Why subcommands first:
|
||||
|
||||
- `messages` already replays the file with filters (`--kind`, `--from`,
|
||||
`--last`, `--tag`, `--thread`, `--action`) and gives you `--raw` for the
|
||||
exact JSON. Anything you would write a one-liner for, `messages` already
|
||||
does.
|
||||
- `wait` consumes the same file with EOF semantics — re-implementing that
|
||||
with `tail -f | jq` will drop events under load and misorder them under
|
||||
rotation.
|
||||
- `context` materializes a worker's inbox view, including cursor state.
|
||||
Hand-rolled filters do not respect `<worker>.inbox-cursor`.
|
||||
|
||||
### Forum channels: never parse `events.jsonl` directly
|
||||
|
||||
Forum channels multiplex many logical threads onto a single `events.jsonl`.
|
||||
Each event carries `thread`, `action`, and tag fields that the forum
|
||||
subcommands know how to fold together. Parsing the file by hand will:
|
||||
|
||||
- Mix threads together and make a thread look incoherent.
|
||||
- Miss thread lifecycle events (open / status / close) that change how
|
||||
later events should be interpreted.
|
||||
- Ignore worker inbox cursors, so you will "see" events a worker has
|
||||
already consumed and assume they are pending.
|
||||
|
||||
Use the forum-aware views instead:
|
||||
|
||||
```bash
|
||||
# List logical threads inside the forum channel
|
||||
trellis channel forum list <channel>
|
||||
|
||||
# Inspect one thread end-to-end
|
||||
trellis channel thread show <channel> <thread>
|
||||
|
||||
# Replay messages for a thread (supports --raw, --kind, --last)
|
||||
trellis channel messages <channel> --thread <thread> --raw --last 100
|
||||
|
||||
# What a specific worker still has pending
|
||||
trellis channel context <channel> --as <worker>
|
||||
```
|
||||
|
||||
Direct reads of `events.jsonl` are reserved for the case where the CLI
|
||||
itself is suspect — e.g. confirming an event was actually persisted, or
|
||||
diffing against `<worker>.inbox-cursor` while debugging the supervisor.
|
||||
|
||||
## Common Failures
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|---|---|---|
|
||||
| `trellis: command not found` | CLI not installed globally | `npm install -g @mindfoldhq/trellis` |
|
||||
| `wait` exits immediately | wrong filter or identity collision | use distinct `--as`, inspect raw messages |
|
||||
| zsh errors on message text | shell interpreted punctuation | use `--stdin` or `--text-file` |
|
||||
| progress line is cut off | pretty output truncation | use `messages --raw --kind progress` |
|
||||
| worker never speaks | provider startup / prompt / MCP delay | inspect `<worker>.log`, `ps`, raw events |
|
||||
| channel not found in another cwd | project bucket mismatch | `cd` to project, use `--scope global`, or `list --all-projects` |
|
||||
| ghost worker in list | supervisor died without cleanup | `trellis channel kill <name> --as <worker> --force` |
|
||||
| forum thread looks scrambled | parsed `events.jsonl` directly | use `forum`, `thread`, `messages --thread` |
|
||||
|
||||
## Storage Layout
|
||||
|
||||
```text
|
||||
~/.trellis/channels/
|
||||
└── <bucket>/
|
||||
└── <channel-name>/
|
||||
├── events.jsonl
|
||||
├── <channel>.lock
|
||||
├── <worker>.log
|
||||
├── <worker>.pid
|
||||
├── <worker>.worker-pid
|
||||
├── <worker>.config
|
||||
├── <worker>.session-id
|
||||
├── <worker>.thread-id
|
||||
├── <worker>.inbox-cursor
|
||||
└── <worker>.spawnlock
|
||||
```
|
||||
|
||||
Agents normally use the CLI, not direct file reads. Direct file reads are
|
||||
for debugging when CLI views are insufficient — and even then, never on a
|
||||
forum channel's `events.jsonl`.
|
||||
276
.pi/skills/trellis-channel/references/workers.md
Normal file
276
.pi/skills/trellis-channel/references/workers.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Workers And Agent Cards
|
||||
|
||||
Use workers when a peer agent should execute independently and report back
|
||||
through the channel event log. A worker is a registered child process (claude
|
||||
or codex) attached to a channel; the supervisor forwards inbox messages to it
|
||||
and translates its output back into channel events.
|
||||
|
||||
## Spawn
|
||||
|
||||
```bash
|
||||
trellis channel create impl-task --by dispatcher --cwd /path/to/repo
|
||||
trellis channel spawn impl-task --provider codex --as codex-impl --timeout 30m
|
||||
|
||||
echo "Implement the schema for table X per .trellis/.../prd.md" \
|
||||
| trellis channel send impl-task --as dispatcher --to codex-impl --stdin
|
||||
|
||||
trellis channel wait impl-task --as dispatcher --from codex-impl --kind done --timeout 30m
|
||||
```
|
||||
|
||||
`spawn` forks a `channel __supervisor` worker that emits `spawned`, streams
|
||||
`progress`, and should end with `done`, `error`, or `killed`. Workers stay
|
||||
inbox-idle until a `send --to <worker>` (or a broadcast when
|
||||
`--inbox-policy broadcastAndExplicit` is set) wakes them.
|
||||
|
||||
Key `spawn` flags:
|
||||
|
||||
- `--agent <name>` — load `.trellis/agents/<name>.md` (provider/model/as/system prompt defaults).
|
||||
- `--provider <claude|codex>` — overrides the agent card; validated against the adapter registry.
|
||||
- `--as <name>` — channel worker handle; defaults to the agent name.
|
||||
- `--cwd <path>` — worker working directory (also the jail root for `--file`/`--jsonl`).
|
||||
- `--model <id>` — model override.
|
||||
- `--resume <id>` — resume an existing claude session / codex thread.
|
||||
- `--timeout <duration>` — auto-kill after `30s` / `2m` / `1h`.
|
||||
- `--warn-before <duration>` — supervisor_warning lead time (default `5m`; `0ms` disables).
|
||||
- `--file <path>` (repeatable, glob-supported) — inject file content into the system prompt.
|
||||
- `--jsonl <path>` (repeatable) — Trellis jsonl manifest (`{file, reason}` per line).
|
||||
- `--by <agent>` — author of the `spawned` event (defaults to `$TRELLIS_CHANNEL_AS` or `main`).
|
||||
- `--inbox-policy <explicitOnly|broadcastAndExplicit>` — default `explicitOnly`.
|
||||
- `--idle-timeout <duration>` — OOM guard idle TTL (default `5m`; `0` disables).
|
||||
- `--max-live-workers <n>` — spawn-time live-worker budget (default `6`; `0` disables).
|
||||
|
||||
The success event `spawned` records `pid`, `provider`, `agent`, the injected
|
||||
`files`, and the resolved `manifests` so later spectators can audit context.
|
||||
|
||||
## Agent Cards
|
||||
|
||||
`--agent <name>` resolves to `.trellis/agents/<name>.md`. The card name must
|
||||
match `[A-Za-z0-9._-]+`. The default Trellis install ships two cards:
|
||||
|
||||
- `.trellis/agents/check.md` — code-quality reviewer.
|
||||
- `.trellis/agents/implement.md` — coding worker for implementation runs.
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: check
|
||||
description: Code quality check expert.
|
||||
provider: claude
|
||||
---
|
||||
```
|
||||
|
||||
Frontmatter fields populate `spawn` defaults (provider, model, `as`); the
|
||||
markdown body becomes the worker's system-prompt role. Cards do **not**
|
||||
auto-attach task files — context must be injected explicitly per spawn (see
|
||||
below).
|
||||
|
||||
Always inspect project cards before spawning a named agent:
|
||||
|
||||
```bash
|
||||
ls .trellis/agents
|
||||
sed -n '1,100p' .trellis/agents/check.md
|
||||
```
|
||||
|
||||
## Context Injection
|
||||
|
||||
Two flags inject content into the worker's system prompt under a
|
||||
`# CONTEXT FILES` block, assembled by `context-loader`:
|
||||
|
||||
- `--file <path>` — repeatable, glob-supported (`*`, `**`). Each match is
|
||||
read and concatenated.
|
||||
- `--jsonl <path>` — repeatable Trellis manifest where every line is
|
||||
`{"file":"<path>","reason":"<why>"}`. The reason is preserved as a header
|
||||
comment above each file's content.
|
||||
|
||||
Limits enforced by the loader:
|
||||
|
||||
- 1 MB hard cap per file (oversize → error).
|
||||
- 200 KB per-file warning to stderr.
|
||||
- 500 KB total assembled-context warning to stderr.
|
||||
- Path-traversal jail: all resolved paths must stay under `--cwd`.
|
||||
|
||||
Example spawning a check agent against a task directory:
|
||||
|
||||
```bash
|
||||
TASK=.trellis/tasks/05-13-example
|
||||
trellis channel spawn cr-example --agent check --provider codex --as check-cx \
|
||||
--file "$TASK/prd.md" \
|
||||
--file "$TASK/design.md" \
|
||||
--file "$TASK/implement.md" \
|
||||
--jsonl "$TASK/check.jsonl" \
|
||||
--cwd "$PWD" --timeout 30m
|
||||
```
|
||||
|
||||
The `spawned` event records both the literal `files` array and any `manifests`
|
||||
expanded from `--jsonl`, so the audit trail captures whatever the worker was
|
||||
actually shown.
|
||||
|
||||
## Names And Routing
|
||||
|
||||
`--as` has two meanings:
|
||||
|
||||
- `send` / `wait` / `interrupt`: speaker identity (author of the resulting event).
|
||||
- `spawn`: the worker handle that other agents address with `--to`.
|
||||
|
||||
Use explicit names when multiple workers or providers participate in one
|
||||
channel:
|
||||
|
||||
```bash
|
||||
trellis channel spawn cr-feature --agent check --as check-claude
|
||||
trellis channel spawn cr-feature --agent check --provider codex --as check-cx
|
||||
|
||||
trellis channel wait cr-feature --as main \
|
||||
--from check-claude,check-cx --kind done --all --timeout 15m
|
||||
```
|
||||
|
||||
`--all` requires `--from` and blocks until every listed worker has produced a
|
||||
matching event; timeout exits with code **124** and prints
|
||||
`timeout: still waiting on ...` to stderr.
|
||||
|
||||
## Soft Interrupt — `interrupt`
|
||||
|
||||
`channel interrupt` is the cooperative redirect: it appends an `interrupt`
|
||||
event (reason `"user"`) and, where the adapter supports it, issues a
|
||||
provider-level turn interrupt with a replacement instruction. Use it when the
|
||||
worker should drop its current turn and act on new input immediately, without
|
||||
losing its session.
|
||||
|
||||
```bash
|
||||
echo "Stop refactoring the parser — switch to fixing the failing test in src/foo.ts" \
|
||||
| trellis channel interrupt impl-task --as dispatcher --to codex-impl --stdin
|
||||
```
|
||||
|
||||
Flags:
|
||||
|
||||
- `--as <agent>` **(required)** — caller identity.
|
||||
- `--to <agent>` **(required)** — target worker.
|
||||
- `--scope <project|global>` — channel scope.
|
||||
- `--stdin` / `--text-file <path>` / `[text]` — replacement instruction body.
|
||||
|
||||
The appended event has `kind: "interrupt"` — downstream `wait` / `messages`
|
||||
filters can subscribe with `--kind interrupt` to react to redirections (e.g.
|
||||
to log the rerouting, or to gate other workers behind a coordinator's
|
||||
correction).
|
||||
|
||||
For low-priority hints that should wait for the worker's next turn, send a
|
||||
plain tagged message instead:
|
||||
|
||||
```bash
|
||||
echo "Check this when you reach the next turn." \
|
||||
| trellis channel send impl-task --as dispatcher --to codex-impl \
|
||||
--stdin --tag question
|
||||
```
|
||||
|
||||
## Hard Interrupt — `kill` + `--resume`
|
||||
|
||||
Use `kill` when the worker must stop **now** (e.g. runaway loop, bad
|
||||
instructions already in flight, or `interrupt` is not honored by the
|
||||
adapter). The supervisor escalates SIGTERM → 8 s grace → SIGKILL; the CLI
|
||||
writes a `killed` event when SIGKILL is needed so the event log stays
|
||||
truthful.
|
||||
|
||||
```bash
|
||||
trellis channel kill impl-task --as codex-impl
|
||||
trellis channel spawn impl-task --as codex-impl --provider codex \
|
||||
--resume "$(cat ~/.trellis/channels/<bucket>/impl-task/worker.session-id)"
|
||||
|
||||
echo "STOP — new instructions: ..." \
|
||||
| trellis channel send impl-task --as dispatcher --to codex-impl --stdin
|
||||
```
|
||||
|
||||
`kill` flags:
|
||||
|
||||
- `--as <agent>` **(required)** — names the worker (positional `<name>` is the channel).
|
||||
- `--scope <project|global>`.
|
||||
- `--force` — SIGKILL immediately (also kills the inner worker pid).
|
||||
|
||||
Side effects: cleans `pid`, `worker-pid`, `config`, `spawnlock` sidecar
|
||||
files; keeps `log`, `session-id`, `thread-id` for forensics and resume.
|
||||
|
||||
When `interrupt` will not converge, kill + `--resume` is the guaranteed
|
||||
redirection path.
|
||||
|
||||
## Worker OOM Guard
|
||||
|
||||
The OOM guard prevents orphaned/idle workers from accumulating and exhausting
|
||||
host resources. It runs at every `spawn` and enforces two policies per
|
||||
project bucket:
|
||||
|
||||
- **Idle TTL** — sweep workers whose last activity is older than the
|
||||
configured threshold (default `5m`; `0` disables).
|
||||
- **Live-worker budget** — refuse the new spawn if more than N workers are
|
||||
already alive in the same project bucket (default `6`; `0` disables).
|
||||
|
||||
Precedence (highest first):
|
||||
|
||||
1. CLI flags: `--idle-timeout`, `--max-live-workers` on `spawn`.
|
||||
2. Environment variables: `TRELLIS_CHANNEL_WORKER_IDLE_TIMEOUT`,
|
||||
`TRELLIS_CHANNEL_MAX_LIVE_WORKERS`.
|
||||
3. `.trellis/config.yaml` under `channel.worker_guard`.
|
||||
4. Built-in defaults (`5m`, `6`).
|
||||
|
||||
Cleanup notices are written to stderr at spawn time so operators can see which
|
||||
idle workers were swept and why a new spawn was rejected. The guard does not
|
||||
touch ephemeral / `channel run` workers any differently — they are subject to
|
||||
the same idle TTL and budget.
|
||||
|
||||
To audit current state, list workers via `channel list` (the `WORKERS`
|
||||
column) and inspect per-channel `pid` / `worker-pid` sidecar files under
|
||||
`~/.trellis/channels/<bucket>/<channel>/`.
|
||||
|
||||
## Worker Inbox APIs
|
||||
|
||||
The inbox is the channel surface workers wake on. Routing is controlled by
|
||||
two knobs:
|
||||
|
||||
- **Inbox policy** (`spawn --inbox-policy`):
|
||||
- `explicitOnly` (default) — worker only wakes on `send --to <worker>` or
|
||||
`interrupt --to <worker>`.
|
||||
- `broadcastAndExplicit` — also wakes on broadcasts (`send` with no `--to`).
|
||||
- **Delivery mode** (`send --delivery-mode`):
|
||||
- `appendOnly` — append the event regardless of worker state.
|
||||
- `requireKnownWorker` — fail if no worker named in `--to` was ever spawned.
|
||||
- `requireRunningWorker` — fail if the named worker is not currently alive.
|
||||
|
||||
Stricter delivery modes prevent silent message loss when callers expect a
|
||||
running peer.
|
||||
|
||||
Inbox-relevant subcommands:
|
||||
|
||||
- `send <channel> [text]` — append a `message` event.
|
||||
- `--as <agent>` **(required)** — author.
|
||||
- `--to <agents>` — CSV; one → string, many → array; broadcast if omitted.
|
||||
- `--stdin` / `--text-file <path>` / `[text]` — body source.
|
||||
- `--delivery-mode <appendOnly|requireKnownWorker|requireRunningWorker>`.
|
||||
- `interrupt <channel> [text]` — soft-interrupt redirect (see above).
|
||||
- `wait <channel>` — block until matching events arrive.
|
||||
- `--as <agent>` **(required)** — `self` for filter context.
|
||||
- `--from <agents>` — CSV authors.
|
||||
- `--kind <kind[,kind...]>` — CSV (OR semantics); supports `interrupt`,
|
||||
`done`, `progress`, etc.
|
||||
- `--to <target>` — defaults to own agent (broadcast + explicit-to-me).
|
||||
- `--include-progress` — also wake on progress events.
|
||||
- `--all` — require every `--from` agent to match (timeout → exit **124**).
|
||||
- `--timeout <duration>` — `30s` / `2m` / `1h` / `1000ms`.
|
||||
- `messages <channel>` — view / filter / follow the event stream.
|
||||
- `--follow` to tail, `--kind` / `--from` / `--to` to filter, `--raw` for
|
||||
JSON-per-line, `--no-progress` to hide progress noise.
|
||||
|
||||
A typical dispatcher loop:
|
||||
|
||||
```bash
|
||||
# 1. Wake the worker.
|
||||
echo "Run the failing test and report." \
|
||||
| trellis channel send impl-task --as dispatcher --to codex-impl --stdin \
|
||||
--delivery-mode requireRunningWorker
|
||||
|
||||
# 2. Block until it finishes.
|
||||
trellis channel wait impl-task --as dispatcher \
|
||||
--from codex-impl --kind done,error --timeout 30m
|
||||
|
||||
# 3. Read the final answer.
|
||||
trellis channel messages impl-task --from codex-impl --last 1 --raw
|
||||
```
|
||||
|
||||
All event-emitting subcommands (`send`, `interrupt`, `post`, `context add` /
|
||||
`delete`, `title set` / `clear`, `thread rename`) print the appended event as
|
||||
a single JSON line on stdout, making the inbox layer easy to script against.
|
||||
128
.pi/skills/trellis-channel/references/workflows.md
Normal file
128
.pi/skills/trellis-channel/references/workflows.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Workflows
|
||||
|
||||
Use these patterns by intent. Prefer durable channels for multi-round work and
|
||||
`channel run` for one-shot questions.
|
||||
|
||||
## Pattern A: Multi-round Brainstorm
|
||||
|
||||
Use when the user says "和 codex/claude 讨论一下", "brainstorm", or "拉一个 agent
|
||||
进来一起看".
|
||||
|
||||
```bash
|
||||
trellis channel create brainstorm-storage-layer --by main \
|
||||
--task .trellis/tasks/05-XX-storage-adapter
|
||||
|
||||
trellis channel spawn brainstorm-storage-layer \
|
||||
--agent architect --provider codex \
|
||||
--file .trellis/tasks/05-XX-storage-adapter/prd.md \
|
||||
--file .trellis/tasks/05-XX-storage-adapter/design.md \
|
||||
--as cx-arch --timeout 30m
|
||||
|
||||
trellis channel send brainstorm-storage-layer \
|
||||
--as main --to cx-arch --text-file /tmp/brainstorm-r1.md
|
||||
|
||||
trellis channel wait brainstorm-storage-layer \
|
||||
--as main --kind done --from cx-arch --timeout 10m
|
||||
```
|
||||
|
||||
Do not stop after one answer. Read the answer, identify vague areas, send a
|
||||
new probe, and repeat until the result is executable.
|
||||
|
||||
Minimum round structure:
|
||||
|
||||
1. Direction split: should this live in an existing mechanism or a new one?
|
||||
2. MVP boundary: v1, v2, and what would force v2 back into v1.
|
||||
3. Data contract: events, schema, metadata, state source of truth, compatibility.
|
||||
4. CLI / UX contract: command names, flags, errors, defaults, ambiguity.
|
||||
5. Cross-layer risk and tests: shared helpers, drift points, release-blocking tests.
|
||||
|
||||
Optional rounds:
|
||||
|
||||
- Operations: logs, debugging, stuck workers, kill/restart, recovery.
|
||||
- Migration/release: breaking status, manifest, changelog, docs-site.
|
||||
- Opposition review: ask the peer agent to argue against the current plan.
|
||||
|
||||
Every probe should request concrete file paths, commands, schema, rejected
|
||||
alternatives, and release-blocking issues. Reject hedging when a decision is
|
||||
needed.
|
||||
|
||||
## Pattern B: Implement / Check Agent
|
||||
|
||||
Use when the user asks to dispatch implementation or review work.
|
||||
|
||||
```bash
|
||||
TASK=.trellis/tasks/05-12-foo
|
||||
trellis channel create cr-foo --task "$TASK" --by main
|
||||
|
||||
trellis channel spawn cr-foo \
|
||||
--agent check \
|
||||
--jsonl "$TASK/check.jsonl" \
|
||||
--file "$TASK/prd.md" \
|
||||
--file "$TASK/design.md" \
|
||||
--file "$TASK/implement.md" \
|
||||
--cwd "$PWD" --timeout 15m
|
||||
|
||||
trellis channel send cr-foo --as main --to check --text-file /tmp/cr-brief.md
|
||||
trellis channel wait cr-foo --as main --kind done --from check --timeout 15m
|
||||
trellis channel messages cr-foo --kind message --from check --tag final_answer
|
||||
```
|
||||
|
||||
For implement work, use `--agent implement` and send an implementation brief.
|
||||
For check work, include the exact diff scope, relevant specs, and validation
|
||||
already run.
|
||||
|
||||
## Pattern C: Parallel Reviewers
|
||||
|
||||
Use one channel and distinct worker names.
|
||||
|
||||
```bash
|
||||
trellis channel create cr-feature --by main --ephemeral
|
||||
|
||||
trellis channel spawn cr-feature --agent check \
|
||||
--jsonl "$TASK/check.jsonl" --file "$TASK/prd.md" --file "$TASK/design.md" \
|
||||
--timeout 15m
|
||||
|
||||
trellis channel spawn cr-feature --agent check --provider codex --as check-cx \
|
||||
--jsonl "$TASK/check.jsonl" --file "$TASK/prd.md" --file "$TASK/design.md" \
|
||||
--timeout 15m
|
||||
|
||||
trellis channel send cr-feature --as main --to check --text-file /tmp/cr-brief.md
|
||||
trellis channel send cr-feature --as main --to check-cx --text-file /tmp/cr-brief.md
|
||||
trellis channel wait cr-feature --as main --kind done --from check,check-cx --all --timeout 15m
|
||||
```
|
||||
|
||||
`--all` means every listed worker must emit a matching event.
|
||||
|
||||
## Pattern D: One-shot Worker
|
||||
|
||||
```bash
|
||||
trellis channel run --provider codex --message "say hi in 3 words" --timeout 1m
|
||||
trellis channel run --agent plan --message-file /tmp/plan-question.md --timeout 10m
|
||||
```
|
||||
|
||||
On success, `run` removes the ephemeral channel. On error/timeout/killed, it
|
||||
keeps the channel and prints the path for inspection.
|
||||
|
||||
## Pattern E: Forum Channel
|
||||
|
||||
Use for issue forums, topic-style feedback, release todos, agent findings, and
|
||||
internal changelogs. Read `forum.md` for the full model.
|
||||
|
||||
## Pattern F: Take Over Existing Thread
|
||||
|
||||
If the user gives a forum/thread name, restore context yourself:
|
||||
|
||||
```bash
|
||||
trellis channel forum <board> --scope global
|
||||
trellis channel thread <board> <thread> --scope global --raw
|
||||
trellis channel context list <board> --scope global --thread <thread>
|
||||
trellis channel messages <board> --scope global --raw --thread <thread>
|
||||
```
|
||||
|
||||
Output a constraint summary, not a transcript dump:
|
||||
|
||||
- user-level problem
|
||||
- context files that affect this repo
|
||||
- current-version versus future-version requirements
|
||||
- whether current code/design satisfies it
|
||||
- next action or comment to append
|
||||
Reference in New Issue
Block a user