agentleFS
Surething-ioSurething-io/cockpit/skills/bot-run/SKILL.md

bot-run

Skill44 starsChanged 8 months agoMITView on GitHub

How to run an @bot line: delegate it to its own session and wait for the result.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every [subagent·@name] line in the message is that Bot's work, not yours.

    line 9
  2. Very specific:

    Do not read the BOT.md or bot-turn of a Bot you are delegating to.

    line 13
  3. Very specific:

    Never poll from memory of how this works: If a POST has returned and you have not opened wait.md this turn, stop and open it.

    line 42
  4. Distinctive:

    Start it with both paths, in this order — the general contract, then the particular Bot:

    line 55
  5. Very specific:

    Leave model unset. It is not inherited: the engine picks its own default, and a model chosen for this conversation would otherwise be …

    line 117
  6. Very specific:

    When the user answers your report — a correction, a pick from a numbered list, an answer to a question the Bot asked — that reply belongs …

    line 149

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Running an @bot line

Every [subagent·@name] line in the message is that Bot's work, not yours. Hand it to a session of its own and wait for the answer — you are the dispatcher for these lines, not the executor. The turn is: write a brief (§1), POST it (§2), wait (wait.md), report (§3).

Do not read the BOT.md or bot-turn of a Bot you are delegating to. They are listed at the end of the message under "pass the path along; do not open them yourself" — that is the only reason you have those paths. The child reads them and works from them; keeping them out of this session is the point.

[main·@name] is the opposite instruction

A line tagged [main·@name] means that Bot's directory is this session's own working directory. There is nothing to delegate — you are already sitting in the files a child would have been started to reach. Read the bot-turn path, then that Bot's BOT.md — both are in the "read these skill files first" list rather than the handoff list, because you are their reader this time — and do the task yourself, in the voice its identity files define. Nothing else in this file applies to such a line: no brief, no delegate call, no polling.

A message may carry both tags. When it does, the order matters: POST every [subagent·@name] brief first, then do your own [main·@name] work, then poll. The children run while you work; doing your own part first only makes them start late. In that message bot-turn is listed in both blocks on purpose — you read it for your own line and hand the same path over for theirs.

What else to open, and when

Two files live next to this one and are opened only when the turn reaches them — check this table before you act, not after:

OpenWhenWhy it is not here
{{COCKPIT_DIR}}/skills/bot-run/wait.mdThe moment a delegate POST has returned — before any status callThe poll loop, the budget rule, and what each status means. Every delegation needs it and no [main·@name] line does, so it stays one read away rather than in front of a session that never delegates
{{COCKPIT_DIR}}/skills/bot-run/followup.mdThe Bot asked something back, or the user answers your reportContinuing a session that already exists. Usually a later turn, and the turn that delegates does not need it in hand

Never poll from memory of how this works. If a POST has returned and you have not opened wait.md this turn, stop and open it. Hand-rolled status checks fail in one direction only — they exit at once and you report a result the child never produced — and that failure is invisible from here, because a confident summary of a run that never finished reads exactly like a real one.

1. Write a self-contained brief

The child sees none of this conversation. Everything it needs goes in the brief: the user's intent in their own words, the context you have accumulated here (which repository, which files are in scope, what was already decided, what it should NOT re-litigate), and what "done" looks like. This is the whole value of delegating from here rather than letting the user type it — the brief you write is the part the user did not have to.

Start it with both paths, in this order — the general contract, then the particular Bot:

Read <the bot-turn path> for how a Bot turn works, then <the Bot's BOT.md path> for who this Bot is and which of its files to read. Follow its "Before working" section, then do the task in the voice its identity files define.

Both paths are in the list at the end of the message. Pass them verbatim; a child that is missing bot-turn has no write-lock protocol and will invent one.

Write only what you learned here; never assert what the Bot remembers. You have not read its files — it has. A brief that says "this is already settled in its memory" is a guess dressed as a citation, and the child will take it as a premise it may not re-open. Say where a constraint actually came from ("the user said so in this conversation"), and leave its memory to it.

2. Delegate — fire every @bot line before waiting on any of them

BRIEF=$(mktemp /tmp/cockpit-brief.XXXXXX)
cat > "$BRIEF" <<'EOF_BRIEF'
<the brief>
EOF_BRIEF

curl -sS --fail-with-body -X POST "{{BASE_URL}}/api/sessions/delegate" \
  -H "Content-Type: application/json" -H "x-cockpit-run-id: $COCKPIT_RUN_ID" \
  --data-binary @- <<EOF_JSON
{"cwd": "${COCKPIT_CWD:-$PWD}", "title": "@<name>: <short label>", "briefPath": "$BRIEF"}
EOF_JSON

The body is { cwd, engine?, model?, title?, prompt? | briefPath? }:

  • Do not delete the brief file. The POST returns before the child has read it: the endpoint only checks that the file exists, and the child is handed the path. Tidying up $BRIEF after the call leaves it with a task it cannot read.
  • cwd has two right answers, decided by what the line asks for:

    The @name line iscwd
    ordinary work${COCKPIT_CWD:-$PWD} — exactly as written above, a variable you never resolve yourself
    "导出 / export", "复盘 / review", "装上 / attach"the Bot's own directory: dirname of the BOT.md path listed at the end of the message

    Ordinary work happens in the project, and the Bot reaches its own files by absolute path. The three maintenance verbs are work on the Bot: its files are the subject, its .locks/ is there, and a review writes .reviews/ into it — a child sitting in some unrelated project would reach all of that by absolute path for no reason, and git inside the Bot's own repository would not work at all. Taking dirname of that path is not opening it; the rule against reading it stands.

    COCKPIT_CWD is this session's own working directory, exported by Cockpit. Leave it as a variable in the JSON — the heredoc expands it. Never substitute a path you worked out instead: not the git root, not the nearest directory with a CLAUDE.md, not any parent that looks more like a project than where you are. Doing that silently moves the child one or more levels above where the user is working, and its transcript then lands under a different project in the session list — which is what happened when a session working inside a subdirectory delegated a child at the repository root instead. It is also not pwd: pwd follows any cd this turn has made, which is why the fallback is only there for a Cockpit too old to export the variable.

  • Leave engine unset unless the user named one. Omitted, the child inherits the engine this session is running on — the x-cockpit-run-id header is what tells the server which that is, so send the header exactly as written above. Set it only when the @name line says which engine to use ("用 codex 跑一下", "run this one on glm"); one of claude, codex, deepseek, kimi, glm, ollama. Never open BOT.md to invent a preference — a Bot manifest has only name and description, and it is not where this decision lives.
  • Leave model unset. It is not inherited: the engine picks its own default, and a model chosen for this conversation would otherwise be multiplied across every child you start.
  • title is optional but always worth setting — it is how the session is listed later.
  • For a one-line task you may send "prompt": "..." instead of briefPath (escape " and \). A Bot task rarely is one: the brief carries the accumulated context, which is the whole point.
  • The receipt comes back at once: { cwd, engine, model?, sessionId, link, title, createdAt, parent? }. Post every Bot's brief first, then open wait.md — one wait covers them all.
  • A 400 names the problem — cwd missing, relative, or not a directory; a brief file that does not exist; too many delegated sessions already running. Report what it says; do not retry blindly.

3. Report

One short section per Bot: its conclusion in a few lines, then [open session](<link>). The full answer lives in that session — do not paste it wholesale, and do not restate it as your own. lastReply is cut at 4000 characters; when lastReplyTruncated is true and you need the rest, repeat the status call with --data-urlencode "full=1". Use the receipt's link exactly as returned — it is the only record of the delegation, and tool output is not searchable later.

A [main·@name] line has no link, because it happened here. Give it its own section alongside the delegated ones and close it the way bot-turn §2 requires — the answer, then the list of Bot files you read and changed. That list is the only record of what the answer stood on, and this is the one line in the message that may have edited those files directly.

A numbered list is a special case. Some Bot tasks (a review sweep, for instance) end in a list of findings the user picks from. Relay it whole with its numbering intact, and keep whatever path the child saved it to — the user answers either in that session or by naming that file in a new one, and dropping either detail strands the work.

Pressing stop here does not stop a delegated session — it is a separate run. Say so if the user expects otherwise. A [main·@name] line is the exception: it runs in this session, so stop really does stop it.

When the user answers your report — a correction, a pick from a numbered list, an answer to a question the Bot asked — that reply belongs in the session it came from. Open followup.md; do not start a second one.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.