Skip to content

ci(mobile): publish nightly Android APKs to a GitHub prerelease - #16271

Merged
juliusmarminge merged 4 commits into
pingdotgg:mainfrom
SunkenInTime:ci/android-apk-mirror
Oct 11, 2026
Merged

juliusmarminge merged 4 commits into
pingdotgg:mainfrom
SunkenInTime:ci/android-apk-mirror

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

What Changed

  • New .github/workflows/mobile-android-apk.yml: runs hourly, plus manual dispatch.
  • New .github/scripts/mirror-play-apk.cjs: plain Node, no dependencies.
  • A short "Android APK mirror" section in docs/operations/release.md.

Each run reads the newest live build on the Play v2 closed testing track (where eas.json submits v2-preview builds) and downloads the universal APK that Google Play generated and signed for it. It then keeps that APK on a rolling android-nightly prerelease, with only the newest build kept. The release page, releases/tag/android-nightly, is a fixed link to hand to nightly users.

Why

Nightly servers run the Orchestrator V2 protocol, which the Play Store release of the app can't talk to. Nightly users need the v2-preview build from the Play testing group, but the group isn't letting people join right now, and we couldn't offer an APK because Play App Signing holds the key. Play already generates a universal APK signed with that key for every uploaded bundle (docs), so CI only has to fetch it. No signing key goes into GitHub, and the APK has the same signature as the Play Store install.

Design notes:

  • Polls instead of chaining off mobile-eas-production.yml. EAS builds and submits with --no-wait, so CI never learns when the bundle reaches Play. A run with nothing new does no writes.
  • Doesn't open a Play edit. It reads the track through the edit-free tracks.releases.list endpoint. Play allows one open edit per account, so an edit-based read could invalidate an in-flight EAS submission if the two shared a service account.
  • Kept away from other release consumers. The prerelease's android-nightly tag doesn't start with v, and it's created with --latest=false. release.yml, the desktop updater, the CLI release lookup, and the marketing site's releases/latest all ignore it. Same idea as the existing desktop-preview release.
  • Recovers from failed runs. An empty asset left by a failed upload doesn't count as published. Cleanup of the previous APK and the notes runs every time, so an interrupted run finishes on the next one.
  • Refuses ambiguous signatures. If Play returns more than one universal APK (one per signing key, after a key rotation), the run fails instead of guessing.

Out of scope: a stable APK mirrored from the production track, and linking the APK from the Nightly tab on t3.codes/download. Both are easy follow-ups; this PR covers only the immediate problem.

Setup needed (maintainers)

Add a repo secret GOOGLE_PLAY_SERVICE_ACCOUNT_JSON with a Play service account key. The account needs the "Release to production, exclude devices, and use Play App Signing" permission to download generated APKs. Reusing EAS Submit's service account is fine. Until the secret exists, the job skips itself.

Verification

No Play credentials were available, so these checks stand in for a real Play run:

  • Real GitHub Actions run. The workflow ran unchanged in a private scratch repo on a stock runner, with only Google's endpoints mocked. These passed:

    • no secret: the job skips itself
    • first publish
    • rerun with nothing new: no writes
    • leftover old APK and stale notes: repaired on the next run
    • newer build: replaces the old APK
    • two signing keys: fails and leaves the release untouched

    A decoy stable release stayed "Latest" throughout.

  • Play API contract. Every endpoint, field, enum, and type was checked against Google's machine-readable API definition. Google's Go and Node clients and fastlane's download_universal_apk_from_google_play build the same download request (:download?alt=media).

  • Token format. Sent to Google's real token endpoint with a throwaway key, it was rejected only for the unknown account ("account not found"). A malformed token gets invalid_request instead.

Not yet proven, and settled by the first real run after the secret is added:

  • how Play responds while it's still generating the APK (an error rather than an empty list would fail that run, and the next hourly run retries)
  • the exact release name EAS's submission service sets (cosmetic, it only affects the APK file name)

Run the workflow once with Run workflow after adding the secret.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (no UI changes)
  • I included a video for animation/interaction changes (none)

Taken over and rebased onto current main by @juliusmarminge: the Play submit track was renamed from alpha to the v2 closed testing track in #2829, so the workflow and release docs now poll v2. The Play API contract and token smoke test were re-verified against Google's current API definition.

