Skip to content

[chore] The tmux, kitty and iTerm2 Operators are one agent wearing three names — declare backend-exclusive tools (no code) #403

Closed

Description

@serge-ivo

The smallest correct step out of #402, available today with no primitive and no code — a change to three agent rows.

The state

All three Operator agents declare the generic terminal connector's tools:

terminal_list_targets · terminal_capture · terminal_run_command
terminal_send_keys · terminal_new_target · terminal_kill_target

terminal_list_targets takes backend: "all" | "tmux" | "kitty" | "iterm2" and defaults to all (connectors/terminal.ts:50). So the tmux Operator, the kitty Operator and the iTerm2 Operator are the same agent with three names and three descriptions, each of which is false about the other two.

Observed: the owner asked the tmux Operator about tmux sessions and it correctly reported two iTerm2 windows, because that is genuinely what it can reach.

The fix

A tmux-only connector already exists in the registry (registry.ts id: "tmux") with six backend-exclusive tools — tmux_list_sessions, tmux_capture_pane, tmux_run_command, tmux_send_keys, tmux_new_session, tmux_kill_session. Declaring those in the tmux Operator's capabilities.tools makes it a tmux agent by construction: there is no iTerm2 code path behind them to reach.

Why bother, given #402 supersedes it

Because it is free and it makes one agent honest now, and because it clarifies the general ticket: the reason kitty and iTerm2 cannot be fixed the same way is precisely the argument for the primitive. Shipping a third and fourth parallel connector to express "one backend" is the workaround that does not scale.

Direction: docs/capability-constraints.md.

Activity

  1. serge-ivo commented on Aug 8, 2026

    @serge-ivo
    ContributorAuthor

    The known cost recorded in 0099's header is filed as #409, verified and with the fix designed — please read it before pushing.

    Two things the migration's note does not have, both measured:

    1. tmux-operator is published, not draft (live D1 + GET /v1/agents — it is one of 15 catalog agents). The kitty/iTerm2 rows being draft does not bound the blast radius: the next subscriber gets a Terminal tab that has never worked.
    2. Teaching the tab the tmux_* names is not a rename. terminal_* takes target: "tmux:main", tmux_* takes session: "main"; and /tmux/list rows carry no backend/id, both of which parseTargets (TmuxTab.tsx:59-61) requires — so a naive swap yields a silently empty list, which is a worse failure than the 403.

    Nothing here asks 0099 to change. The consent carry is right and covers cda75e28 (which holds terminal write but no tmux row today — verified), and leaving surfaces:["tmux"] declared is the right call. #409 argues the console fix should ship alongside rather than wait for #402/#404, and adds the generalisation: TmuxTab.tsx is the only unguarded hardcoded tool name in the console tree — McpConnections.tsx:226 already does it correctly — so this is the moment to ratchet it at one.

  2. serge-ivo commented on Aug 8, 2026

    @serge-ivo
    ContributorAuthor

    Shipped in 78d2cfe as part of 782f00c, together with #409 — deliberately as one unit, because #403 alone would have shipped a dead Terminal tab on a published catalog agent (tmux-operator is live, not draft; confirmed against /v1/agents, 15 agents).

    Verified in production: migration 0099_tmux_operator_backend_exclusive_tools.sql applied to the remote D1 — 🚣 Executed 5 commands, ✅ — in the deploy for 782f00c.

    Checkbox 1 ✅ — the six tmux_* names were verified against TMUX_TOOLS in lib/connectors/tmux.ts rather than transcribed from the ticket.

    Two things the ticket did not anticipate, both handled:

    • Write consent would have been silently revoked. Consent is keyed by connector. 0073 copied tmux→terminal and kept the originals, so a pre-0073 instance has both — but the instance subscribed on 2026-08-07 has only a terminal row. The migration mirrors 0073 back, scoped by a.slug = 'tmux-operator' so an unrelated agent's terminal grant cannot become a tmux grant. Checked on a sqlite fixture: the new instance gains tmux/write, the other agent's instance does not, re-running is a no-op.
    • The console tab broke, which became [bug] #403 breaks the Terminal tab: the console calls terminal_* by name, and the tmux Operator will no longer declare them #409 and shipped in the same push.

    Checkbox 2 ✅ — honest descriptions rather than unpublishing. Both kitty-operator and iterm-operator are already draft in prod, so unpublishing is a no-op that leaves the misleading copy in place; the sentence travels with the row if anyone publishes it later. Each now states it is not limited to the backend in its name.

    Checkbox 3 ✅ — lintAgentClaims re-run over all three rows: 0 violations, before and after. Worth recording why that tick is not a verdict: the lint only asks whether a runtime claim is backed by runtime/workflow, and all three genuinely declare runtime: "coding". What they overstate is which resource the runtime reaches — the defect class this ticket is about, which the lint structurally cannot see. That is now written down as a test rather than left to be rediscovered.

    Closing: delivered and verified in production.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions