worktree-create ยท diff
git:20261017.4ed21ba to git:20261018.8b14e79
3 added, 1 removed. Audit A to A.
---
name: worktree-create
description: Create a named Toastty task workspace and Git worktree, nested as a task space under the current session, for planning or implementation. Use when the user asks to hand off a task or move it into a new worktree or task space. Start a fresh task conversation or fork an existing Codex or Claude discussion into the worktree.
---
# Worktree Create
Create the task's worktree and workspace together. Launch a fresh task session,
or fork the current conversation when the task has already been discussed.
A generated summary must not replace inherited conversation or a settled plan.
The user continues directly in the new workspace, and the task session reports
to them there. After a verified handoff, the launcher exits its own agent session
by default; see [parent session lifetime](#parent-session-lifetime).
Resolve scripts relative to the loaded package, including inside plugin snapshots.
Use `scripts/create-worktree.sh` and `scripts/open-toastty-worktree-session.sh`.
Never edit the delivered snapshot.
## Select the start
- **Default: execute the established task.** The user's worktree-create request
starts work on the task discussed in the conversation. Use `--mode implement`
unless the user explicitly limited this task to planning, investigation, or
another read-only outcome. Do not add an approval checkpoint merely because
the task is moving into a worktree or needs some design before implementation.
- **Publication scope:** user-authorized implementation handoffs include task-branch
push and PR publication under [the task workflow](references/task-workflow.md).
The launch prompt carries this scope. Include any user publication limits
verbatim in the handoff. Merging, deployment, and production activation require
separate authorization; repository publication rules and runtime approvals
still apply.
- **Existing discussion:** fork with `--fork-from-session "$TOASTTY_SESSION_ID"`
using the same provider. Continue from inherited decisions and the next
unfinished step; do not restart discovery or produce a replacement plan.
- **New task:** use a fresh conversation with the user's actual task request.
Use `--mode implement` for an actionable task. If none can be identified, ask
what to work on instead of inventing scope. Use `--mode plan` only for an
explicitly limited request.
- Resolve ordinary implementation choices autonomously. Preserve explicit user
approval requirements and ask about material unresolved scope changes; keep
independent authorized work moving while awaiting an answer.
- Forks are independent conversations. Later parent messages do not transfer.
The child owns this task after launch and reports directly to the user there.
Do not fork unrelated conversation history when starting a new task.
- Provider changes cannot inherit a native conversation. If a required fork
is unavailable, report the exact missing capability and retain the task;
do not silently substitute a fresh session with a summary.
## Prepare
Read `toastty-capabilities` and require executable `TOASTTY_CLI_PATH`, current
`TOASTTY_PANEL_ID`, and managed `TOASTTY_SESSION_ID`. Use the injected socket
for the owning instance. Discover live actions and queries. Structured forks
require `agent.launch` support for `forkFromSessionID`, and that parameter's
`supportedProfileIDs` must list the selected profile. Check this before creating
resources. Older running apps need an updated app; no raw-terminal fallback
bypasses missing launch support.
Before creating a worktree or workspace for a fork, also verify the installed
provider CLI supports the native fork arguments. First resolve the executable the
selected profile would run and assign it to `$PROVIDER_EXECUTABLE`. Do not use a
bare `command -v claude` or `command -v codex` for this: inside a managed session
Toastty's command shim comes first on `PATH`, so it returns the shim.
- If the live query list includes `agent.profile.state`, run
`"$TOASTTY_CLI_PATH" --json query run agent.profile.state profileID=<profile>`
and use its `executablePath`. It resolves the binary a launch would exec, in
the owning instance's launch environment, skipping the shims. When it returns
`resolved: false`, the fork is blocked; report its `failure` value.
- Otherwise the running Toastty predates that query, and nothing in it exposes
the executable, so fall back to a best-effort lookup. It reads `agents.toml`
from disk and this session's `PATH`, so it cannot see a profile edit awaiting
Reload Configuration. Limit it to the plain case: the profile's argv[0] in
`agents.toml` must be the bare provider name `claude` or `codex` (a built-in
profile with no override also uses that name). Any other argv[0], such as an
absolute path or a wrapper, is a blocked fork that needs the query. Set that
name as `profile_command` and resolve it with the shim directory removed and
the agent base path appended, as the shim itself does:
```bash
shimless="$(printf '%s' "$PATH" | tr ':' '\n' | grep -vxF "$TOASTTY_AGENT_SHIM_DIR" | paste -sd: -)"
candidate="$(PATH="$shimless${TOASTTY_AGENT_BASE_PATH:+:$TOASTTY_AGENT_BASE_PATH}" command -v "$profile_command")"
# A shell function or alias yields a bare name rather than a path, and a
# symlinked PATH entry can still reach the shim. Accept only a real file
# outside Toastty's shims; anything else leaves the fork blocked.
if [[ "$candidate" == /* ]] && resolved="$(realpath "$candidate" 2>/dev/null)" &&
[[ -x "$resolved" && "$(basename "$resolved")" != toastty-agent-shim &&
"$(dirname "$resolved")" != "$(realpath "$TOASTTY_AGENT_SHIM_DIR")" ]]; then
PROVIDER_EXECUTABLE="$candidate"
fi
```
TODO: remove this fallback once every running Toastty provides the query.
Toastty composes the provider's fork invocation itself; the helper only passes
`forkFromSessionID`. These probes confirm the installed CLI accepts the flags
Toastty will use. Run them read-only on the verified executable, without
launching or authenticating an agent:
- Codex: `"$PROVIDER_EXECUTABLE" fork --help` must succeed and advertise the
session and prompt arguments, plus the `-C`/`--cd` option used by Toastty.
- Claude: `"$PROVIDER_EXECUTABLE" --help` must advertise `--resume`,
`--fork-session`, and `--system-prompt-snapshot` with its `off` value.
`"$PROVIDER_EXECUTABLE" --version` must meet the minimum the live
`forkFromSessionID` descriptor states, rather than a floor pinned here.
Missing or ambiguous evidence is a blocked fork, not permission to substitute a
fresh session. Record the verified executable, whether it came from the query or
the fallback, and the capability evidence in the handoff. Label a fallback result
as best-effort: it checks the CLI this session resolves, not proof of the exact
binary the launch will run. Run required setup separately; `--initial-command` cannot be combined
with `--fork-from-session`.
Read [model and base selection](references/model-and-base.md). Choose an available
provider/model/effort explicitly, preserving Codex versus Claude unless the user
requests otherwise. Identify the repository, intended remote/destination and
pinned base commit without modifying the parent checkout. Choose a short task
slug and semantic branch prefix (`feat`, `fix`, `debug`, `refactor`, `test`,
`docs`, or `chore`) matching repository conventions.
Find explicit fresh-worktree setup requirements in the target repository's
instructions. Run those commands from the new worktree before launch. Do not
infer setup from a package manager's presence, and do not add trust-changing
commands without authorization.
## Create
The examples use `SKILL_DIR` for the loaded skill directory and `TASK` for the slug.
```bash
"$SKILL_DIR/scripts/create-worktree.sh" \
--slug "$TASK" --branch-prefix "$PREFIX" --base-ref "$BASE_SHA" --json
```
- Parse the returned branch, worktree, and handoff paths.
+ Parse the returned branch, worktree, and handoff paths. The `handoff_path` is the
+ destination for a file you must create; the helper does not write a handoff or
+ template.
Run the required setup. Keep any failure and the created resources visible; do
not launch an agent into a half-configured task or delete resources to hide an
error.
## Preserve context
Keep `WORKTREE_HANDOFF.md` to current worktree/branch, pinned base/destination,
mode and launch selections, publication scope and user limits, source session
identity, setup result, and artifact paths/URLs to open. Link the task workflow at
`$TOASTTY_USER_SKILLS_ROOT/worktree-create/references/task-workflow.md`, falling
back to `~/.toastty/skills/...` when that variable is absent, and verify that the
file exists. Use that stable source rather than `$SKILL_DIR`, whose delivered
snapshot path is content-addressed: it changes whenever the skill is edited, so a
handoff pointing into it pins the child to a superseded copy. Explicitly instruct
the child to read and follow that linked file; do not paste its contents. Keep the
private handoff out of commits.
Explicitly ask the launched agent in the handoff to provide verification proof
under the linked [task workflow standard](references/task-workflow.md).
For forks, use inherited history for the request, decisions, authorization,
progress, and next steps. Add a brief task pointer only when the history contains
multiple tasks. Reference settled plans unchanged; do not summarize the discussion
or introduce another approval gate. If essential context was lost to compaction,
consult the referenced artifacts or ask a focused question. Fresh sessions also
need the actual request and constraints; do not invent scope or a finished plan.
List every Scratchpad bound to the current session with `panel.scratchpad.list`.
Export each one with `panel.scratchpad.export` and its `documentID`, and record
each export's path, title, purpose, revision, and whether it is the session
default in the handoff. If none are bound, continue without scanning other
panels. Surface list/lookup/export errors; do not silently omit an artifact
that is the task's design source.
If the live query list lacks `panel.scratchpad.list`, the app predates multiple
Scratchpads per session and supports one linked Scratchpad. Use that path
throughout: find it with `panel.scratchpad.lookup`, export it by `sessionID`,
recreate it and any local HTML mocks with `createPolicy=new` and no `purpose`,
skip `panel.scratchpad.make-default`, and verify with `panel.scratchpad.lookup`
and `panel.scratchpad.state`.
## Launch
```bash
"$SKILL_DIR/scripts/open-toastty-worktree-session.sh" \
--workspace-name "$TASK" --worktree-path "$WORKTREE" \
--handoff-file "$HANDOFF" --mode "$MODE" \
--model "$MODEL" --reasoning-effort "$EFFORT" --json
```
Add `--fork-from-session "$TOASTTY_SESSION_ID"` for an existing discussion.
The source must have verified native session metadata and use the same provider.
The helper passes the worktree cwd explicitly, creates a background workspace,
opens the handoff, launches a managed session and applies workspace scope. It
does not set task or branch annotations.
The helper preserves an existing parent scope, scopes an unrestricted parent
to its current workspace, and includes the new workspace so the launcher can
finish setup. The child receives only its own workspace. Scope is cooperative
guidance, not a security sandbox.
Forks must establish a new native session identity and use the worktree's effective
cwd and permissions. Check launch/runtime evidence before claiming context was
transferred successfully. A composed command alone does not prove the provider
started. The child verifies its directory, branch, scope and handoff before
writes; previous paths in inherited history are historical. Do not resume the
same live native session into a second writer.
After launch, record returned workspace/panel/session IDs in the launcher's
completion notes. Do not rewrite the child's handoff or task state after launch.
## Open referenced artifacts
After the helper returns the new workspace and session IDs, the launcher opens
the task artifacts explicitly referenced by the handoff in the new workspace's
right panel. Do this as part of creation, not as a later offer.
Use the references assembled while writing the handoff; do not build a Markdown
link parser or scan unrelated files or panels. Deduplicate identical artifacts.
Include the associated plans, design documents, mocks, and bound Scratchpads,
not instruction files, executable paths, logs, or every source-code citation.
Record the artifact paths/URLs and titles in the handoff before launch.
- For repository documents, use the corresponding file in the new worktree when
it contains the referenced version. Copy task-owned untracked documents and
local mock assets when necessary, preserving their relative asset paths; do not
silently substitute a different version. Keep exported/private artifacts out
of product commits. Report missing files or inaccessible URLs explicitly.
- Open documents with `panel.create.local-document` using their absolute
`filePath`, the returned destination `workspaceID`, and `placement=rightPanel`.
Open mock sites with `panel.create.browser`, their exact URL, and the same
workspace and placement. For local HTML mocks use the Scratchpad flow rather
than starting an external browser. Use the applicable Toastty document or
Scratchpad skill when preparing the artifact.
- Carry over every exported Scratchpad. First record the child's
`defaultDocumentID` from `panel.scratchpad.list`. Then, in listed order, create
a copy for the returned child `sessionID` with `panel.scratchpad.set-content`,
its exported HTML, original title and purpose, and `createPolicy=additional`.
Each copy opens in the child's right panel without replacing a Scratchpad the
child already created. Afterwards, if the source had a default and the recorded
child default was null, call `panel.scratchpad.make-default` with the source
default's copy. Create local HTML mocks the same way, as separate panels; never
overwrite one artifact with another. Do not use `createPolicy=new` here: it
unbinds the previous default, including an earlier copy.
These are independent copies for the fork; retain the source panels and record
each original document/revision as provenance. Do not rebind or close source
Scratchpads. Preserve supporting assets required to render them; report
anything that cannot be preserved.
- Check every response for success. Verify document paths and right-panel
placement with the destination workspace snapshot. Run `panel.scratchpad.list`
for the child session to confirm every carried-over copy is bound with its
title and the expected default, and check content with
`panel.scratchpad.state`. Use browser state queries for
loading results without selecting or focusing the new workspace. Report
partial failures with exact artifact and workspace identities; do not claim
that referenced artifacts opened merely because the handoff opened.
The launcher owns this initial opening step; the child should not duplicate it.
Artifact failure does not justify launching another child or deleting the
created workspace. Continue opening the remaining independent artifacts, retain
successful setup, and report what remains.
## Handoff and checks
Report the task workspace, worktree/branch, selected mode/provider/model/effort,
whether conversation forking was verified, setup result, and artifact-opening results.
Include exact resource IDs in the durable record; keep the user-facing summary
brief. The user continues planning, implementation and testing in that workspace.
Neither session merges automatically.
Use the helper's JSON results and live metadata to verify child placement and
scope. Confirm no task or Git branch annotation was added. For workflow changes,
validate scripts and exercise the changed launch behavior with a disposable CLI
fixture. For repository copies, also follow that repository's verification guide.
Custom `--startup-command` launches are only for explicit smoke/custom shell use
and cannot claim managed forks.
## Parent session lifetime
Default to exiting the launching parent agent after a successful single-task
handoff, but only when the parent runs in a top-level workspace. A parent in a
task space keeps running: its task space is marked done through `worktree-done`
once its own work is finished, and `session.exit-after-turn` refuses sessions in
task spaces. Check with `workspace.snapshot` for the parent's workspace; a
non-null `parentWorkspaceID` means a task space. Also keep the parent running
when it is creating multiple worktrees as part
of the current request, has specific unfinished coordination work from that
request, or the user explicitly asks to keep it. Decide from the actual assignment;
do not ask for routine confirmation. Record whether the parent will exit or
remain and why in the launcher's completion notes, not in the child's
post-launch handoff.
Keep the parent available if setup, child startup, fork verification, scope, or
artifact opening failed or remains unverified. Finish the independent setup work
and report the exact blocker. Creating a workspace or delivering a launch command
alone is insufficient. Do not exit while another authorized parent task remains.
Exit belongs to the launcher after all setup and artifact work, never inside
`open-toastty-worktree-session.sh`. Before requesting the exit, save the resource
identities and verification results in the durable completion record. Complete
any Toastty notification before the exit request. The child must not depend on a
reply to a parent that is exiting.
For a Codex or Claude Code interactive parent, ask Toastty to exit the parent
after its current turn with `session.exit-after-turn`, targeting the injected
parent panel and requiring its exact managed session identity. Resolve both from
the launcher's injected `TOASTTY_PANEL_ID` and `TOASTTY_SESSION_ID`; never use the
currently focused panel, the returned child IDs, or an inherited child
environment. When the turn completes, Toastty types the provider's native
`/exit`. It skips the exit, and the parent stays, when anyone typed into the
parent or sent it a phone message during the turn, or when the turn ends without
completing. Other providers have no verified native exit, and the action refuses
them, as it refuses sessions in task spaces; retain the parent and report it.
Make the request as the last tool action, then give the handoff summary as the
final message, including where to continue and that the parent will exit:
```bash
"$TOASTTY_CLI_PATH" --json action run session.exit-after-turn \
--panel "$TOASTTY_PANEL_ID" "expectedSessionID=$TOASTTY_SESSION_ID"
```
The request does not end the turn, so a final answer can follow it in Codex as
well as in Claude Code. Make no tool calls after it. A successful response proves
the request was armed, not that the parent will exit; describe it as an exit
request. If the request returns an error, retain the parent and report it. Make
at most one request; do not retry or weaken the identity check.
If the running Toastty does not list `session.exit-after-turn` in `action list`,
retain the parent and say so in the handoff summary.
Never substitute `session stop` (registry bookkeeping), `exit` in a tool shell
(only exits that shell), process kills, or panel or workspace closure. When the
parent ran in a tab that Toastty opened for a session started from the phone,
Toastty closes that tab after the parent's clean exit; otherwise the parent's
terminal stays. Preserve the parent's workspace and source artifacts.