Done by Claude Opus 5.5 (1M context) in Claude Code, running in T3 Code, with review and research by gpt-6-astra.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 6, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This adds an hourly, credentialed Google Play-to-GitHub release pipeline that downloads signed Android APKs and mutates a rolling prerelease, creating a new distribution capability and operational side effects. The workflow and external integration warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b44878da-e6b4-4525-89e0-77d686d23b72


📥 Commits

Reviewing files that changed from the base of the PR and between 0de3187 and f5688d7.



📒 Files selected for processing (1)
  • .github/workflows/mobile-android-apk.yml


🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/mobile-android-apk.yml


Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.




📝 Walkthrough
📝 Walkthrough

Walkthrough

Adds a scheduled and manually triggered workflow that checks the Google Play alpha track and mirrors its newest published universal APK to the rolling android-nightly GitHub prerelease.

Changes

Android APK mirror

Layer / File(s) Summary
Workflow entry and configuration
.github/workflows/mobile-android-apk.yml, docs/operations/release.md
The workflow runs hourly or on manual dispatch. It skips checkout and mirroring when the service-account secret is absent. The documentation describes the track, prerelease, signing, and permission requirements.
Play authentication and build selection
.github/scripts/mirror-play-apk.cjs
The script authenticates with a service-account JWT and reads published releases and active artifacts. It selects the build with the greatest version code.
APK and prerelease update
.github/scripts/mirror-play-apk.cjs
The script downloads the build’s universal APK and creates or updates the prerelease. It skips an existing nonempty matching asset, removes other APK assets, and updates changed release notes.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as Mobile Android APK workflow
  participant Script as mirror-play-apk.cjs
  participant OAuth as Google OAuth token endpoint
  participant Play as Android Publisher API
  participant Release as GitHub Release
  Workflow->>Script: Run with package, track, release tag, and credentials
  Script->>OAuth: Exchange signed service-account JWT
  OAuth-->>Script: Return access token
  Script->>Play: Read published track releases
  Play-->>Script: Return active artifacts and version codes
  Script->>Play: Download selected build's universal APK
  Play-->>Script: Return APK
  Script->>Release: Create or update release and APK assets
  Script->>Release: Update release notes when they differ
Loading


Merge Risk: ⚪ Minimal · up to f5688

No actionable merge-blocking issue was identified in the nightly APK workflow. It is ready for normal checks and the planned credential setup.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 0de31

The publication and recovery design includes useful safeguards, but manual execution can run selected-branch code with both Play credentials and repository write authority. The permissions and branch protections governing that access remain unverified, so the security assessment is conditional rather than a confirmed vulnerability.

Retained concerns

  • Medium · security · inferred: Manual dispatch introduces a conditional source-ref-to-credential boundary: the selected ref supplies executable script code that receives both the Play service-account key and repository write authority. No trusted-ref restriction or protected environment is declared in this workflow. This is an unresolved control concern, not a verified externally reachable attack.
Security review details

Security Blast Radius

  • inferred — Compromised execution could affect repository contents and releases within the GitHub token’s effective authority, and every Play application authorized to the supplied service account. Fixed package and tag values constrain honest execution, not malicious checked-out code. Actual Play grants and repository restrictions are unavailable.

Security Findings and Attack Paths

  • inferred — The conditional attack path requires control of a selected ref, permission to dispatch it, and credential availability during execution. There is no pull-request trigger or public workflow input. The supplied candidate remains deferred because these authorization conditions are unresolved; no verified Security finding is established.

Trust Boundaries and Controls

  • observed — The service-account JSON is trusted configuration: its token_uri becomes both JWT audience and POST destination without endpoint validation. The request sends a signed assertion, not the private key itself. No attacker-controlled source for that secret value is established.
  • observed — Fresh downloads use an authenticated fixed Google API base, reject multiple universal APK candidates, sanitize the release-name portion of the filename, and invoke the GitHub CLI through argument arrays rather than shell interpolation.

Resilience and Maintainability Implications

  • observed — The repeat path trusts an existing asset by filename, uploaded state, and nonzero size; it does not revalidate Play signing-key ambiguity or cryptographic provenance. Existing release state is accepted by tag without an ownership marker or prerelease-status check. No poisoned asset, ownership collision, or already-published key-rotation case is established.

Hardening Proposals

  • proposed — Make the privileged execution boundary explicit by restricting manual runs to trusted workflow and script revisions or a protected environment, and confirm that effective Play grants and repository permissions match the intended publication scope.
  • proposed — Consider validating the Google token endpoint and documenting exclusive ownership of the rolling release. If independent release writers are permitted, add ownership and APK provenance checks before trusting or deleting existing assets.

Pre-merge checks | Passed 3 | Failed 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 1 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check Warning The description explains the problem, implementation, scope, setup, verification, limitations, and agent usage. However, it does not include the required Scope and approval section or link a triaged i… Add a Scope and approval section. Link the triaged issue or discussion that approved the direction and scope, including the maintainer approval comment. If no prior approval exists, obtain it or explain why this change qualifies for an exem…
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly and concisely identifies the main change: publishing nightly Android APKs through CI to a GitHub prerelease.

Full details: Docstring Coverage

Explanation

Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 1 files. (1 skipped: 1 unsupported.)


Full details: Description check

Explanation

The description explains the problem, implementation, scope, setup, verification, limitations, and agent usage. However, it does not include the required Scope and approval section or link a triaged issue or explicit maintainer approval for this broader workflow change.

Resolution

Add a Scope and approval section. Link the triaged issue or discussion that approved the direction and scope, including the maintainer approval comment. If no prior approval exists, obtain it or explain why this change qualifies for an exemption.


  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR



  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@SunkenInTime SunkenInTime changed the title ci(mobile): publish Google-signed Android APKs to a GitHub prerelease ci(mobile): publish nightly Android APKs to a GitHub prerelease Oct 6, 2026
@SunkenInTime

Copy link
Copy Markdown
Contributor Author

@coderabbitai Re the retained manual-dispatch concern: not changing this. Only users with write access can dispatch a workflow, and the same users can already push a branch whose workflow reads any repository secret, since GOOGLE_PLAY_SERVICE_ACCOUNT_JSON is a repository secret rather than an environment-protected one. A ref check in this workflow would not close that path. mobile-eas-production.yml follows the same model with EXPO_TOKEN and accepts branch dispatches. If maintainers want the key scoped tighter, the right fix is a protected environment, which is a repo settings change, not a code change.

@coderabbitai

coderabbitai Bot commented Oct 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd --hidden --type f '^(mobile-eas-production|mobile-android-apk)\.yml$' . --exec bash -c '
for file do
  printf "\n--- %s ---\n" "$file"
  ast-grep outline "$file" || true
  sed -n "1,240p" "$file"
done
' bash {} +

Length of output: 13199


🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd --hidden --type f '^(mobile-eas-production|mobile-android-apk)\.yml$' . --exec bash -c '
set -euo pipefail
file="$1"
printf "\n--- %s ---\n" "$file"
ast-grep outline "$file"
sed -n "1,155p" "$file"
' bash {}

Length of output: 8927


@SunkenInTime Thanks for the clarification. I checked both workflows. .github/workflows/mobile-eas-production.yml explicitly supports branch dispatches and uses EXPO_TOKEN without a protected environment.

You are right: a ref check in this workflow would not prevent a write-access user from creating another workflow that reads the repository secret. I withdraw the manual-dispatch finding. No change is needed for this concern.

A tighter secret-access boundary would require an environment-scoped secret with protection rules configured in repository settings.


✏️ Learnings added
Learnt from: SunkenInTime
URL: https://github.com/pingdotgg/t3code/pull/16271

Timestamp: 2026-10-06T17:32:56.679Z
Learning: In pingdotgg/t3code, `.github/workflows/mobile-android-apk.yml` intentionally permits manual branch dispatches with the repository-level `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON` secret. `.github/workflows/mobile-eas-production.yml` follows the same trust model with `EXPO_TOKEN` and explicitly supports branch dispatches. Do not recommend a workflow-local ref check as a boundary against repository-secret access by write-access users, who can create another workflow that reads the secret. Stronger isolation requires moving the secret to a protected environment and configuring its protection rules in repository settings.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Copy link
Copy Markdown
Member

Note

This comment is posted by Julius' dot

This adds an hourly Play-to-GitHub APK distribution workflow and a new rolling release, but the PR has no linked maintainer approval for that direction and scope. Closing under the prior-approval rule. Discuss the release channel and credential requirements with maintainers in Ideas, then link their approval when requesting reconsideration.

SunkenInTime and others added 3 commits October 11, 2026 14:36
Testers who can't join the Play testing group have no way to install the
Android app. Play App Signing holds the signing key, so CI can't sign an
APK itself, but Play generates and signs a universal APK for every uploaded
bundle.

An hourly workflow reads the newest live build on the alpha track, downloads
that universal APK, and keeps it on the rolling android-preview prerelease.
It reads the track without opening a Play edit so it can't invalidate an
in-flight EAS submission, and it skips itself until
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON is configured.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The alpha track carries the v2-preview builds, the only Android builds that
can connect to a nightly server. Name the release android-nightly and tell
readers who it is for, instead of a generic preview label.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
eas.json submitted v2-preview builds to the alpha track when this branch was cut. pingdotgg#2829 renamed the submit target to the v2 closed testing track, so polling alpha would never see a v2-preview build.
@juliusmarminge juliusmarminge self-assigned this Oct 11, 2026
@juliusmarminge

Copy link
Copy Markdown
Member

Taking this over — thanks for building it, @SunkenInTime. Rebased onto current main (828 commits of drift, cherry-picks were clean) with one fix on top:

  • Track rename: this branch was cut when eas.json submitted v2-preview builds to the alpha track. feat(orchestrator): introduce new orchestrator #2829 changed the submit target to the v2 closed testing track, so polling alpha would never see a v2-preview build. PLAY_TRACK and the release docs now say v2 (77c49ce).

Re-verified while rebasing, since the original checks predate the rebase:

  • Play API contract re-checked against Google's current discovery document: applications.tracks.releases.list returns ReleaseSummary (releaseLifecycleState, activeArtifacts[].versionCode as int32), and generatedapks.download is the media-download endpoint the script uses. All fields and enums match.
  • Token smoke test reran with a throwaway key against Google's real token endpoint: rejected with Invalid grant: account not found, not invalid_request, so the JWT grant is still well-formed.
  • vp fmt --check and vp lint clean on the three changed files.

