Spawn a coding-agent session correctly with `ainb run`: always into a git worktree, never bare into a plain checkout. Use whenever you are about to start a Claude/Codex/Gemini/Copilot session in a terminal. Guards the invocations that silently produce a `(broken)` workspace row, two agents sharing one working tree, a `--parent` flag that never fires, or a teardown that cancels itself and leaks the session.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add stevengonsalvez/claudecode-bootstrap --skill ainb-spawn --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ainb Spawn?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/stevengonsalvez-ainb-spawn)More formats (shields.io, HTML) on the badges page.
---
name: ainb-fleet:ainb-spawn
description: |
Spawn a coding-agent session correctly with `ainb run`: always into a git
worktree, never bare into a plain checkout. Use whenever you are about to
start a Claude/Codex/Gemini/Copilot session in a terminal. Guards the
invocations that silently produce a `(broken)` workspace row, two agents
sharing one working tree, a `--parent` flag that never fires, or a teardown
that cancels itself and leaks the session.
version: "0.1.0"
user-invocable: true
triggers:
- ainb-fleet:ainb-spawn
- ainb spawn
- spawn a coding agent
- run claude in a worktree
- start an agent session
allowed-tools:
- Bash
---
# ainb spawn, start a session correctly
One command, two legal shapes for `--repo`. Getting that choice wrong is what
shares a working tree between two agents or nests a worktree inside a worktree.
## The two legal shapes
Fresh session off a repo root (the common case):
```bash
ainb run \
--repo /absolute/path/to/repo-root \
--worktree --create-branch fix/issue-101 \
--tool claude \
--dangerously-skip-permissions \
-p "$(cat /tmp/task-101.md)"
```
Existing task worktree (isolation already done, do not nest another):
```bash
ainb run --repo /absolute/path/to/existing/worktree --tool claude -p "$(cat task.md)"
```
Which shape? One command decides it (`.git` is a *file* in a real worktree, a
*directory* in a normal clone):
```bash
test -f "$P/.git" && echo "worktree: pass bare" || echo "repo root: add --worktree --create-branch"
```
## Flags, and why
| Flag | Why |
|---|---|
| `--repo <abs-path>` | Repo root, or an existing task worktree. Absolute, always. |
| `--create-branch <branch>` | Implies `--worktree` and names the branch. Prefer over bare `--worktree`, which invents `ainb/session-<shortid>`. |
| `--worktree` | Isolation. Lands at `~/.agents-in-a-box/worktrees/by-name/<repo>--<branch>--<shortid>`. |
| `--tool claude\|codex\|gemini\|copilot` | Which CLI to launch (default `claude`). |
| `--model <id>` | Passed through to the provider unchanged. Optional. |
| `--dangerously-skip-permissions` | Unattended runs only. |
| `-p "<task>"` | Initial prompt, sent once the input box is ready. |
| `--name <handle>` | Optional stable tmux handle. Legal: it changes the session/tmux name only, never `workspace_name`, and fleet routes on the tmux name. Prefer the minted name unless you want something to type at. |
| `--parent <session-id>` | Routes the child's completions to your inbox. Needs *your own* session id, which you must resolve (see below), not an env var. |
## Parent linkage, resolve your own id
There is **no `$AINB_SESSION_ID`**. ainb exports only `AINB_PARENT_SESSION` into
a session, and that holds the *parent's* id, not the session's own. Resolve
yours from the tmux session name:
```bash
MY_TMUX=$(tmux display-message -p '#{session_name}' 2>/dev/null)
MY_ID=$(ainb list --format json \
| jq -r --arg t "$MY_TMUX" '.[] | select(.tmux_session_name == $t) | .session_id')
ainb run --repo "$REPO" --worktree --create-branch "$BRANCH" --tool claude \
${MY_ID:+--parent "$MY_ID"} -p "$(cat "$TASK_FILE")"
```
Empty `MY_ID` (not inside an ainb session) omits the flag and spawns unparented,
which is fine. The `${...:+...}` guard is not cosmetic: an unresolved id fails
two different ways, and only one of them is loud.
## Traps
| Trap | What happens | Do instead |
|---|---|---|
| `--repo <repo-root>` with no `--worktree` / `--create-branch` | Agent runs in the repo's own working tree; two agents stomp each other. The TUI used to render that row as `(broken)`; it now names it after the owning repo, so nothing in `ainb list` flags the mistake. | Add `--worktree --create-branch <branch>` |
| `--parent ""` (quoted, empty or whitespace-only) | Accepted by the parser, then trimmed and dropped by `ainb run`. The child spawns UNPARENTED, no warning, and its completions never reach your inbox. | `${MY_ID:+--parent "$MY_ID"}` so an empty id emits no flag |
| `--parent $MY_ID` unquoted with `MY_ID` unset (e.g. `"$AINB_SESSION_ID"`, which ainb never exports) | The token vanishes before clap sees it, so clap consumes the NEXT token as the parent id. Next token starts with `-`, or `--parent` was last: clap aborts with `error: a value is required for '--parent <PARENT>'`, exit 2, nothing spawns. Next token is a bare word (path, branch): clap swallows it as the parent id and the flag it belonged to is lost, corrupting the spawn. | Resolve `MY_ID` from the tmux name (above), then `${MY_ID:+--parent "$MY_ID"}` |
| `ainb kill <id>` / `ainb git cleanup` without `--force` | Both prompt `[y/N]` on stdin with no tty check. From a tool call the read returns empty, they print `Cancelled.` and exit 0, so the session leaks while you believe it is gone. | Always `--force` |
| `rm -rf <dir>` right after a bare `ainb kill` | Deletes the checkout out from under a still-live agent. | `--force`, then confirm via `ainb list` before deleting |
| `tmux new-session ... claude -p` for repo coding | No worktree, no session record, invisible to every fleet verb. | Use `ainb run` |
## Verify
```bash
ainb list --format json | jq -r '.[] | "\(.session_id)\t\(.workspace_name)\t\(.worktree_path)"'
ainb status <id> # one-shot state
ainb logs <id> --lines 80 # recent output, -f to follow
ainb kill <id> --force # teardown, exact id only; --force is mandatory here
ainb git cleanup --dry-run # preview the worktree prune
ainb git cleanup --force # perform it
```
`workspace_name == "(broken)"` means ainb could not resolve the session root to
a git repository at all: no ancestor directory holds a usable `.git`, and the
directory name carries no `<repo>--<branch>--<shortid>` hint to fall back on.
Kill it and respawn with `--worktree --create-branch`.
A plain checkout, or a subdirectory of one, is **not** broken. It resolves to the
repository that owns it and is labelled with that repository's name. It is only
unisolated, and `ainb list` will not tell you that, so a real-looking
`workspace_name` is not proof you passed the isolation flags.
## Note: subdirectory sessions carry the owning repo's name
Point `--repo` at a subdirectory of a checkout and the TUI workspace row shows
the **owning repository's** name, not the subdirectory's. That is intended (the
workspace row is the grouping key and the repo owns the group), but it reads as a
rename to anyone who remembers the old labels. Not a bug, and not a sign the
wrong path was passed.
## See also
- [`/ainb-fleet:standup`](../standup/SKILL.md) to confirm the session joined the fleet.
- `/coding-agent` (toolkit skill) for choosing between `ainb run`, a Task subagent, and raw tmux.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!