You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An Agent's runtime provider is immutable by design ("immutable Computer/provider
binding", README). The only way to move an Agent from Codex to Claude Code is to
suspend it, delete it, and create a new one. That is a reasonable identity model,
but on Feishu it has a consequence that is not part of any stated design goal:
Changing an Agent's runtime provider orphans a Feishu app in the customer's
tenant and forces the registration of a brand-new one.
The chain is entirely mechanical:
agent update exposes --display-name, --model, --reasoning-effort, --instructions, --allowed-tool, and --max-duration-ms. There is no --provider, and the Web Execution choices panel has no provider control
either. Both are correct given the immutability rule.
Deleting the old Agent disables its IM binding in the same transaction
(agent-service.ts:529, disableImBindingInTransaction). This is deliberate
and asserted by an integration test (im-binding.test.ts:4032).
imBindings.agentId is never updated anywhere in the repository, so the
binding cannot follow the Agent.
The new Agent therefore has no binding. FeishuSetupService resolves existing via #currentForAgent(agentId) (setup-service.ts:119), which
returns nothing for a new Agent.
reauthorize — the one intent that reuses existingAppId — requires that existing be present (setup-service.ts:123, else FEISHU_REAUTHORIZATION_REQUIRES_BINDING). So the only reachable intent is create, and existingAppId is passed as undefined
(setup-service.ts:138).
DefaultFeishuRegistrationGateway then calls registerApp with createOnly: false and an appPreset named after the new Agent's display
name (setup-service.ts:130), producing a new Feishu app.
The user-visible cost of trying a different runtime is therefore: a dead app left
in the Feishu tenant, a new app registered, a new QR scan, and re-adding the new
bot to every group it was in. Session continuity is lost as well, which is
expected — the orphaned tenant app is not.
Desired outcome
Changing an Agent's runtime provider should not require re-authorizing IM.
The asymmetry is already visible in the existing model: FeishuSetupIntentSchema = ["create", "reauthorize", "replace"] covers replace
the app, keep the Agent. The reverse — keep the IM identity, rebuild the Agent
underneath it — has no representation.
Concretely, one of:
a supported way to re-point an existing, active binding at a different Agent of
the same Team (an explicit rebind operation, revision-fenced like other Agent
mutations); or
a provider change performed in place as a new Agent revision, keeping the
Agent id and therefore the binding; or
if neither is desired, surface the real cost before the destructive step —
today nothing warns that deletion will orphan a tenant-level Feishu app.
Alternatives considered
Leave as is. Defensible while Codex is the only runnable provider, since
nobody has a reason to switch. [Feature]: Make the Claude Code provider actually runnable #53 changes that: once Claude Code runs, "try
the other provider" becomes a normal thing to do, and every attempt costs a
tenant app.
Document it. Does not help — the orphaned app is a side effect in the
customer's Feishu tenant, not in OpenTag, so there is nothing the operator can
clean up from OpenTag afterwards.
Delete the Feishu app on unbind. Rejected: OpenTag should not delete
tenant-level assets it did not exclusively own, and the app may have been added
to groups by other people.
Notes
Related to #53 (making Claude Code runnable) — that issue is what turns this from
theoretical into routine. Not a duplicate: #53 is about a provider that cannot
run, this is about the cost of moving between providers that can.
Observed on main @ 2875047 while switching a working Feishu-bound Codex Agent.
User problem
An Agent's runtime provider is immutable by design ("immutable Computer/provider
binding", README). The only way to move an Agent from Codex to Claude Code is to
suspend it, delete it, and create a new one. That is a reasonable identity model,
but on Feishu it has a consequence that is not part of any stated design goal:
Changing an Agent's runtime provider orphans a Feishu app in the customer's
tenant and forces the registration of a brand-new one.
The chain is entirely mechanical:
agent updateexposes--display-name,--model,--reasoning-effort,--instructions,--allowed-tool, and--max-duration-ms. There is no--provider, and the Web Execution choices panel has no provider controleither. Both are correct given the immutability rule.
(
agent-service.ts:529,disableImBindingInTransaction). This is deliberateand asserted by an integration test (
im-binding.test.ts:4032).imBindings.agentIdis never updated anywhere in the repository, so thebinding cannot follow the Agent.
FeishuSetupServiceresolvesexistingvia#currentForAgent(agentId)(setup-service.ts:119), whichreturns nothing for a new Agent.
reauthorize— the one intent that reusesexistingAppId— requires thatexistingbe present (setup-service.ts:123, elseFEISHU_REAUTHORIZATION_REQUIRES_BINDING). So the only reachable intent iscreate, andexistingAppIdis passed asundefined(
setup-service.ts:138).DefaultFeishuRegistrationGatewaythen callsregisterAppwithcreateOnly: falseand anappPresetnamed after the new Agent's displayname (
setup-service.ts:130), producing a new Feishu app.The user-visible cost of trying a different runtime is therefore: a dead app left
in the Feishu tenant, a new app registered, a new QR scan, and re-adding the new
bot to every group it was in. Session continuity is lost as well, which is
expected — the orphaned tenant app is not.
Desired outcome
Changing an Agent's runtime provider should not require re-authorizing IM.
The asymmetry is already visible in the existing model:
FeishuSetupIntentSchema = ["create", "reauthorize", "replace"]covers replacethe app, keep the Agent. The reverse — keep the IM identity, rebuild the Agent
underneath it — has no representation.
Concretely, one of:
the same Team (an explicit rebind operation, revision-fenced like other Agent
mutations); or
Agent id and therefore the binding; or
today nothing warns that deletion will orphan a tenant-level Feishu app.
Alternatives considered
nobody has a reason to switch. [Feature]: Make the Claude Code provider actually runnable #53 changes that: once Claude Code runs, "try
the other provider" becomes a normal thing to do, and every attempt costs a
tenant app.
customer's Feishu tenant, not in OpenTag, so there is nothing the operator can
clean up from OpenTag afterwards.
tenant-level assets it did not exclusively own, and the app may have been added
to groups by other people.
Notes
Related to #53 (making Claude Code runnable) — that issue is what turns this from
theoretical into routine. Not a duplicate: #53 is about a provider that cannot
run, this is about the cost of moving between providers that can.
Observed on
main@ 2875047 while switching a working Feishu-bound Codex Agent.