Still needed from maintainers before this does anything:

  • Add the GOOGLE_PLAY_SERVICE_ACCOUNT_JSON repo secret (confirmed it doesn't exist yet). Until then the job skips itself, as designed.
  • After merge + secret, run Mobile Android APK once via Run workflow; that first real run is what settles the two unknowns called out in the description.

Follow-ups deliberately left out, same as the original scope: link the android-nightly release from the Nightly mobile beta callout (apps/web/src/components/NightlyMobileBeta.tsx) and docs/user/install.md, which still send Android users to the Play testing group, and a stable APK mirrored from the production track.

@juliusmarminge

Copy link
Copy Markdown
Member

Update: GOOGLE_PLAY_SERVICE_ACCOUNT_JSON is now set (the existing Play Console service account EAS Submit uses; verified read-only against the Play API — track read and generatedApks list both return 200). So after merge, all that's left is one manual Run workflow for Mobile Android APK.

@juliusmarminge
juliusmarminge merged commit c0c495e into pingdotgg:main Oct 11, 2026
29 checks passed
LadyBluenotes added a commit to LadyBluenotes/grandtheftrepo that referenced this pull request Oct 12, 2026
* feat(source-control): GitCafe lives in @t3tools/source-control-gitcafe (pingdotgg#17681)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): add provider wizard no longer shifts sideways while it grows (pingdotgg#17292)

* fix(web): PR search keeps the caret where you type (pingdotgg#17675)

* fix(server): thread PR badges catch up when another environment reads the PR (pingdotgg#17729)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): refuse editor paths with line breaks or quotes when the editor is a Windows command shim (pingdotgg#17749)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): align compact button touch targets (pingdotgg#17748)

* fix(server): t3_thread_launch refuses a new worktree whose base ref has no commit (pingdotgg#17791)

* fix(web): omit underlines on markdown image links (pingdotgg#17728)

* fix(server): restore auto resume for wrapped Claude gateway rate limits (pingdotgg#17778)

* fix(opencode): name OpenCode 2 sessions after their thread (pingdotgg#17414)

* fix(web): find update settings from the command palette (pingdotgg#17396)

Co-authored-by: Claude <claude@anthropic.com>

* fix(provider-opencode): tell OpenCode Zen and Go models apart (pingdotgg#17424)

* fix(server): a pull that fast-forwards no longer fails on large Git output (pingdotgg#17376)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): cancel question auto-advance after navigation (pingdotgg#17364)

* fix(server): a bare repository name resolves to the signed-in account again (pingdotgg#17379)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): a maximized right panel stays maximized when you return to its thread (pingdotgg#17327)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mobile): allow starting a task with only an image (pingdotgg#17409)

* fix(server): PR watch no longer reports passed while a second run of a check is still going (pingdotgg#17344)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): say why a thread can't be settled (pingdotgg#17258)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): prevent busy terminals from starving history persistence (pingdotgg#17181)

* feat(server): use macOS .icns app icons as project icons (pingdotgg#17149)

* fix(mobile): usage reset icon lines up with its row (pingdotgg#17175)

* fix(web): paths pasted after @ keep their underscores (pingdotgg#16619)

Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): settle every OpenCode subagent call one report answers (pingdotgg#17134)

* perf(web): switching project keeps Diagnostics and Providers mounted (pingdotgg#17122)

* perf(web): Open Source Licenses downloads its manifest once per session (pingdotgg#17119)

* fix(server): restore OpenCode adapter test typecheck (pingdotgg#17810)

* fix(server): Claude subagents show the reasoning effort they run at (pingdotgg#17496)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(server): stop Claude subagents without stopping their owner (pingdotgg#17826)

* fix(server): stopped native subagents no longer read as Running (pingdotgg#17223)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* perf(server): t3_thread_list reads only the listed project's threads (pingdotgg#17843)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(server): show diffs for projects outside the server cwd (pingdotgg#17724)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* fix(server): check the specific scope for scripts, preview input, and full-access MCP grants (pingdotgg#17772)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(source-control): stop Forgejo status refresh from scanning every pull request (pingdotgg#12223)

Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Signed-off-by: Loïs Postula <lois@postu.la>

* refactor(contracts): source control provider kind is an open branded slug (pingdotgg#17739)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(source-control): each host package ships a client definition (pingdotgg#17746)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(client-runtime): add project clone sources come from host definitions (pingdotgg#17756)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(web): host presentation and behavior come from client definitions (pingdotgg#17757)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(source-control): reference parsing and project matching are host resolvers (pingdotgg#17770)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(pull-requests): quick actions follow each host's capabilities, not GitHub (pingdotgg#17774)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(projects): new projects can be published to any ready host (pingdotgg#17860)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): send Claude MCP servers over the control channel (pingdotgg#17898)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): a finished reply replaced by a steer is no longer labeled partial (pingdotgg#17761)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(client-runtime): queued runs that start after a steer show up in the thread (pingdotgg#17764)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(mobile): choose the microphone order for voice input (pingdotgg#17896)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(source-control): host settings live on each host's definition, with a GitCafe token (pingdotgg#17901)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(pi): preserve tool images and structured results (pingdotgg#17851)

* fix(server): Claude 5 task lists reach the tasks drawer (pingdotgg#14964)

* fix(web): find bar and thread details panel stop covering each other (pingdotgg#17858)

Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(web): use server metadata for file chip icons (pingdotgg#17923)

* fix(desktop): copy images from HTML previews (pingdotgg#17555)

* docs(pi): update installation and remote login guidance (pingdotgg#17836)

* fix(pi): preserve native abort outcomes (pingdotgg#17853)

* fix(pi): keep thinking defaults specific to each model (pingdotgg#17835)

* fix(pi): preserve shell command exit codes (pingdotgg#17834)

* fix(pi): expire and cancel extension approvals (pingdotgg#17840)

* feat(pi): include native sessions in usage reports (pingdotgg#17848)

* fix(server): route Copilot ACP subagent output into subagent threads (pingdotgg#17714)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* fix(web): composer banner titles truncate beside their icon instead of wrapping (pingdotgg#17699)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* fix(server): Muse turns no longer fail on Windows (pingdotgg#17163)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Theo Browne <me@t3.gg>

* fix(pi): allow known read-only T3 tools without approval (pingdotgg#17852)

Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix: worktree threads keep their worktree when the agent starts, and messages sent during setup queue (pingdotgg#17654)

* fix(server): keep Claude workflows alive while they report progress (pingdotgg#17715)

* fix(web): media preview centers its content and pins the close button (pingdotgg#17951)

* fix(server): threads without a project no longer need Git installed (pingdotgg#17959)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): toggling tools and thinking at the bottom keeps you at the bottom (pingdotgg#17954)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): Compact chip follows Claude's real prompt cache TTL (pingdotgg#17945)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(usage): bound OpenCode history reads to prevent backend OOM (pingdotgg#17961)

* refactor: format diff line counts through one shared helper (pingdotgg#17948)

* fix: new projects start their first thread in the project folder, not a worktree (pingdotgg#17371)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* perf(server): drive shell last-error lookup from thread bindings (pingdotgg#17842)

Co-authored-by: Victor Vogel <263261067+only21mil@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(server): skip parsing plain terminal history output (pingdotgg#17179)

* perf(server): batch terminal history writes every 250 ms (pingdotgg#17183)

* perf(server): storage cleanup no longer runs a full status or size walk for worktrees it keeps (pingdotgg#17911)

* perf(usage): usage scans skip OpenCode legacy messages older than the window (pingdotgg#17254)

* perf(usage): OpenCode legacy walk stats entries before checking for symlinks (pingdotgg#17638)

Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): MCP app permission prompts no longer overflow the screen (pingdotgg#17962)

* feat(provider-antigravity): support subscription quota and usage limits (pingdotgg#17530)

* fix(desktop): keep generated annotation styles in sync (pingdotgg#17838)

Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: Mike Olson <1510193+mwolson@users.noreply.github.com>

* fix(web): Resume continues on the model picked in the composer (pingdotgg#17867)

* fix(devices): bump agent-device to 0.21.24 for native Windows hosts (pingdotgg#17706)

* fix(web): keybinding group headings no longer touch the group above (pingdotgg#17766)

* feat(web): configure OpenTelemetry exports in diagnostics (pingdotgg#12538)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* docs: update user count to 500k (pingdotgg#17783)

* fix(mobile): working pill no longer bulges on its right end (pingdotgg#16143)

Signed-off-by: id0sch <id0sch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(opencode): stop retaining every message of a loaded OpenCode thread (pingdotgg#17784)

* fix(web): switch thumbs stay in their track while scrolling (pingdotgg#15240)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(keybindings): thread jumps no longer overlap model picker jumps (pingdotgg#14475)

* fix(mobile): restore QR scanning in iPad pairing sheet (pingdotgg#16019)

* fix(server): delegated Muse tasks no longer ask approval for every command (pingdotgg#18065)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(codex): prevent unsupported agent history in ChatGPT sharing (pingdotgg#17499)

Co-authored-by: connorwalker <connor@project-chinook.com>

* fix(server): disabled providers stop checking for CLI updates (pingdotgg#16772)

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* fix(mobile): round Android queued message sheet corners (pingdotgg#14934)

* fix(ssh): record the archive lock owner's real PID (pingdotgg#14598)

* fix(desktop): keep annotation comment direction independent of host page (pingdotgg#11005)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* fix(ssh): qualify runner script builders in tunnel test (pingdotgg#18078)

* fix(web): keep thread links open until the shell is live (pingdotgg#14697)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(web): scope PR title collapse to tab scrollers (pingdotgg#14644)

* fix(server): detect fork PRs for branches without upstreams (pingdotgg#13894)

Co-authored-by: maria-rcks <maria@kuuro.net>

* fix(search): find threads by their branch PR number (pingdotgg#14658)

Co-authored-by: maria-rcks <maria@kuuro.net>

* feat(web): show Claude workflow phases and members in Lineage (pingdotgg#12598)

Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: GPT-6.1-Sol (Codex) <noreply@openai.com>
Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* fix(mobile): round Android Agents sheet corners (pingdotgg#14925)

* fix(web): the Usage page sends a signed-out browser to pairing (pingdotgg#17938)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): OpenCode 2 continuations end after a reconnect took a Stop's end (pingdotgg#14744)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(server): OpenCode 2 continuations replay only their own background reply (pingdotgg#14752)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(server): ACP reapplies a model after a switch away from it failed partway (pingdotgg#14723)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(web): focus settings search with command-f (pingdotgg#17859)

* fix(mobile): keep Android project paths on one line (pingdotgg#14178)

* fix(web): unpin preview dragging on narrow chat canvases (pingdotgg#15556)

* fix(web): thread details toggle no longer covers the thread title on Windows desktop (pingdotgg#16869)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): a directory no longer resolves as the resource monitor binary (pingdotgg#16838)

Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): a Claude usage limit no longer resets the context meter to 0% (pingdotgg#16394)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): GitLab merge requests can expand unchanged lines (pingdotgg#17528)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(provider-cursor): a skill tree deeper than the scan limit no longer hides every skill (pingdotgg#17389)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): pass hex theme colors to HTML renders (pingdotgg#16325)

* fix(web): align the API estimate info icon (pingdotgg#15655)

* test(server): ACP teardown tests pass on Windows hosts (pingdotgg#17080)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): sync device tool license versions with installer pins (pingdotgg#18121)

* fix: sync model favorites and visibility across clients (pingdotgg#16816)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* chore(deps-dev): bump compression from 1.8.1 to 1.8.2 in the npm_and_yarn group across 1 directory (pingdotgg#16309)

Signed-off-by: dependabot[bot] <support@github.com>

* fix(server): update fff to stop runaway watcher rescans (pingdotgg#14543)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(mobile): license generation works with filtered installs (pingdotgg#18127)

* fix(mobile): image-only messages ask the agent to respond, like desktop (pingdotgg#16480)

Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* feat(pull-requests): guided reviews, a beta tour of a pull request (pingdotgg#18124)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(mcp): agents can write and read pull request review guides (pingdotgg#18143)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): Sol Ultrafast stops vanishing from the Codex model picker (pingdotgg#18200)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(usage): say resets momentarily in the final minute (pingdotgg#17869)

* fix(server): preserve ambient Cursor MCP servers (pingdotgg#15875)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* fix(server): skip Windows cleanup for exited child processes (pingdotgg#16007)

* feat(settings): providers can be turned on or off per project (pingdotgg#17879)

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* perf(github): resolve credentials once per GraphQL request (pingdotgg#18289)

* fix(server): refresh linked PRs without a checkout (pingdotgg#17167)

* fix(mobile): add compose to the single-column iPad list (pingdotgg#18157)

* fix(mobile): let sheet lists scroll before dismissal (pingdotgg#17177)

* fix(mobile): restore compact iPad trackpad scrolling (pingdotgg#13665)

* fix(mobile): preserve filters across layout changes (pingdotgg#13085)

* fix(mobile): separate unfolded thread list from header (pingdotgg#13088)

* fix(android): Match thread fallback layouts to the loaded pane (pingdotgg#14669)

* fix(mobile): size inline MCP apps to their content (pingdotgg#17040)

* fix(mobile): preserve iPad search chrome across layout changes (pingdotgg#13667)

* fix(client): apply host color scheme to saved MCP apps (pingdotgg#17026)

* fix(android): Use MD3 loading spinners (pingdotgg#14282)

* fix(client): merge No project filters across environments (pingdotgg#17050)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* fix(client): tolerate blocked cookies in MCP app sandboxes (pingdotgg#17027)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* feat(mobile): browse and review pull requests natively (pingdotgg#18126)

* feat(mobile): guided reviews for pull requests (pingdotgg#18267)

* fix(devices): refresh backlogged iOS video and require input admission (pingdotgg#18326)

* feat(mobile): keep pull requests available offline (pingdotgg#18351)

* fix(mobile): keep bot badges out of PR attachments (pingdotgg#18347)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(desktop): tooltips no longer open under the Windows and Linux window controls (pingdotgg#17672)

* fix(web): revert trailing toast icons (pingdotgg#18356)

Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* fix(web): even 4px inset around rows in the PR badge tooltip (pingdotgg#18352)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* ci(mobile): publish nightly Android APKs to a GitHub prerelease (pingdotgg#16271)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

---------

Signed-off-by: Loïs Postula <lois@postu.la>
Signed-off-by: id0sch <id0sch@users.noreply.github.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>
Co-authored-by: Tristan Knight <admin@snappeh.com>
Co-authored-by: Saikrishna Ambeti <saikrisha.ambeti1@gmail.com>
Co-authored-by: Zach <tzachbonfil@gmail.com>
Co-authored-by: Nikita Koynov <43469098+nkoynov@users.noreply.github.com>
Co-authored-by: Sergiy Dybskiy <s@serg.tech>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Karan Sharma <hello@mrkaran.dev>
Co-authored-by: Scott Norteman <snorteman@gmail.com>
Co-authored-by: Maxwell Young <maxtheyoung@gmail.com>
Co-authored-by: James Villarrubia <8172873+jamesvillarrubia@users.noreply.github.com>
Co-authored-by: Claudesaul <139932571+Claudesaul@users.noreply.github.com>
Co-authored-by: Dylan Corso <96969209+DylanTX@users.noreply.github.com>
Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-authored-by: Prathmesh Vhatkar <psv2522@gmail.com>
Co-authored-by: Afonso Ferreira <99990310+Aforno@users.noreply.github.com>
Co-authored-by: Derek Trimm <275381468+derektrimm@users.noreply.github.com>
Co-authored-by: Rakshith Bhat <88523594+RakshithBhat03@users.noreply.github.com>
Co-authored-by: Krishna Vijay <228381532+im-kvijay@users.noreply.github.com>
Co-authored-by: only21mil <thevictorvogel@gmail.com>
Co-authored-by: maria <maria@kuuro.net>
Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>
Co-authored-by: Loïs Postula <lois@postu.la>
Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Co-authored-by: Igor Makowski <56691628+Mnigos@users.noreply.github.com>
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>
Co-authored-by: Bilal Bakr <62337003+Bil0000@users.noreply.github.com>
Co-authored-by: Nicholas Tindle <nicktindle@outlook.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: Victor Vogel <263261067+only21mil@users.noreply.github.com>
Co-authored-by: Maciek Geneja <88164545+Maseeek@users.noreply.github.com>
Co-authored-by: Mike Olson <1510193+mwolson@users.noreply.github.com>
Co-authored-by: Akbar Danial Akma <44286537+akbarakma@users.noreply.github.com>
Co-authored-by: TanJeeSchuan <89920999+TanJeeSchuan@users.noreply.github.com>
Co-authored-by: fixfon <12512757+fixfon@users.noreply.github.com>
Co-authored-by: kamkm <99585688+Kamkmgamer@users.noreply.github.com>
Co-authored-by: id0Sch <id0Sch@users.noreply.github.com>
Co-authored-by: raphaelpra <3457781+raphaelpra@users.noreply.github.com>
Co-authored-by: Fluffy-Bunny-23 <193831219+Fluffy-Bunny-23@users.noreply.github.com>
Co-authored-by: Arham Mahajan <89351952+arhammahajan@users.noreply.github.com>
Co-authored-by: Connor Walker <70173040+connwalk@users.noreply.github.com>
Co-authored-by: connorwalker <connor@project-chinook.com>
Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com>
Co-authored-by: Alex <me@pixp.cc>
Co-authored-by: Guillermo Casanova <75276669+Gigioxx@users.noreply.github.com>
Co-authored-by: Abdelrhman Ehab <105376880+abdelrhmanehab10@users.noreply.github.com>
Co-authored-by: Alex Southwell <saphid@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Adamulek123 <adam.bogucki2018@gmail.com>
Co-authored-by: GPT-6.1-Sol (Codex) <noreply@openai.com>
Co-authored-by: AdEx-Partners-DE <stark.burns@adexpartners.com>
Co-authored-by: Exotic <118054752+extoci@users.noreply.github.com>
Co-authored-by: wellorbetter <1419919418@qq.com>
Co-authored-by: freddy-d <38051127+freddy-d@users.noreply.github.com>
Co-authored-by: Furox <177975472+Furox-Art@users.noreply.github.com>
Co-authored-by: Vantrongs <i.kosilov2003@gmail.com>
Co-authored-by: Cameron Varley <cam.avarley@gmail.com>
Co-authored-by: Sheehan Munim <80079528+sheehanmunim@users.noreply.github.com>
Co-authored-by: Jake Leventhal <jakeleventhal@me.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hasan Shoaib <142208891+realhasanshoaib@users.noreply.github.com>
Co-authored-by: Ali Younes <159104116+whoisaldo@users.noreply.github.com>
Co-authored-by: Arav Jain <aravhawk@gmail.com>
Co-authored-by: Alb11747 <albertli_042@hotmail.com>
Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants