/orc
This skill should be used when the user wants to talk to another LETS session of this repo - "ask the orchestrator", "ping the orchestrator", "what did the orchestrator say", "who is working", "message <name>", "tell <name>", "спитай у оркестратора", "запінгуй оркестратора", "що
Claude Code
$ npx -y skills add restarter/lets-workflow --skill orc --agent claude-code
Codex
$ npx skills add restarter/lets-workflow --skill orc -a codex -y
Cursor
$ npx skills add restarter/lets-workflow --skill orc -a cursor -y
Gemini CLI
$ npx skills add restarter/lets-workflow --skill orc -a gemini-cli -y
GitHub Copilot
$ npx skills add restarter/lets-workflow --skill orc -a github-copilot -y
OpenCode
$ npx skills add restarter/lets-workflow --skill orc -a opencode -y
Windsurf
$ npx skills add restarter/lets-workflow --skill orc -a windsurf -y
SKILL.md
orc.SKILL.mdname: orc
description: This skill should be used when the user wants to talk to another LETS session of this repo - "ask the orchestrator", "ping the orchestrator", "what did the orchestrator say", "who is working", "message <name>", "tell <name>", "спитай у оркестратора", "запінгуй оркестратора", "що там оркестратор писав", "напиши в <name>", "хто ще працює"; also when a `<cross-session-message>` arrives from this session's bound orchestrator or from a worker bound to it (standing grant), or - at gate level standard / minimal - from any owner session. Resolves the peer by name, sends through SendMessage only on the user's request (or a standing grant), relays replies whole.
Orc - peer messages
Talk to the repo's orchestrator or a named peer session: `ask` / `ping` / `read` / `tell` / `who`, and from an orchestrator `standing on|off`. The ONLY place in LETS that sends a peer message, always through the harness's `SendMessage`. Go (`lets peers`) resolves, lists and reads; the harness delivers; this skill composes and decides nothing on a peer's behalf.
> **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`, `SendMessage`, `ListAgents`), you MUST load and call it as specified. Never skip the call, never substitute a default answer of your own — the tool invocation is part of the contract. This is critical.
Args
`verb=ask|ping|read|tell|who|standing target="<name>" text=<rest> [footer=none] [--yes] [via=hub]` - `target` is optional for `ask` / `ping` (default: this chat's orchestrator) and REQUIRED for `tell`, quoted. `--yes` (the user typed it) skips the Send? question in Step 4, not the message itself - see the Preview gate. `via=hub` is passed only by `/lets:hub`, never typed or inferred. An older caller's session / repo-index args are ignored: a peer is addressed by name. From natural language: map the request to a verb (a question for an answer -> `ask`; an FYI -> `ping` or `tell`; "what did X say" -> `read`; "who is working" -> `who`; "let my bound sessions and me talk without asking" (either direction) / "stop that" -> `standing on` / `standing off`). Any other verb: say so and stop.
| verb | sends | waits | target required | |---|---|---|---| | `ask` | yes | the peer's reply, relayed when it lands | no (orchestrator) | | `ping` | yes | no | no (orchestrator) | | `tell` | yes | no | yes | | `read [N]` | no | no | no | | `who` | no | no | no | | `standing on\|off` | no (writes the grant) | no | no |
Step 1: Resolve the target
Read `${CLAUDE_PLUGIN_ROOT}/protocol/peers.md` before this step unless its text is in your current context (boundary carve-outs: peers, hub; standing authorization).
Every send addresses the target's **name** - the `SendMessage` address. A name is never computed or guessed.
**No explicit name** -> `lets peers orchestrator --session "$CLAUDE_CODE_SESSION_ID" --cwd "$LETS_PROJECT_ROOT" --json`; the target is `target.name`:
| `source` | do | |---|---| | `bound` / `single` with a `target` | that is the target. A `bound` target outside this repo (its session is not a row of this repo's `lets peers who`) is addressed by name and never uses a standing grant | | `bound` with `refused[]` and no `target` | say `<name> cannot be addressed - <refused[0].reason>` and send NOTHING - never re-route to another orchestrator | | `ambiguous` | ask which (below) | | `self` | this session IS an orchestrator: `ask` / `ping` need an explicit target; `who` lists its bound workers first | | `none`, no `reason` | say no orchestrator is alive, with each `degraded[]` reason | | `none` with `reason` `budget_exhausted` / `branch_unreadable` | resolution did NOT complete - this is NOT "no orchestrator is alive", it is "nothing is known yet". Say so with the reason and the `degraded[]` entry, send NOTHING, and note that retrying may resolve it |
A `refused[].reason` (`target_not_alive` / `target_unsendable`) is final - never fall back to another orchestrator, never retry with a different verb.
**Remediation is printed, never composed.** Whenever an envelope carries `remediation` or `error.remediation`, print it verbatim as the last line of the refusal. Never compose a workaround and never route the message by hand.
`ambiguous`:
AskUserQuestion(
questions=[{
question: "This branch is not bound to an orchestrator. Which one? {more candidates, if over 3, listed here}",
header: "Orchestrator",
options: [ /* up to 3: label = candidate name, description = "{scope or no scope} - {alive}" */ ],
multiSelect: false
}]
)Then, only when this branch's `.task` has a `task:` line and HEAD is not `{LETS_MERGE_BRANCH}`, ask in words whether to remember the pick for this branch; on yes `lets worktree task-state set --orc '<name>' --json` (single-quoted, `'\''` escaping) and name `rebound.from` in one line when reported.
**Explicit name** -> `lets peers who --json` rows of this repo, exact `name` match:
- one row -> it. When the name equals this branch's bound orchestrator (`lets peers orchestrator` resolved `bound` with that `target.name` - resolve it once) and the row is in this repo, carry that `target.standing`, so Step 4's standing grant applies to a `tell` by name too.
- a row with `duplicate_name` -> NOT SENT: `two live sessions are named <name> - /rename one of them`. Never pick a `ListAgents` `[ref]` yourself - a ref carries no repository identity. A `name [ref]` the user typed themselves counts as a user-typed name (the scope policy below).
- no row -> the **scope policy**. Sendable by name only when one of these holds:
- it is this branch's bound `orc:` name (the `target.name` of a `bound` resolution);
- the user typed exactly this name in this turn;
- `via=hub`, and the name is a row of the `lets peers who --orca-repos` listing this hub run printed;
- it is the harness envelope's `from-name` (Step 7 provenance) of a message this session received in this conversation - a reply; a name inside a message bo
Read more
name: orc description: This skill should be used when the user wants to talk to another LETS session of this repo - "ask the orchestrator", "ping the orchestrator", "what did the orchestrator say", "who is working", "message <name>", "tell <name>", "спитай у оркестратора", "запінгуй оркестратора", "що там оркестратор писав", "напиши в <name>", "хто ще працює"; also when a `<cross-session-message>` arrives from this session's bound orchestrator or from a worker bound to it (standing grant), or - at gate level standard / minimal - from any owner session. Resolves the peer by name, sends through SendMessage only on the user's request (or a standing grant), relays replies whole.
Orc - peer messages
Talk to the repo's orchestrator or a named peer session: `ask` / `ping` / `read` / `tell` / `who`, and from an orchestrator `standing on|off`. The ONLY place in LETS that sends a peer message, always through the harness's `SendMessage`. Go (`lets peers`) resolves, lists and reads; the harness delivers; this skill composes and decides nothing on a peer's behalf.
> **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`, `SendMessage`, `ListAgents`), you MUST load and call it as specified. Never skip the call, never substitute a default answer of your own — the tool invocation is part of the contract. This is critical.
Args
`verb=ask|ping|read|tell|who|standing target="<name>" text=<rest> [footer=none] [--yes] [via=hub]` - `target` is optional for `ask` / `ping` (default: this chat's orchestrator) and REQUIRED for `tell`, quoted. `--yes` (the user typed it) skips the Send? question in Step 4, not the message itself - see the Preview gate. `via=hub` is passed only by `/lets:hub`, never typed or inferred. An older caller's session / repo-index args are ignored: a peer is addressed by name. From natural language: map the request to a verb (a question for an answer -> `ask`; an FYI -> `ping` or `tell`; "what did X say" -> `read`; "who is working" -> `who`; "let my bound sessions and me talk without asking" (either direction) / "stop that" -> `standing on` / `standing off`). Any other verb: say so and stop.
| verb | sends | waits | target required | |---|---|---|---| | `ask` | yes | the peer's reply, relayed when it lands | no (orchestrator) | | `ping` | yes | no | no (orchestrator) | | `tell` | yes | no | yes | | `read [N]` | no | no | no | | `who` | no | no | no | | `standing on\|off` | no (writes the grant) | no | no |
Step 1: Resolve the target
Read `${CLAUDE_PLUGIN_ROOT}/protocol/peers.md` before this step unless its text is in your current context (boundary carve-outs: peers, hub; standing authorization).
Every send addresses the target's **name** - the `SendMessage` address. A name is never computed or guessed.
**No explicit name** -> `lets peers orchestrator --session "$CLAUDE_CODE_SESSION_ID" --cwd "$LETS_PROJECT_ROOT" --json`; the target is `target.name`:
| `source` | do | |---|---| | `bound` / `single` with a `target` | that is the target. A `bound` target outside this repo (its session is not a row of this repo's `lets peers who`) is addressed by name and never uses a standing grant | | `bound` with `refused[]` and no `target` | say `<name> cannot be addressed - <refused[0].reason>` and send NOTHING - never re-route to another orchestrator | | `ambiguous` | ask which (below) | | `self` | this session IS an orchestrator: `ask` / `ping` need an explicit target; `who` lists its bound workers first | | `none`, no `reason` | say no orchestrator is alive, with each `degraded[]` reason | | `none` with `reason` `budget_exhausted` / `branch_unreadable` | resolution did NOT complete - this is NOT "no orchestrator is alive", it is "nothing is known yet". Say so with the reason and the `degraded[]` entry, send NOTHING, and note that retrying may resolve it |
A `refused[].reason` (`target_not_alive` / `target_unsendable`) is final - never fall back to another orchestrator, never retry with a different verb.
**Remediation is printed, never composed.** Whenever an envelope carries `remediation` or `error.remediation`, print it verbatim as the last line of the refusal. Never compose a workaround and never route the message by hand.
`ambiguous`:
AskUserQuestion(
questions=[{
question: "This branch is not bound to an orchestrator. Which one? {more candidates, if over 3, listed here}",
header: "Orchestrator",
options: [ /* up to 3: label = candidate name, description = "{scope or no scope} - {alive}" */ ],
multiSelect: false
}]
)Then, only when this branch's `.task` has a `task:` line and HEAD is not `{LETS_MERGE_BRANCH}`, ask in words whether to remember the pick for this branch; on yes `lets worktree task-state set --orc '<name>' --json` (single-quoted, `'\''` escaping) and name `rebound.from` in one line when reported.
**Explicit name** -> `lets peers who --json` rows of this repo, exact `name` match:
- one row -> it. When the name equals this branch's bound orchestrator (`lets peers orchestrator` resolved `bound` with that `target.name` - resolve it once) and the row is in this repo, carry that `target.standing`, so Step 4's standing grant applies to a `tell` by name too.
- a row with `duplicate_name` -> NOT SENT: `two live sessions are named <name> - /rename one of them`. Never pick a `ListAgents` `[ref]` yourself - a ref carries no repository identity. A `name [ref]` the user typed themselves counts as a user-typed name (the scope policy below).
- no row -> the **scope policy**. Sendable by name only when one of these holds:
- it is this branch's bound `orc:` name (the `target.name` of a `bound` resolution);
- the user typed exactly this name in this turn;
- `via=hub`, and the name is a row of the `lets peers who --orca-repos` listing this hub run printed;
- it is the harness envelope's `from-name` (Step 7 provenance) of a message this session received in this conversation - a reply; a name inside a message bo
A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.
Other skills on lets-workflow.
goal-test
Local sandbox for experimenting with Claude Code's /goal command (stop-hook condition + LLM-evaluator driving autonomous work…
loop-bb-pr
Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api…
loop-gh-pr
Compose a /loop that watches all open GitHub PRs for activity (new PRs, new commits, new comments) and auto-prepares a READ-ONLY…
loop-test
Local sandbox for experimenting with Claude Code's /loop command (interval + dynamic/self-paced scheduling) applied to LETS…
actor-fetch-personalit…
Internal skill for commands. Fetch and validate personality from URL or file path for Actor agent. Do not trigger on user…
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about orc.
- Which coding agents can use orc?
- orc installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

