本文へ移動
cccskills
無料GitHub で公開

kolu

Drive one AI agent from another through kolu's terminals: spawn a Claude Code / Codex / opencode session in a PTY, prompt it, watch the screen for its reply, read it, and prompt again — a create→send→snapshot loop run with the `kaval-tui` CLI directly (no MCP). `kaval-tui` writes input and reads scrollback; `pulam-tui` adds a precise agent-state done-signal when you drive hooked terminals. Triggers on "drive another agent", "send a prompt to a terminal agent", "have one agent prompt another", "agent drives agent", "orchestrate agents in terminals", "make Claude drive Codex", "prompt the agent running in that terminal", or wiring a loop where one coding agent supervises another.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md9.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

kolu — drive one agent from another through its terminal

You can run a coding agent (Claude Code, Codex, opencode) inside a kolu-owned PTY and steer it from the outside: type a prompt, submit it, watch the screen until it's done, read what it said, type the next prompt. The whole toolkit is kaval-tui — write input, read the screen, spawn, kill. The driver runs it directly; there's no server to stand up and no MCP layer.

pulam-tui adds a precise done-signal (wait --until <state>) — but only for hooked terminals (see the last section). For a raw kaval-tui-spawned terminal, the done-signal is watching the screen settle, below.

The loop

id=$(kaval-tui create --json -- claude | jq -r .id)            # spawn the inner agent
kaval-tui send  "$id" "refactor the parser to use a lexer"     # 1. TYPE the prompt
kaval-tui send  "$id" --key Enter                              # 2. SUBMIT it (its own step)
wait_until_settled "$id"                                       # 3. let its turn finish (below)
kaval-tui snapshot "$id" --viewport                            # 4. read the screen
kaval-tui send  "$id" "now add tests for it"; kaval-tui send "$id" --key Enter   # loop

Leaf commands, all kaval-tui: create (spawn) · send (type) · send --key Enter (submit) · snapshot (read) · kill. Typing and submitting are two separate sends — that is load-bearing, see below.

Read with snapshot --viewport, not | tail. A bare snapshot prints the whole scrollback — thousands of lines on a long-running or compacted agent — so snapshot | tail -8 hands you the bottom of the buffer (often just trailing blanks), not the live screen. --viewport asks the daemon for just its terminal's last screenful — the right "what's on screen now" read, and correct regardless of how tall your own shell is (over --host the remote terminal is a different size). --tail N (alias --lines N) bounds it to the last N lines when you want a fixed slice.

kaval-tui send — type, then submit (two steps)

kaval-tui send <id> [text...] writes input to the terminal — exactly the text (and any --keys) you pass, with NO implicit Enter. It types; it does not submit. Submitting a prompt is its own second send:

kaval-tui send "$id" "fix the failing test in parser.ts"   # 1. type the prompt
kaval-tui send "$id" --key Enter                           # 2. submit it

Do this as two separate send commands — not send "text" --key Enter in one call. The separation is load-bearing: an Enter sent in the same breath as the text races Claude Code's bracketed-paste / debounced input handling — it arrives before the pasted text has registered and is silently dropped, leaving the prompt staged on the ❯ line while send reports success. A standalone follow-up send --key Enter lands after the text has settled, so it actually submits. (If a turn never seems to start, this is the #1 cause — snapshot and look for the prompt sitting unsent on the ❯ line.)

Specifics:

  • Multiline prompts and piped stdin go as one bracketed paste, so they land in the input box as a block instead of submitting line-by-line. Automatic (--paste / --no-paste force it). For a big prompt, pipe it — cat task.md | kaval-tui send "$id" — then send "$id" --key Enter.
  • --key <name> (repeatable, sent after the text) is both the submit channel (Enter) and the control channel: Escape, C-c, Enter, Up/Down/Left/Right, Tab, Home, End, Backspace, M-<char>.
  • --json → { id, bytes, paste, keys } to confirm what was written.

send is blind — it writes whether or not the agent is ready for input. Always pair it with snapshot so you don't fire a prompt into a not-yet-ready session (e.g. before the TUI has drawn its input box, or over a trust prompt).

Interrupt a runaway before redirecting it:

kaval-tui send "$id" --key Escape          # stop Claude Code mid-stream
kaval-tui send "$id" --key C-c             # SIGINT whatever's running

The done-signal — watch the screen settle

After you submit, you need to know when the turn ends. For a raw kaval-tui-spawned terminal there's no agent-state feed, so use the screen itself: poll snapshot until it stops changing. A working agent streams output, so a screen that's held still for a couple of polls means the turn ended — it finished, or it's blocked asking you something (both mean "your move"). Then read the snapshot to see which, and respond.

# Block until <id>'s screen is unchanged across 2 polls, capped at a deadline so
# a wedged agent can't hang the loop forever (the manual equivalent of a timeout).
wait_until_settled() {
  local id=$1 deadline=$(( $(date +%s) + 600 )) prev="" cur stable=0
  while [ "$stable" -lt 2 ] && [ "$(date +%s)" -lt "$deadline" ]; do
    sleep 3
    cur=$(kaval-tui snapshot "$id" --viewport)   # diff the live screen, not the whole scrollback
    if [ "$cur" = "$prev" ]; then stable=$((stable + 1)); else stable=0; fi
    prev=$cur
  done
}

Poll --viewport, not a bare snapshot: a settle test diffs two reads, and diffing two full-scrollback dumps is slow and noisy (any scrollback churn reads as "still moving"), while two screenfuls compare cleanly.

Tune sleep/deadline to the work. It's coarser than pulam-tui wait (a busy agent that pauses mid-thought can read as settled), so after it returns, confirm the reply is actually present in the snapshot before moving on.

pulam-tui wait — the precise done-signal (hooked terminals only)

When you do have agent-state detection, pulam-tui wait <id> --until <buckets> is the exact done-signal — it blocks until the agent reaches a coarse state, then exits 0:

  • working — busy (thinking / tool_use / background task).
  • awaiting — awaiting_user: it's asking you a question.
  • waiting — the just-finished post-turn lull.

awaiting and waiting both mean "your move", so --until awaiting,waiting catches a turn ending; --timeout <ms> fails loud (exit 2) so a wedged agent can't hang the loop; if the terminal exits before reaching the state, wait fails loud too (exit 3 — the agent you were driving died); --json → { id, agent }.

Mind the stale-state race — wait in two phases. wait matches the agent's state the instant it connects, replaying whatever it is right now. So right after a send, the agent may still report the previous turn's waiting/awaiting for a beat before it picks up the new prompt — and a lone wait --until awaiting,waiting would return immediately on that stale state, before the turn you asked for has even begun. For a robust loop, wait for the pickup first, then the turn-end:

kaval-tui send "$id" "fix the parser"; kaval-tui send "$id" --key Enter
pulam-tui wait "$id" --until working           # 1. it picked up the prompt
pulam-tui wait "$id" --until awaiting,waiting   # 2. its turn ended

Caveat — agent state needs HOOKED terminals. Detection keys on kolu's shell rc-hooks (the OSC marks a terminal emits as commands run). kaval-tui create is the raw multiplexer — a plain $SHELL, no hooks by design — so an agent you spawn that way often isn't detected, and wait will just time out. wait is reliable when you drive already-hooked terminals: the ones a running kolu-server spawned (point kaval-tui --socket $XDG_RUNTIME_DIR/kolu/pty-host.sock at them), or a future kolu-tui. For a raw kaval-tui create loop, use the screen-settle done-signal above.

Reach — which daemon you're driving

Bare kaval-tui autodiscovers a running daemon on this machine. Two ways to point it elsewhere:

  • --socket <path> targets a specific local daemon — e.g. a running kolu-server's kaval ($XDG_RUNTIME_DIR/kolu/pty-host.sock), to drive the terminals you have open in kolu (these ARE hooked, so pulam-tui wait works against them once a pulam reads that kaval).
  • --host <ssh> reaches a daemon on another machine (provisioned with Nix); a remote PTY survives the link.

Acceptance

Before calling a driven turn done:

  • You submitted with a separate send --key Enter (not an implicit Enter, not send "text" --key Enter in one call) — a prompt left staged on the ❯ line is the #1 failure here.
  • The inner agent's reply is actually in the snapshot — not an empty box or a half-rendered stream. The screen-settle wait is coarse; verify the content.
  • Your wait had a deadline / --timeout so a wedged agent fails instead of hanging the loop.
  • If the screen settled on a question (the agent is awaiting you), you read it and answered — you didn't send the next task on top of a blocked prompt.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

be

無料

Modern, interactive alternative to `/do` — clarify intent up front, then take a task end-to-end with a serial AI review gauntlet (lens debate (lowy ⇄ hickey) → codex debate → simplify → code-police, each editing the branch in turn) → CI → evidence. ONLY invoke when the user explicitly types `/be` or `$be`; never auto-select from a natural-language request.

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

be-review

無料

Run /be's review gauntlet SERIALLY — /lens-debate (lowy ⇄ hickey), then /codex-debate, then /simplify, then code-police, each editing and committing on the live branch in turn. Use from /be §4, or when the user asks to "run the review gauntlet". Requires Claude Code's Skill tool.

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

ci

無料

Reference for the `odu` runner — how to invoke a full pipeline, a single recipe, or a platform-pinned node, and how to attach to a live run, from a project whose CI odu runs. Trigger when the user asks to "run CI", "run the pipeline", "re-run a check", to run named lanes or recipes (e.g. "run fmt and nix", "just the e2e lane", bare selectors like `fmt`/`nix`/`e2e`), or names a recipe by `<recipe>@<platform>`. This skill — not a repo's local `just ci` / `just <recipe>` — is how an odu-run request is served.

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

Review code for quality, simplicity, and common mistakes before declaring work complete.

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

Run an automated codex⇄Claude debate to consensus — no round cap, no deadlock exit. Two explicit subcommands. `review` (also the bare/back-compat default) — codex (reviewer) critiques the current diff and a Claude subagent (author) fixes/disputes, looping until they agree. `answer` — Claude and codex each answer a freeform prompt in parallel, then cross-check until they agree, and a unified answer is returned. Use when the user types `/codex-debate`, asks to "have codex review this", "run the codex debate", "review this PR with codex", "argue this with codex until you agree", or passes a question to "have Claude and codex debate/answer until they agree".

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

do

無料

Do a task end-to-end — implement, PR, CI loop, ship. ONLY invoke when the user explicitly types `/do` or `$do`; never auto-select from a natural-language request, even one that sounds like an end-to-end task.

日本語の概要は準備中です。原文の説明を表示しています。

srid/emanote9642026年7月26日 更新

srid のスキルをすべて見る

このスキルの問題を報告する