Installs into .claude/skills of the current project.
Are you the author of Yaco Agent?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/imoonkey-yaco-agent)
---
name: yaco-agent
description: Orchestrate the YACO agent lifecycle (Claude Code, Codex) through the yaco agent CLI. Start, send, wait, list, inspect, and link agent sessions.
metadata:
yaco-dependent: "true"
---
# yaco-agent — Agent Lifecycle Orchestration
Operation manual for `yaco agent`, the lifecycle driver for coding-agent
sessions (Claude Code, Codex). The runtime is tmux-backed, but you operate it
through `yaco agent`, never through raw `tmux` commands.
## CLI contract for skill automation
Text is the default surface for reads and inspection. `agent list`, `status`,
`whoami`, `capture`, and the `--wait` family print human/pipe-friendly text
straight to stdout — no `--json`, no `jq`. Pass `--json` when you need to parse
returned fields programmatically or branch on the `{ok,data}` / `{ok,error}`
discriminator; mutations (`start`, `send`, `rename`, `kill`, and task
`attach`/`detach`) carry it so you can check success.
## Session model
- **Handle = tmux session name**, used directly with no suffix. Default handles
are `<index>-<provider>`; an explicit `--name <handle>` is used as-is.
- **State files** live in `${YACO_HOME:-~/.yaco}/sessions/<handle>.json` — a
global registry. Commands filter by `sessionPath` to scope to a project, so
run follow-up `yaco agent` commands from the same project root, or store the
handle returned by `start` and reuse it.
- **`status`** of a session is one of `starting`, `idle`, `processing`, or
`not found`, tracked via agent hooks (primary) with a capture-pane regex
fallback.
- **`sessionId`** is the agent's conversation UUID, usable with `claude
--resume` / `codex resume`. A Codex empty-start session reports
`"pending:awaiting-first-prompt"` for `sessionId` until its first message is
sent.
## Lifecycle commands
```bash
# Start a session (providers: claude, codex)
yaco agent start <provider> "prompt" --name <handle> --json
# Start and block until the agent finishes its first turn (prints the reply raw)
yaco agent start <provider> "prompt" --name <handle> --wait
# Resume a previous conversation by its sessionId
yaco agent start claude --resume <session-id> --name <handle> --json
yaco agent start codex --resume <session-id> --name <handle> --json
# Send a follow-up turn to a running session
yaco agent send <handle> "message" --json
# Send and block until the agent finishes that turn (prints the reply raw)
yaco agent send <handle> "message" --wait
# Wait for the completion of a freshly started, non-resumed session
yaco agent wait <handle> --from-start
# Rename a session handle
yaco agent rename <old-handle> <new-handle> --json
# Resolve the current process to its own YACO session handle
yaco agent whoami
# Tear down a session
yaco agent kill <handle> --json
```
`--resume <id>` resumes a conversation: Claude receives `--resume` as a flag;
Codex is rewritten to the `codex resume <id>` subcommand. The state file records
`sessionId` immediately.
`whoami` resolves via `TMUX_PANE` first, then known provider session-id
environment such as `CODEX_THREAD_ID` or `CLAUDE_CODE_SESSION_ID`, then process
ancestry.
## Waiting for completion
A completion wait returns the provider's **structured final message**, parsed
from the provider's own session log — not pane text. In text mode the agent's
final answer (`text`) prints raw to stdout, pipe-friendly with no prefix. With
`--json` the successful payload is the small provider-neutral shape:
```ts
{ handle, provider, outcome: "final" | "question", text }
```
- `outcome: "final"` is the only completed-turn result; `text` is the agent's
final answer.
- `outcome: "question"` means the agent yielded for user input mid-turn; `text`
is the question prompt and the turn is not done.
- Timeout, missing log, dead session without a final flush, malformed cursor,
and unsupported provider come back as `{ok:false, error}` envelopes.
Pick the form by situation:
- **Fresh, non-resumed worker started non-blocking** (e.g. parallel fanout):
start without `--wait`, then `yaco agent wait <handle> --from-start`.
- **Interactive or sequential one-shot start**:
`yaco agent start <provider> "prompt" --name <handle> --wait`.
- **Follow-up turn**:
`yaco agent send <handle> "message" --wait`.
`start --wait` and `send --wait` resolve the correct provider-log origin
internally (from-start for a new session, a pre-send cursor for a follow-up, the
resume cursor for a resumed session), so ordinary workflows never type an origin
flag. The bare `yaco agent wait` primitive requires an explicit origin
(`--from-start` or `--cursor <token> --offset <bytes>`) and has no default.
**Never use `capture` to detect completion.** `capture` is diagnostics only;
completion comes from `start --wait`, `send --wait`, or an explicit-origin
`agent wait`.
## Listing and inspecting
```bash
# List sessions for a project (defaults to the current project root)
yaco agent list
yaco agent list --path <project-path>
# List every session across all projects
yaco agent list --all
# Inspect a single session by handle
yaco agent status <handle>
```
`list` enumerates sessions; `status` takes exactly one handle and returns that
session's full metadata: `handle`, `provider`, `sessionPath`, `pid`,
`sessionId`, `status`, `createdAt`, plus the lineage fields below.
## Diagnostic capture
```bash
yaco agent capture <handle> # snapshot
yaco agent capture <handle> --lines 50 # last N lines
yaco agent capture <handle> --strip-ansi false # keep ANSI codes
```
`capture` is a diagnostic snapshot of the tmux pane — use it to eyeball what a
session is currently showing, never to read a turn's result (use `--wait` /
`messages` for that). Text mode returns clean text (ANSI stripped by default);
`--json` wraps it as `{ok:true, data:{text:"..."}}`.
## Navigating message history
`messages` reads a session's **full** message history from the provider's
structured log (never PTY). The orchestrator's structured **final** message
already comes from `wait` / `--wait`; reach for `messages` to navigate *earlier*
turns by a stable index.
```bash
# Orient first on a long session: shape + prompt-landmark indices, constant size
yaco agent messages <handle> --summary --json
# Token-cheap table of contents: one lean row per message {index, role, types, chars}
yaco agent messages <handle> --json
# Narrow first (filters never change a row's absolute index), then preview the window
yaco agent messages <handle> --role assistant --type tool_use --json
yaco agent messages <handle> --range -20.. --preview --json # last 20, with snippets
# Pull one full message by index (negative counts from the end)
yaco agent messages <handle> --index 47 --json
yaco agent messages <handle> --index -1 # last message, text raw
```
For a large session, **start with `--summary`** — it returns the role/kind/tool
histograms and the `prompts` landmark indices (real user messages) at constant
size, so you don't dump hundreds of rows to get oriented. Then two-step from
there: **scan `--meta`** (default) → **narrow** with `--role` / `--type`
(prefix-matches, so `--type tool_use` hits `tool_use:Bash`) / `--range a..b`
(inclusive; open ends and negative bounds) → optionally `--preview[=N]` / `--ts`
on the narrowed set → **pull** the full message with `--index <i>`. `chars` is
the budget signal (length of the text `--index` returns). Indices are stable: a
row's `index` is frozen for the session's log, so a `--meta` index is safe to
pass straight to `--index`.
- `--summary` JSON returns a `MessagesSummary`; `--meta` JSON returns a
`MessageMeta[]`; `--index` JSON returns one `MessageFull`
(`{index, role, types, chars, ts, text}`).
- Errors: invalid handle → `USAGE`; no session / pending (no log yet) / index
out of range → `NOT_FOUND`; provider without the capability → `INVALID`.
## Session lineage
`list` and `status` return lineage as fields on each session — you read them,
you never infer lineage yourself:
- `spawnedBy: "user:web" | "user:terminal" | "agent"` — who started the session.
- `parentSession` (optional) — the handle of the agent that spawned this one.
A session's **children** are derived by scanning all sessions (`yaco agent list
--all --json`) for those whose `parentSession` equals the handle in question.
## Linking sessions to tasks
A session is linked to a task through the task CLI, which is the only writer of
a task's `agents` list. Do not edit `tasks.json`.
```bash
yaco task attach <task-id> <session-handle> --json
yaco task detach <task-id> <session-handle> --json
```
See the `/yaco-task` skill for the task graph itself.
## Teardown
```bash
yaco agent kill <handle> --json
yaco agent kill --all --json # all sessions under cwd — human-only
```
`kill --all` is a **nuclear option**: multiple workstreams may share a project's
agent sessions, so only a human should invoke it. Skills kill sessions one
handle at a time.
## Example — capture and thread a handle
```bash
# Start non-blocking, capture the handle, then drive the session by it
HANDLE=$(yaco agent start claude "Fix the failing unit tests" \
--name fixer --json | jq -r .data.handle)
RESULT=$(yaco agent wait "$HANDLE" --from-start)
yaco agent send "$HANDLE" "Now add tests for the edge cases" --wait
yaco agent kill "$HANDLE" --json
```
## Notes
- For tests, prefer `npm run test` for pure unit coverage and
`npm run test:integration` when tmux-backed checks are needed.
- Provider shortcuts (the one-word `yaco <provider> ...` form) are for
interactive human typing only and MUST NOT appear in skill automation. Skills
always use the canonical `yaco agent start <provider> ...` form.