Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
08abe2d
fix(client-runtime): keep a warm thread un-settled despite a merged/c…
t3dotgg Jul 23, 2026
08d96c6
Fix composer context strip alignment and glass shell (#4404)
juliusmarminge Jul 23, 2026
34fdfa1
Polish iOS git progress overlay with glass effects (#4387)
juliusmarminge Jul 23, 2026
083e9cf
Improve composer glass fallbacks (#4406)
juliusmarminge Jul 23, 2026
eed8c32
feat(web): collapse large git diffs by default to make chat more read…
t3dotgg Jul 24, 2026
bbbaca6
Stop new threads inheriting checkout/branch from viewed thread (#4411)
t3dotgg Jul 24, 2026
291285d
fix: tone down branch-mismatch banner (#4416)
t3dotgg Jul 24, 2026
1c0255f
fix: Claude Code skills discoverable for the composer $ picker (#4414)
t3dotgg Jul 24, 2026
7fe7a67
fix(web): keep settled threads reachable when opened directly (#4413)
t3dotgg Jul 24, 2026
2887b43
feat(sidebar-v2): thread snoozing (#4311)
t3dotgg Jul 24, 2026
c7db66e
Upgrade Clerk packages and Expo integration (#4440)
juliusmarminge Jul 24, 2026
e667835
Increase light-mode contrast for user message bubbles (#4441)
juliusmarminge Jul 24, 2026
3a32ef6
Restore model picker layout and retain iterative test state (#4450)
juliusmarminge Jul 24, 2026
f286b50
Color settled PR labels on hover (#4451)
juliusmarminge Jul 24, 2026
3dec2e9
[codex] Fix glass hover compositing artifacts (#4446)
juliusmarminge Jul 24, 2026
ebd1e8c
Add Claude Opus 5 model (#4472)
thomaslittle Jul 24, 2026
c42ee1e
feat(web): add collapse-all toggle to diff panel (#4475)
0x4bs3nt Jul 24, 2026
b4356cf
feat(web): show fast mode as a bolt instead of a "Normal" label (#4488)
t3dotgg Jul 25, 2026
bbab068
fix(sync): preserve Droid medium-access with Auto runtime mode
cursoragent Jul 25, 2026
093e193
fix(sync): restore fork release and runtime-mode adaptations
cursoragent Jul 25, 2026
d3c4aed
fix(sync): refresh lockfile after Clerk upgrade restack
cursoragent Jul 25, 2026
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
24 changes: 21 additions & 3 deletions .agents/skills/test-t3-app/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: test-t3-app
description: Launch and test the T3 Code web app in isolated development environments, including first-try browser authentication with one-time pairing URLs, pairing-token recovery, worktree-safe state directories, dev server lifecycle, and direct SQLite inspection or fixture seeding. Use when an agent needs to run T3 locally, test UI behavior in a browser, recover from an expired or consumed pairing token, isolate dev state, or prepare test data in state.sqlite.
description: Launch, retain, and test the T3 Code web app in isolated development environments, including first-try browser authentication with one-time pairing URLs, pairing-token recovery, worktree-safe state directories, cross-turn dev server lifecycle, and direct SQLite inspection or fixture seeding. Use when an agent needs to run T3 locally, iteratively test UI behavior with a human, recover from an expired or consumed pairing token, isolate dev state, or prepare test data in state.sqlite.
---

# Test T3 App
Expand All @@ -20,6 +20,16 @@ Treat a base directory as disposable only when it was created or deliberately se

The dev runner disables browser auto-open by default. Do not pass `--browser` during automated testing: an automatically opened page can consume the one-time bootstrap token before the controlled browser uses it.

## Preserve the environment while iterating

Treat the overall testing or implementation loop—not an assistant turn or one verification pass—as the environment lifecycle boundary.

- Keep the dev process, base directory, selected ports, authenticated browser tab, registered projects, and seeded fixtures alive while the user may inspect the result or request follow-up changes.
- Do not stop the server merely because one verification pass completed or because you are yielding a response to the user.
- Before starting another environment, check whether the existing process and browser tab still serve the task. Reuse them when healthy instead of discarding useful state.
- On a later turn, verify that the existing process is alive and reuse its printed ports and base directory. If it exited, restart with the same base directory; create a new pairing token only when the browser session is no longer valid.
- Tell the user when a test environment remains available, including its non-secret web URL when useful. Never include a pairing token.

## Authenticate the browser on the first navigation

1. Wait for the server log that says authentication is required and includes a URL ending in `/pair#token=...`.
Expand Down Expand Up @@ -58,9 +68,17 @@ Read [references/sqlite-fixtures.md](references/sqlite-fixtures.md) before chang

The helper refuses to write to the shared `~/.t3` directory by default and creates a database backup before each mutation.

## Finish the test
## Tear down only when the testing loop is finished

Tear down when the user explicitly asks, confirms the iteration is finished, or the overall task is genuinely complete with no pending human review. Do not infer completion from the end of an assistant turn.

When teardown is appropriate:

1. Stop the dev process with its terminal interrupt.
2. Preserve the isolated base directory when it contains useful reproduction evidence or state for a likely follow-up.
3. Otherwise remove only a path created for this test after resolving and verifying the exact target.

Stop the dev process with its terminal interrupt. Preserve the isolated base directory when it contains useful reproduction evidence; otherwise remove only a path that was created for this test after resolving and verifying the exact target. A fresh isolated base directory is the safest reset when authentication, migrations, or fixture state becomes ambiguous.
If completion is uncertain, keep the environment alive and mention that it is retained for further iteration. A fresh isolated base directory remains the safest reset when authentication, migrations, or fixture state becomes ambiguous.

## Troubleshoot predictably

Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/test-t3-app/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface:
display_name: "T3 App Testing"
short_description: "Launch and seed isolated T3 test environments"
default_prompt: "Use $test-t3-app to launch an isolated T3 development environment and test it in the browser."
short_description: "Launch and retain isolated T3 test environments"
default_prompt: "Use $test-t3-app to launch an isolated T3 environment and iteratively test it in the browser while preserving state."
117 changes: 90 additions & 27 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ on:
type: string

permissions:
contents: read
contents: write
id-token: none

env:
T3CODE_RELEASE_REPOSITORY: aaditagrawal/t3code
T3CODE_DESKTOP_UPDATE_REPOSITORY: aaditagrawal/t3code

jobs:
check_changes:
name: Check for changes since last nightly
Expand Down Expand Up @@ -78,6 +82,7 @@ jobs:
cli_dist_tag: ${{ steps.release_meta.outputs.cli_dist_tag }}
is_prerelease: ${{ steps.release_meta.outputs.is_prerelease }}
make_latest: ${{ steps.release_meta.outputs.make_latest }}
release_repository: ${{ steps.release_meta.outputs.release_repository }}
ref: ${{ github.sha }}
steps:
- name: Checkout
Expand Down Expand Up @@ -105,6 +110,20 @@ jobs:
NIGHTLY_SHA: ${{ github.sha }}
NIGHTLY_RUN_NUMBER: ${{ github.run_number }}
run: |
release_repository="${T3CODE_RELEASE_REPOSITORY:?T3CODE_RELEASE_REPOSITORY is required}"
desktop_update_repository="${T3CODE_DESKTOP_UPDATE_REPOSITORY:?T3CODE_DESKTOP_UPDATE_REPOSITORY is required}"
for repository in "$release_repository" "$desktop_update_repository"; do
if [[ ! "$repository" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
echo "Invalid release repository: $repository" >&2
exit 1
fi
done
if [[ "$GITHUB_REPOSITORY" != "$release_repository" || "$GITHUB_REPOSITORY" != "$desktop_update_repository" ]]; then
echo "This fork release workflow is configured for release repository $release_repository and desktop updater repository $desktop_update_repository, but it is running in $GITHUB_REPOSITORY." >&2
exit 1
fi
echo "release_repository=$release_repository" >> "$GITHUB_OUTPUT"

if [[ "${GITHUB_EVENT_NAME}" == "schedule" || ( "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && "${DISPATCH_CHANNEL:-stable}" == "nightly" ) ]]; then
nightly_date="$(date -u -d "$NIGHTLY_DATE" +%Y%m%d)"

Expand Down Expand Up @@ -204,6 +223,7 @@ jobs:

- id: relay_state
name: Read production relay tracing config
continue-on-error: true
shell: bash
run: |
vp run --filter t3code-relay deploy \
Expand All @@ -213,15 +233,17 @@ jobs:
--github-env-file "$RUNNER_TEMP/relay-client-tracing.env"

- name: Upload relay client tracing config
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: relay-client-tracing-config
path: ${{ runner.temp }}/relay-client-tracing.env
if-no-files-found: error
if-no-files-found: warn
retention-days: 1

- id: public_config
name: Resolve production relay public config
if: always()
shell: bash
run: |
set -euo pipefail
Expand All @@ -243,8 +265,13 @@ jobs:
fi
done
if (( ${#missing[@]} > 0 )); then
printf 'Missing required relay deployment configuration: %s\n' "${missing[*]}" >&2
exit 1
# Fork: relay/Clerk production config is optional for desktop releases.
printf 'Relay public config unavailable (%s); continuing without hosted relay wiring.\n' "${missing[*]}" >&2
echo "clerk_publishable_key=" >> "$GITHUB_OUTPUT"
echo "clerk_jwt_template=" >> "$GITHUB_OUTPUT"
echo "clerk_cli_oauth_client_id=" >> "$GITHUB_OUTPUT"
echo "relay_url=" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "clerk_publishable_key=$CLERK_PUBLISHABLE_KEY" >> "$GITHUB_OUTPUT"
Expand All @@ -262,7 +289,11 @@ jobs:
name: Build WSL node-pty (linux-x64)
needs: [preflight]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
# Build against Debian bullseye glibc (≈ Ubuntu 20.04) so the bundled WSL
# native addon loads on common Ubuntu 20.04/22.04 WSL distros. N-API covers
# Node ABI, not libc ABI. Use a standard GitHub-hosted runner + Node bullseye
# container instead of Blacksmith Ubuntu 2004 labels, which can queue forever.
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Checkout
Expand All @@ -283,11 +314,16 @@ jobs:
run: |
set -euo pipefail
# Resolve node-pty from apps/server (where it's a dependency) and build
# its native binary from source for Linux. node-addon-api resolves from
# node-pty's own dependency tree, so node-gyp has everything it needs.
# its native binary from source for Linux against an older glibc. node-
# addon-api resolves from node-pty's own dependency tree inside the
# mounted workspace, so node-gyp has everything it needs.
pty_pkg="$(node -e "console.log(require.resolve('node-pty/package.json', { paths: ['$GITHUB_WORKSPACE/apps/server'] }))")"
pty_dir="$(dirname "$pty_pkg")"
( cd "$pty_dir" && npx --yes node-gyp rebuild )
docker run --rm \
-v "$GITHUB_WORKSPACE:$GITHUB_WORKSPACE" \
-w "$pty_dir" \
node:24.13.1-bullseye \
bash -lc 'apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq build-essential python3 >/dev/null && npx --yes node-gyp rebuild'
mkdir -p wsl-prebuild
cp "$pty_dir/build/Release/pty.node" wsl-prebuild/pty.node
file wsl-prebuild/pty.node
Expand All @@ -303,20 +339,15 @@ jobs:
name: Build ${{ matrix.label }}
# build_wsl_node_pty stays in `needs` so it runs first and its artifact is
# available to download, but only the Windows matrix entry consumes it. We
# therefore gate the job on preflight + relay (must succeed) WITHOUT requiring
# build_wsl_node_pty, so a failed Linux prebuild doesn't skip the macOS/Linux
# builds. `!cancelled()` (not `!failure()`) lets the job run even when
# build_wsl_node_pty failed; the Windows-only download step below then fails
# that single platform if the prebuild is missing.
needs: [preflight, relay_public_config, build_wsl_node_pty]
if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' }}
# Gate the job on preflight only (fork: no relay requirement). `!cancelled()`
# (not `!failure()`) lets macOS/Linux builds run even when build_wsl_node_pty
# failed; the Windows-only download step below then fails that single
# platform if the prebuild is missing.
needs: [preflight, build_wsl_node_pty]
# Fork: desktop builds must not depend on upstream relay/Clerk production config.
if: ${{ !cancelled() && needs.preflight.result == 'success' }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
env:
T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }}
T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }}
T3CODE_CLERK_CLI_OAUTH_CLIENT_ID: ${{ needs.relay_public_config.outputs.clerk_cli_oauth_client_id }}
T3CODE_RELAY_URL: ${{ needs.relay_public_config.outputs.relay_url }}
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -361,6 +392,7 @@ jobs:
run-install: true

- name: Download relay client tracing config
continue-on-error: true
uses: actions/download-artifact@v8
with:
name: relay-client-tracing-config
Expand All @@ -370,6 +402,10 @@ jobs:
shell: bash
run: |
config_path="$RUNNER_TEMP/relay-client-tracing/relay-client-tracing.env"
if [[ ! -f "$config_path" ]]; then
echo "No relay client tracing config artifact; continuing without it."
exit 0
fi
tracing_token="$(sed -n 's/^T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=//p' "$config_path")"
echo "::add-mask::$tracing_token"
cat "$config_path" >> "$GITHUB_ENV"
Expand Down Expand Up @@ -608,7 +644,8 @@ jobs:
publish_cli:
name: Publish CLI to npm
needs: [preflight, relay_public_config, build]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' && needs.build.result == 'success' }}
# Fork: do not publish the globally named upstream npm package from this repo.
if: false
runs-on: ubuntu-24.04 # blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
permissions:
Expand Down Expand Up @@ -637,6 +674,7 @@ jobs:
- --filter=@t3tools/scripts...

- name: Download relay client tracing config
continue-on-error: true
uses: actions/download-artifact@v8
with:
name: relay-client-tracing-config
Expand All @@ -646,6 +684,10 @@ jobs:
shell: bash
run: |
config_path="$RUNNER_TEMP/relay-client-tracing/relay-client-tracing.env"
if [[ ! -f "$config_path" ]]; then
echo "No relay client tracing config artifact; continuing without it."
exit 0
fi
tracing_token="$(sed -n 's/^T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=//p' "$config_path")"
echo "::add-mask::$tracing_token"
cat "$config_path" >> "$GITHUB_ENV"
Expand All @@ -664,8 +706,8 @@ jobs:

release:
name: Publish GitHub Release
needs: [preflight, build, publish_cli]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build.result == 'success' && needs.publish_cli.result == 'success' }}
needs: [preflight, build]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build.result == 'success' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
steps:
Expand Down Expand Up @@ -700,15 +742,29 @@ jobs:

- name: Merge macOS updater manifests
run: |
set -euo pipefail
shopt -s nullglob

found_mac_manifest=false
for x64_manifest in release-assets/*-mac-x64.yml; do
arm64_manifest="${x64_manifest%-x64.yml}.yml"
if [[ -f "$arm64_manifest" ]]; then
node scripts/merge-update-manifests.ts --platform mac "$arm64_manifest" "$x64_manifest"
rm -f "$x64_manifest"
arm64_manifest="${x64_manifest/-x64.yml/.yml}"
if [[ ! -f "$arm64_manifest" ]]; then
echo "Missing matching arm64 macOS manifest for $x64_manifest" >&2
exit 1
fi

found_mac_manifest=true
node scripts/merge-update-manifests.ts --platform mac \
"$arm64_manifest" \
"$x64_manifest"
rm -f "$x64_manifest"
done

if [[ "$found_mac_manifest" != true ]]; then
echo "No macOS updater manifests found to merge." >&2
exit 1
fi

# - name: Merge Windows updater manifests
# run: |
# shopt -s nullglob
Expand Down Expand Up @@ -745,6 +801,7 @@ jobs:
tag_name: ${{ needs.preflight.outputs.tag }}
target_commitish: ${{ needs.preflight.outputs.ref }}
name: ${{ needs.preflight.outputs.release_name }}
repository: ${{ needs.preflight.outputs.release_repository }}
generate_release_notes: true
previous_tag: ${{ needs.preflight.outputs.previous_tag }}
prerelease: ${{ needs.preflight.outputs.is_prerelease }}
Expand All @@ -766,6 +823,7 @@ jobs:
tag_name: ${{ needs.preflight.outputs.tag }}
target_commitish: ${{ needs.preflight.outputs.ref }}
name: ${{ needs.preflight.outputs.release_name }}
repository: ${{ needs.preflight.outputs.release_repository }}
generate_release_notes: true
prerelease: ${{ needs.preflight.outputs.is_prerelease }}
make_latest: ${{ needs.preflight.outputs.make_latest }}
Expand Down Expand Up @@ -814,6 +872,7 @@ jobs:
- --filter=@t3tools/web...

- name: Download relay client tracing config
continue-on-error: true
uses: actions/download-artifact@v8
with:
name: relay-client-tracing-config
Expand All @@ -823,6 +882,10 @@ jobs:
shell: bash
run: |
config_path="$RUNNER_TEMP/relay-client-tracing/relay-client-tracing.env"
if [[ ! -f "$config_path" ]]; then
echo "No relay client tracing config artifact; continuing without it."
exit 0
fi
tracing_token="$(sed -n 's/^T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=//p' "$config_path")"
echo "::add-mask::$tracing_token"
cat "$config_path" >> "$GITHUB_ENV"
Expand Down
Loading
Loading