Skip to content

[Bug]: ACP Registry binary agents break on every upstream release — prepared version is not pinned #26531

Closed

Description

@socksprox

Area

apps/server (packages/provider-acp-registry)

Steps to reproduce

  1. Settings → Providers → Add provider → ACP Registry → add an agent with a binary-only distribution (e.g. devin). Prepare succeeds and threads work.
  2. Wait until the upstream vendor publishes a new release and the ACP Registry index advances to a newer version (Devin CLI releases every few days, so this happens quickly).
  3. Start a thread with the same provider instance.

Expected behavior

The provider instance keeps working on the version that was prepared, or T3 Code automatically prepares the new version / offers a repair action.

Actual behavior

The provider snapshot reports:

ACP Registry agent 'devin' has not been prepared on this environment.

and starting a thread fails (surfaced as Not found). Re-adding the agent via the registry search is the only in-app recovery, which also creates a second provider instance.

Root cause (verified on main)

inspect() in packages/provider-acp-registry/src/server/AcpRegistrySupport.ts derives the expected executable path from agent.version taken from the current registry index:

  • binaryPaths() → ~/.t3/tools/<agentId>/<version>/<platformTarget>/<cmd>
  • if exists(executablePath) is false → { status: "unprepared" } → installed: false + the message above in driver.ts (acpRegistrySnapshotReadiness).

AcpRegistrySettings (packages/provider-acp-registry/src/settings.ts) has no field recording which version was prepared, so after any registry version bump the previously prepared directory (tools/<agentId>/<oldVersion>/) no longer matches and the instance is dead in the water.

The block is artificial — resolve() already self-heals

The spawn path used at turn start (AcpRegistryCatalog.resolve, AcpRegistrySupport.ts ~L1810) calls installBinary(agent, target) for binary agents with no command override. installBinary checks exists(executablePath) and downloads+extracts the current registry version if missing. So the code already knows how to recover — the instance just never gets that far:

  • installed: false → enrichSnapshot early-returns (driver.ts:637), so no probe/models/auth state is populated.
  • installed: false → availability constraints push "Provider executable is not installed." (apps/server/src/mcp/OrchestratorMcpService.ts:356), and the web client (ChatView.logic.ts, ProviderStatusBanner, ModelPickerContent) treats the provider as unusable.

Only binary agents are affected

For npx/uvx distributions, inspect only checks that the runner exists, and resolve calls ensureGlobalPackage, which reconciles the pinned package@version at launch. Binary is the only distribution that demands an exact-versioned directory at inspect time while recording no prepared version anywhere.

Cache semantics make the failure sudden, not gradual

inspect reads loadCachedRegistry() (in-memory ref → disk cache), while prepare and resolve call refreshRegistry()/loadRegistry(). The first search/prepare/resolve that fetches a newer index flips every prepared instance of that agent to unprepared at the next snapshot — with no prepare having failed.

No repair path for existing instances

  • serverPrepareAcpRegistryAgent is only invoked from the Add-provider search step (AcpRegistrySearchStep.tsx); an existing instance's settings form offers no Prepare/Repair action.
  • MAINTENANCE = makeManualOnlyProviderMaintenanceCapabilities({ packageName: null }) → no update check or maintenance affordance for acpRegistry providers.
  • uninstallManagedBinary removes the whole tools/<agentId>/ tree only when no instance references the agent; there is no per-version GC, so stale versioned dirs accumulate anyway.

Suggested fixes (any of)

  • Have inspect for binary agents accept the newest versioned dir actually present under tools/<agentId>/<version>/<target>/ instead of requiring registry-latest — resolve will still transparently install the latest version on next launch, matching npx/uvx behavior.
  • Record the prepared agentVersion on the provider instance at prepare time and resolve against it.
  • Since resolve already auto-installs, inspect could report ready whenever any version is prepared (surfacing the prepared version in the snapshot), or
  • Add a Prepare/Repair action on the instance card that calls the existing serverPrepareAcpRegistryAgent RPC.

Impact

Major degradation or frequent failure — binary-only registry agents (e.g. Devin) silently become unusable on every upstream release.

Version or commit

main @ 5211acf (verified against a fresh source pull of main)

Environment

macOS 27 (Apple Silicon), T3 Code desktop, devin ACP Registry agent — prepared 3000.11.205, registry later moved to 3000.11.228.

Workaround

Three options:

  1. Settings → Providers → Add provider → ACP Registry → Add the same agent again (runs prepare for the new version; creates a second instance).
  2. Set Executable override on the instance to an existing agent binary on PATH (keeps the registry's args/env).
  3. Manually download the registry-pinned archive into ~/.t3/tools/<agentId>/<newVersion>/<platformTarget>/ so bin/<cmd> exists.

Activity

  1. AndreaBarghigiani commented on Nov 6, 2026

    @AndreaBarghigiani

    I was facing the same issue and solved with workaround 3, hopefully #26543 or #31486 once merged will solve this 🤞

  2. nafiskabbo commented on Nov 10, 2026

    @nafiskabbo

    Same failure on the latest nightly, with a newer version pair — adding fresh evidence.

    Environment: T3 Code desktop 0.1.9-nightly.20261110.4491, macOS arm64 (Apple Silicon).

    Evidence:

    • Previously prepared: devin 3000.11.234 at ~/.t3/tools/devin/3000.11.234/darwin-aarch64/bin/devin.
    • Registry advanced to 3000.12.43 (cached ~/.t3/caches/acp-registry/registry.json refreshed 2026-11-11). No prepare failed.
    • inspect() looks for the current version at ~/.t3/tools/devin/3000.12.43/darwin-aarch64/bin/devin, which does not exist.
    • ~/.t3/caches/acpRegistry_devin.json shows status: "warning", installed: false, setup.canInstall: false, and the message above.
    • Devin is greyed out in the model picker, so the resolve() self-heal never runs.

    This matches the root cause exactly: the check is pinned to the registry-latest directory, ACP registry snapshots hardcode canInstall: false, and existing instances have no Prepare/Repair action.

    Recovery that worked without creating a second provider instance: extract the registry-pinned archive into the expected path.

    mkdir -p ~/.t3/tools/devin/3000.12.43/darwin-aarch64
    tar -xzf devin-3000.12.43-aarch64-apple-darwin.tar.gz \
      -C ~/.t3/tools/devin/3000.12.43/darwin-aarch64

    bin/devin --version → devin 3000.12.43 (517d03d73926). The provider should return to Available after the next status check/app restart.

    Hope #26543 lands; this will recur for every binary agent on every upstream release.

    — Diagnosed with OpenCode (DeepSeek V4.1 Flash Free)

  3. jBRNDnl commented on Nov 11, 2026

    @jBRNDnl

    Same failure on Linux with a different binary agent, mistral-vibe. Adding it as evidence for #26543.

    Environment: T3 Code 0.1.9-nightly.20261111.4501, headless t3 serve, Linux x86_64 (Debian).

    What happened:

    • mistral-vibe 3.1.0 was prepared and working: ~/.t3/tools/mistral-vibe/3.1.0/linux-x86_64/vibe-acp.
    • The cached index ~/.t3/caches/acp-registry/registry.json still listed 3.1.0 days after the live index moved to 3.1.1. Nothing in T3 refreshed it, because session start and status checks read the cache only. I replaced the cached file with the live index by hand. That has the same effect as a refreshRegistry().
    • After the next server restart, the first status check reported installed: false, status: "warning", ACP Registry agent 'mistral-vibe' has not been prepared on this environment. The 3.1.0 binary was still on disk. The provider stayed unavailable in the UI for about 2.5 hours, and there was no install or update action on the existing provider.
    • Starting a thread with the provider from the CLI (t3 thread start --provider acpRegistry_mistral_vibe ...) went through resolve(), which installed 3.1.1/linux-x86_64/vibe-acp and ran it. The next status check reported ready with version 3.1.1.

    So it matches the root cause here: inspect() only looks at the registry's current version, and resolve() would have recovered by itself. The old 3.0.4 and 3.1.0 directories are still there (about 700 MB), which is what #32658 addresses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions