Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions .claude/skills/thurbox-session/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ origin/main` before `session create`, or check that
`session create` is **synchronous** — the tmux window is live when it returns.

```bash
thurbox-cli session create --name <slug> \
thurbox-cli session create --name 'Run exec automations off the TUI thread' \
--repo-path /abs/path/to/repo \
--worktree-branch <branch> --base-branch main \
--worktree-branch fix/automation-exec-nonblocking --base-branch main \
--json
```

| Flag | Meaning |
|---|---|
| `--name` | 1–64 chars, no slashes, no leading `.` |
| `--name` | 1–64 chars, no slashes, no leading `.`; spaces are fine — write an imperative sentence, not a slug |
| `--repo-path` | absolute path to the **primary** repo |
| `--worktree-branch` | create a git worktree on this branch |
| `--base-branch` | base for the worktree (default `main`) |
Expand All @@ -59,6 +59,35 @@ thurbox-cli session create --name <slug> \

Capture the returned UUID — every later command keys off it.

### Naming a session

A session name is an **imperative summary of the work, in sentence case**. It
says what the worker is being asked to do; it is not an identifier for it.

```
Run exec automations off the TUI thread good
Document the customization surface good
thurbox-automation-nonblocking bad — a kebab slug, reads as an id
Fix stuff bad — says nothing
```

Spaces are allowed. `session create`, `session get --json`, and
`message send --to` all round-trip a spaced name intact; any claim that names
must be hyphenated is wrong. The rest of the rules follow from how the name is
used:

- **Imperative mood, sentence case.** Capitalize the first word only. Leave
identifiers in the casing they already have — `gh`, `TUI`, `extension.toml`.
- **No repo prefix.** The repo is already on the session (`session get --json`,
field `cwd`) and in the run log. Repeating it spends the 64 characters twice.
- **Quote it.** The name is a mailbox address — `message send --to 'Run exec
automations off the TUI thread'`. Unquoted, the shell splits it on spaces and
the send addresses something that isn't there.
- **The branch is not the name.** `--worktree-branch` stays kebab-case and may
contain slashes (`fix/automation-exec-nonblocking`); `--name` may not.
- **Keep it short.** The TUI's window list truncates. Two names that only differ
past the cut are the same name as far as the operator can see.

## 1a. Remote hosts (`--host`)

Hosts come from `~/.config/thurbox/hosts.toml`; a host `foo` registers the
Expand Down Expand Up @@ -137,8 +166,9 @@ One session can span several repos. Two repeatable flags:
material the worker should read but not modify.

```bash
thurbox-cli session create --name cross-cut --repo-path /repos/a \
--agent claude --worktree-branch feat/x --base-branch main \
thurbox-cli session create --name 'Add a license header to every source file' \
--repo-path /repos/a --agent claude \
--worktree-branch chore/license-header --base-branch main \
--add-repo /repos/b@main --add-repo /repos/c@master \
--add-dir /repos/reference \
--json
Expand Down Expand Up @@ -204,14 +234,14 @@ environment, so a worker sends its own mail with no ids:

```bash
# instruct the worker to finish with:
thurbox-cli message send --to <lead-name-or-uuid> --kind result --body '<PR url or NOT_APPLICABLE>'
thurbox-cli message send --to '<lead-name-or-uuid>' --kind result --body '<PR url or NOT_APPLICABLE>'
```

The payload travels through the durable DB, never the pane. Drain it
exactly-once from the lead:
Quote the address: a name is a sentence with spaces in it. The payload travels
through the durable DB, never the pane. Drain it exactly-once from the lead:

```bash
thurbox-cli message inbox --for <lead> --claim --json
thurbox-cli message inbox --for '<lead>' --claim --json
```

**The control plane's own Claude IS a thurbox session** — it runs inside one, so
Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,13 @@ file means editing those four lines too. You do not have to: renaming the
session does not require renaming the file, and `FLEET.md` is a fine name for
the standing context of a session called anything.

There is a seventh appearance of `fleet`, and it is **not** coupled to the other
six: the worker naming convention `fleet-<slug>` in `orchestration/playbooks/`
and `orchestration/runs/_TEMPLATE.md`. Worker session names are free-form
strings that nothing resolves. Rename them for consistency or leave them —
nothing breaks either way. The same goes for this README's own prose: it is
documentation, so it follows a rename rather than driving one.
**Worker** session names are not among the six and not coupled to them. They are
free-form strings that nothing resolves, and by the convention in
`orchestration/playbooks/` and `orchestration/runs/_TEMPLATE.md` each is an
imperative sentence describing the work — `Document the customization surface` —
carrying neither a `fleet` prefix nor a repo prefix. A rename never reaches
them. The same goes for this README's own prose: it is documentation, so it
follows a rename rather than driving one.

## Layout

Expand Down Expand Up @@ -198,15 +199,18 @@ work and its PR arrives conflicting.
A worker finishes by mailing its result to the lead:

```bash
thurbox-cli message send --to <lead> --kind result --body '<PR url or NOT_APPLICABLE>'
thurbox-cli message send --to '<lead>' --kind result --body '<PR url or NOT_APPLICABLE>'
```

and the lead drains the inbox exactly-once:

```bash
thurbox-cli message inbox --for <lead> --claim --json
thurbox-cli message inbox --for '<lead>' --claim --json
```

Quote the address. A session name is an imperative sentence, spaces and all, so
an unquoted one is split by the shell and mails somewhere else.

This beats polling `gh pr list` on three counts. It is **exact** — the worker
names its own artifact instead of you inferring it from a PR list that may
contain someone else's. It is **immediate** — `message send` wakes the
Expand Down
4 changes: 3 additions & 1 deletion orchestration/playbooks/_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ to a single repo", "apply the same change across N repos").

How to decompose the goal into thurbox sessions. For each session, define:

- **name** — hyphenated, no spaces, ≤ 64 chars (e.g. `fleet-<slug>`).
- **name** — an imperative sentence in sentence case, ≤ 64 chars, no slashes
(e.g. `Document the customization surface`). Spaces are fine. Don't prefix it
with the repo; the session and the run log both carry that already.
- **repo / worktree** — the target repo and branch the worker operates on.
- **prompt** — self-contained; the worker never sees this conversation.
- **done when** — the acceptance signal (a PR, a passing test, a file).
Expand Down
6 changes: 5 additions & 1 deletion orchestration/playbooks/cross-repo-sweep.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ tweak, a license header, a README badge, a config migration.

One worker session **per repo**, all with the same prompt shape.

- **name** — `fleet-sweep-<repo>`.
- **name** — the change, imperative and in sentence case, ending in the repo it
targets: `Add a license header to widgets`. A sweep runs one goal many times
and the name is a mailbox address, so a name that omits the repo is a name
every session in the wave shares. Bare repo name, no owner — `--name` takes no
slashes.
- **repo / worktree** — that repo, fresh worktree off its default branch.
- **prompt** — the generic goal + "adapt to this repo's stack; open a PR. If the
change doesn't apply here, say so and stop." Either way it finishes by mailing
Expand Down
4 changes: 3 additions & 1 deletion orchestration/playbooks/ship-feature.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

One worker session.

- **name** — `fleet-ship-<slug>`.
- **name** — the change, imperative and in sentence case:
`Cache the registry sync between runs`. No repo prefix — the session already
carries the repo, and so does the run log.
- **repo / worktree** — `repo`, fresh worktree off `base`.
- **prompt** — self-contained: the goal, acceptance criteria, "open a PR when
done, then mail the PR URL back". Point the worker at the repo's own
Expand Down
9 changes: 6 additions & 3 deletions orchestration/runs/_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@

## Sessions

Name each session as an imperative sentence describing the work, in sentence
case — no repo prefix, the repo has its own column.

| Session name | Repo | Intent | Status | Artifact / PR |
|---|---|---|---|---|
| `fleet-...` | `owner/repo` | one line | running / done | link |
| `Document the customization surface` | `owner/repo` | one line | running / done | link |

## Timeline

- <time> — launched `fleet-...` against `owner/repo`.
- <time> — drained the inbox; `fleet-...` reported …
- <time> — launched `Document the customization surface` against `owner/repo`.
- <time> — drained the inbox; that session reported …

## Outcome

Expand Down