Skip to content
Closed
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
17 changes: 17 additions & 0 deletions .agents/skills/babysit-worktrees/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: babysit-worktrees
description: Address pull request comments for every active non-main worktree.
disable-model-invocation: true
---

# Babysit worktrees

This skill requires unsandboxed execution. If the environment is sandboxed, report that blocker and stop.

Load `$spawn-worktrees`.

Instruct each subagent to use the global `$babysit` skill. Do not load `$babysit` or perform its work yourself.

Be silent while you patiently wait for each subagent terminal result.

As subagents finish, cherrypick any new commits created on their branches onto local `main` that are not already present; ensure `base/fork` documentation is also updated as needed.
6 changes: 6 additions & 0 deletions .agents/skills/babysit-worktrees/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface:
display_name: "Babysit Worktrees"
short_description: "Address PR comments in active non-main worktrees."

policy:
allow_implicit_invocation: false
30 changes: 30 additions & 0 deletions .agents/skills/rebuild-main/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: rebuild-main
description: Rebuild local main from base/fork and the active worktree commits.
disable-model-invocation: true
---

# Rebuild main

The goal is to rebuild `main` from `base/fork` and the active worktree commits, preserving their customizations and tracking. The rebuilt `main` should be a clean fast-forward of `base/main`, with all worktree customizations applied in order.

## Steps

1. Inventory all active non-main worktree branches.
2. Study the existing `FORK.md` and preserve `main`'s old tip for recovery and reference. Require a clean `main` worktree before rewriting it.
3. Fix the target at the current `base/main` commit. Require all worktree branches to share that base, with one customization commit per branch. Report branches needing preparation and stop before rebuilding.
4. Rewind `main` to its latest upstream base without revert commits, then fast-forward it to the target.
5. `base/fork` goes first. Apply all `base/fork` commits above the target to `main` in order, or fast-forward `main` to `base/fork` when equivalent.
6. Cherry-pick each remaining worktree branch's single commit onto `main`, one branch at a time, preserving its message. Before proceeding to the next branch, complete and validate the integration work needed as noted in "Integration Work" below, for it to coexist with the branches already applied.

## Integration work

- Preserve existing `main` tracking configuration.
- Reflect relevant `BRANCH_DETAILS.md` content in `FORK.md` without retaining branch-specific `BRANCH_DETAILS.md` files on `main`.
- For each branch, reassess existing `FORK.md` guidance against its current implementation and branch documentation; the old integration notes may be stale. Update the affected `FORK.md` sections during that branch's step. Include conflict-resolution glue and its documentation in the cherry-pick commit itself. Put any subsequent integration glue and its documentation together in a follow-up commit before picking the next branch. It is ok, and expected, to also update `FORK.md` in `base/fork` at every step with new commits there, so it remains mirror-synced with `main` after the rebuild.

## Report

- The base and branch commits used to rebuild `main`.
- Integration changes and the corresponding `FORK.md` updates for each branch.
- Behavior conflicts between worktree branches, including how they were resolved or what remains unresolved.
6 changes: 6 additions & 0 deletions .agents/skills/rebuild-main/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface:
display_name: "Rebuild Main"
short_description: "Rebuild local main from active-worktree commits."

policy:
allow_implicit_invocation: false
59 changes: 59 additions & 0 deletions .agents/skills/spawn-worktree/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
name: spawn-worktree
description: Orchestrate one subagent in a specified active worktree. Use to understand how to include minimal dispatch context, handle silent supervision, and terminal lease cleanup.
---

# Spawn one worktree subagent

This skill is for the orchestrator only. Keep its name, instructions, and orchestration context out of the child prompt.

Require a target worktree. If none was provided, report that and stop.

Before dispatch, read the main worktree's `.agents/skills/worktrees/SKILL.md`. Use it as the current worker contract when supervising the child. Do not copy its procedure into the child prompt. The child loads that file itself.

## Child prompt

Give the subagent exactly the context it needs:

- The absolute worktree path and an instruction to work only there.
- An instruction to read `BRANCH_DETAILS.md` at the worktree root, before acting and treat it as the complete branch-customization context. The worktree for `base/fork` is an exception, it should read `FORK.md` instead, and ignore customization sections explicitly attributed to other branches. Do not read these files yourself.
- The absolute path to the main worktree's `.agents/skills/worktrees/SKILL.md` and an instruction to load `$worktrees` directly from that path before desktop or mobile integrated verification. Do not copy or summarize the skill in the prompt.
- An instruction to use the fixed web and server ports from `BRANCH_DETAILS.md`, follow `$worktrees`, and validate the changes. When frontend behavior changes, run one integrated verification pass for each affected surface: `$test-t3-app` for web and `$test-t3-mobile` for mobile. Do not copy or summarize these skills in the prompt. Integrated UI verification is exempt from the `base/fork` branch, that worktree only runs typechecks and automated tests.
- A statement that the subagent works alone in its branch and worktree; no one else will change that worktree while it runs.
- The skills and task instructions the subagent must follow.

Mention only skills that the child must load. State its task directly.

Never name, reference, summarize, or frame the task through any skill you loaded. Keep the larger orchestration, its name, your current step or reasoning, future steps, other subagents and worktrees, `FORK.md` (except for the `base/fork` branch), and copied or inferred branch documentation out of the child prompt.

Bad: `Within the context of $update-worktrees, use $update-worktree to update this branch.`

Good: `Use $update-worktree to update this branch.`

Spawn with `fork_turns: "none"`.

## Silent supervision

Monitor the child until it reaches a confirmed terminal state. Ordinary progress, unchanged queue state, and long waits stay silent. Report only a concrete inconsistency with the worker contract and the correction you issued.

Compare the child's messages and the host ledgers with the current `$worktrees` instructions. Steer immediately when the child starts runtime work without the required lease, bypasses the desktop lease through another browser driver, holds capacity it is not actively using, stages the wrong source, uses shared Git transfer state, deletes a temporary worktree before releasing its path-scoped lease, or treats queue age as a reason to cancel or replace a request.

When the child reports fixing a typecheck or test failure that may come from host-specific paths, permissions, process behavior, filesystem semantics, or locale, ask it to double-check that exact failure against the same host's deterministic upstream-control manifest before accepting the fix. If the control branch reports the same failure, have the child undo only that environment-driven fix.

Queue order is not an orchestration concern. Never cancel, rephase, reprioritize, or coordinate a handoff merely because an older request is still waiting. A live child owns its requests. Intervene in queue state only after that child is confirmed terminal and left a holder or request behind.

When several children run, keep monitoring all of them while any remain live. A quiet worker is not terminal. Ask for a holder audit only when there is evidence that acquired capacity may be idle.

## Cleanup after a terminal result

You remain responsible for runtime-slot leak recovery. After the subagent reaches a confirmed completed or interrupted state, run this idempotent safeguard from the main worktree even if the subagent reported releasing its slots:

```sh
node "/absolute/path/to/main/scripts/worktree-runtime-slot.ts" \
cleanup \
--worktree /absolute/path/to/worktree
```

Keep this command and responsibility out of the child prompt. `cleanup` releases only slots owned by that exact worktree. Run it only after a confirmed terminal result; a timeout, stale listing, or quiet subagent is not terminal.

After every child is terminal, verify both host ledgers contain no holders or requests owned by the completed worktrees. Report the consolidated results only after this audit.
6 changes: 6 additions & 0 deletions .agents/skills/spawn-worktree/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface:
display_name: "Spawn Worktree"
short_description: "Dispatch and supervise one worktree agent."

policy:
allow_implicit_invocation: false
7 changes: 7 additions & 0 deletions .agents/skills/spawn-worktrees/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: spawn-worktrees
description: Spawn one subagent for every active non-main worktree.
disable-model-invocation: true
---

Inventory the repository's registered worktrees. Use `$spawn-worktree` once for each active non-main worktree, exclude also `base/main`; that skill is for you to load, not for your subagents. If none exist, report that there is nothing to spawn and stop.
6 changes: 6 additions & 0 deletions .agents/skills/spawn-worktrees/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface:
display_name: "Spawn Worktrees"
short_description: "Spawn one agent for every active non-main worktree."

policy:
allow_implicit_invocation: false
41 changes: 37 additions & 4 deletions .agents/skills/test-t3-app/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ the panel reports unavailable, explain the blocker and stop verification.
Do not install or switch to another automation system. For native mobile
testing, use [test-t3-mobile](../test-t3-mobile/SKILL.md).

Load `$worktrees` for host selection, exact-source staging, and runtime ownership. Acquire the selected browser host's `desktop` lease before integrated UI interaction, and release it after closing owned tabs. Starting a server alone needs no lease.

## Start the app

Reuse this task's healthy dev server. Otherwise run `vp run dev` from the
repository root and retain its terminal session. Use the worktree's ignored
`.t3` state and read the actual ports and pairing URL from the dev-runner output.
Never run against `~/.t3/userdata` or set `VITE_HTTP_URL` or `VITE_WS_URL`.
Reuse this task's healthy dev server. Otherwise run `vp run dev` from the repository root and retain its terminal session. When verifying a standalone feature worktree, invoke `node "<main-worktree>/scripts/dev-runner.ts" dev` from that worktree so current orchestration launches its source without copying infrastructure changes into the branch. Use the worktree's ignored `.t3` state and read the actual ports and pairing URL from the dev-runner output. Never run against `~/.t3/userdata` or set `VITE_HTTP_URL` or `VITE_WS_URL`.

Test with meaningful project and thread data. Read
[references/sqlite-fixtures.md](references/sqlite-fixtures.md) only when
inspecting or seeding SQLite. Stop the test server before direct fixture writes.

## Use the Browser panel

Follow the host selection in `$worktrees` before the first control call. Native subagent callers have independent preview contexts while their tabs remain visible in the main conversation. Keep returned tab IDs for this test; an explicit `tabId` deliberately shares a target, so use only owned tabs during verification. Providers that omit native caller metadata share their credential's default context.

Call `preview_status`, then `preview_open` if the Browser panel is
closed. Navigate to the complete startup pairing URL once with
`preview_navigate`, then use `preview_snapshot` and T3's interaction tools.
Expand All @@ -39,3 +40,35 @@ using retained terminal sessions or captured PIDs.
When sharing is requested, start with `vp run dev --share` and give the user
a fresh complete pairing URL that you have not consumed. Keep other credentials
out of screenshots, commits, and replies.

### Route a worktree server through collaborative preview

When driving a Windows-hosted `vp run dev` through T3 Code's collaborative preview, treat the preview as another tailnet consumer and launch with `--share` from the outset. Read the actual `webPort` and shared HTTPS origin from the current `[dev-runner]` line. Call `preview_status` first; if no automation-capable tab exists, call `preview_open` without a URL and retain its returned tab id. Navigate that tab to the shared origin and confirm the app loads before pairing, then navigate the same tab to the exact shared pairing URL.

If the shared origin returns 502 while loopback HTTP is healthy, compare the Vite listener with `tailscale serve status --json`. An older worktree can leave the proxy targeting `http://127.0.0.1:<web-port>` while Vite listens only on `::1`. Stop only the exact test-owned mapping with `tailscale serve --https=<share-port> off`, then recreate it with `tailscale serve --bg --https=<share-port> http://localhost:<web-port>`; an explicit `http://[::1]:<web-port>` is also valid when the listener is known. Verify the bare shared origin before issuing or consuming a pairing token. Current main-owned sharing uses `localhost` automatically, so do not keep restarting the app once an older branch's address-family mismatch is proven.

The environment-port bridge can translate the Windows loopback URL to the host's tailnet IP while Vite remains bound only to `127.0.0.1`. The translated URL then refuses the connection, the preview eventually reports `chrome-error://chromewebdata/`, and `preview_navigate` may time out even though loopback HTTP is healthy. Do not retry that route or diagnose the app; restart the test-owned stack with `--share` if it was not already shared, issue a fresh token, and use the verified shared HTTPS origin.

On a host where the preview and worktree have a verified direct environment route, read the actual `webPort` from `[dev-runner]` and use the environment-port bridge. Call `preview_status` first; if no automation-capable tab exists, call `preview_open` without a URL and retain its returned tab id. Navigate the initialized tab with `preview_navigate`:

```json
{
"tabId": "<returned-tab-id>",
"target": {
"kind": "environment-port",
"port": 5733,
"path": "/pair#token=<token>"
}
}
```

Replace `5733` with the selected worktree web port. Preserve the complete pairing path and fragment, navigate it exactly once, and continue in the same tab. For an already authenticated tab, use the same target with the required non-secret path.

Do not pass a loopback pairing URL such as `http://127.0.0.1:<web-port>/pair#token=...` directly to `preview_open` or `preview_navigate`. Use `--share` whenever the controlled preview, a human, or another device is not in the checkout host's direct network namespace.
Retain the `tabId` of each tab created for this test. At final teardown, close only those owned tabs with `preview_close`, passing each `tabId` explicitly, before stopping the test environment. Confirm each close returns `tabId: null`.

### Diagnose transport failures

For HTTP 431, retain the Vite warning and compare the same request path with and without a synthetic cookie header of the observed byte length. Record only sizes and cookie names, never credential values. Cookies are scoped by hostname, not port, so concurrent worktrees on one host accumulate cookies. The current main dev runner supplies a 64 KiB Node header limit while honoring an explicit `NODE_OPTIONS` limit. Restart only the task-owned stack through that runner when an older branch still uses Node's default. Clearing all browser cookies would disrupt unrelated worktrees.

For a snapshot timeout, retain the request ID and determine whether the renderer received it and whether desktop capture began. A host connection dropping before capture is not proof of a native capture failure. Recheck the selected host after it reconnects and retry once on an owned tab; report a repeated stall with the request stages instead of restarting the user's desktop or changing feature code.
3 changes: 3 additions & 0 deletions .agents/skills/test-t3-app/agents/openai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ interface:
display_name: "T3 App Testing"
short_description: "Test web and desktop in T3's Browser panel"
default_prompt: "Use $test-t3-app to verify the affected web or desktop flow through T3's Browser panel."

policy:
allow_implicit_invocation: true
13 changes: 12 additions & 1 deletion .agents/skills/test-t3-app/references/sqlite-fixtures.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Load this reference only when inspecting or seeding local T3 state directly.

## Select the correct database

When `--base-dir` or `--home-dir` is explicit, runtime state lives under `<base-dir>/userdata` and the database path is `<base-dir>/userdata/state.sqlite`. The `<base-dir>/dev` state directory is only the fallback for an implicit development home, preventing an ordinary `vp run dev` from touching production state.
When `--base-dir` or `--home-dir` is explicit, runtime state lives under `<base-dir>/userdata`. Hot projections and runtime state are stored in `state.sqlite`; cold archive manifests and compressed chunks are stored in `archive.sqlite`. The `<base-dir>/dev` state directory is only the fallback for an implicit development home, preventing an ordinary `vp run dev` from touching production state.

Start the target runtime once before seeding so all migrations have run. Use an isolated base directory. Stop the server before writes to avoid racing application state or an active projection.

Expand All @@ -18,6 +18,15 @@ node apps/server/scripts/t3-sqlite-state.ts query \
--sql "SELECT name FROM sqlite_schema WHERE type = 'table' ORDER BY name"
```

The helper targets `state.sqlite` by default. Select the cold archive database explicitly for read-only inspection:

```bash
node apps/server/scripts/t3-sqlite-state.ts query \
--base-dir <base-dir> \
--database archive \
--sql "SELECT t.thread_id, t.archive_version, COUNT(c.chunk_index) AS chunk_count FROM archive_threads AS t LEFT JOIN archive_thread_chunks AS c ON c.thread_id = t.thread_id GROUP BY t.thread_id, t.archive_version ORDER BY t.thread_id"
```

Inspect current columns before writing a fixture:

```bash
Expand All @@ -36,6 +45,8 @@ node apps/server/scripts/t3-sqlite-state.ts exec \

Use one statement per invocation for both `query` and `exec`; the helper wraps writes in a transaction and prints the backup path after a successful mutation. Use a single insert with multiple value rows when a fixture needs several records.

Cold archive manifests and chunks are authoritative recovery data. Prefer `--database archive` for queries only. Exercise archive and restore behavior through application commands and APIs instead of constructing or changing archive bundles directly; only use archive writes for a deliberately isolated corruption or compatibility fixture.

## Seed projection data carefully

The web UI primarily reads these projection tables:
Expand Down
Loading
Loading