Skip to content

[Feature]: Make skill invocation provider-agnostic ($skill across providers) #7795

Description

@marcob896

Before submitting

Area

apps/web, apps/mobile, packages/contracts, provider adapters

Problem or use case

T3 Code is a multi-provider client, so users should not need to remember each provider's private grammar for the same concept.

Today the composer exposes two apparently stable concepts:

  • $skill-name for skills
  • /command for commands

That model works naturally with Codex: $ lists skills and the resulting $skill-name is a native explicit skill invocation.

With Claude, however, T3 discovers the same skills for the $ picker but flattens the selected semantic skill chip to plain $skill-name text. Claude does not treat that as a direct user invocation. A skill marked disable-model-invocation: true therefore refuses to run, while /skill-name works because Claude exposes user-invocable skills through its slash-command mechanism.

The immediate fix in #7673 removes those Claude skills from $ and leaves them under /. That prevents invalid selections, but it leaks Claude's provider-specific grammar into the shared T3 UX and removes composition capabilities:

ok, now $implement all the tickets

A $ skill chip can be inserted naturally in the middle of a prompt. Provider slash-command autocomplete is available only when / opens the message, because slash expansion itself requires the command at the start. Moving Claude skills to / is therefore not just a different symbol; it makes the same T3 feature behave differently depending on the selected provider.

Proposed solution

Give T3 Code a provider-agnostic invocation model:

  • $skill-name always means explicitly invoke this skill.
  • /command always means execute this command.
  • The composer and persisted T3 timeline use those canonical semantics consistently across providers.
  • Provider adapters lower the canonical invocation to the strongest correct provider-native mechanism.

The important architectural change is to preserve skill invocation as structured data through dispatch instead of immediately flattening ComposerSkillNode to $skill-name text. The send contract could carry the selected skill invocation(s), their position, and the surrounding user text. Each adapter can then translate or reject the operation honestly:

  • Codex can emit its native $skill-name representation.
  • Claude can use its native explicit user-invocation path, including any required placement or expansion behavior.
  • Future providers can map the same T3 action to ACP commands, a native skill/tool call, prompt injection, or another supported mechanism.

The exact lowering mechanism should remain provider-owned. T3 should not pretend an invocation succeeded by sending an inert mention as prose.

Provider-specific constraints still need explicit handling. If a provider supports only one explicit skill, requires invocation at message start, or cannot preserve a particular composition, T3 should normalize the prompt where semantics are preserved or show a clear validation error. It should never silently downgrade an explicit invocation to a hint for the model.

Disabled skills should remain absent from invocation UI. This proposal complements the discovery and safety work in #7671/#7673 rather than reverting it.

Why this matters

T3 Code's value is partly that it provides one coherent interface over multiple coding agents. Requiring users to remember “Codex skills use $, Claude skills use /, but / only works at the beginning” breaks that abstraction.

A canonical invocation model provides:

  • consistent muscle memory across providers;
  • inline skill composition where the provider can support it;
  • an honest distinction between skill invocation and command execution;
  • safer handling of user-invocation-only skills;
  • a stable contract for future providers instead of adding UI exceptions per adapter.

Smallest useful scope

  1. Preserve a selected composer skill as structured invocation metadata through the web send path.
  2. Keep $ as the canonical skill picker and chip for Codex and Claude.
  3. Lower one explicit skill invocation correctly in the Codex and Claude adapters.
  4. Keep / reserved for T3/provider commands.
  5. Reject unsupported combinations clearly rather than sending inert text.
  6. Add focused tests proving that the same canonical $skill action invokes the selected skill with both providers.

Mobile and multiple-skill composition can follow if keeping the first slice smaller is necessary, but the shared contract should not preclude them.

Acceptance criteria

  • Selecting a skill from $ explicitly invokes that skill on both Codex and Claude.
  • Claude user-invocation-only skills are available through the canonical $ skill picker rather than requiring users to know Claude's internal slash syntax.
  • $skill can remain part of a larger natural-language prompt in the T3 composer.
  • / remains the command surface and is not overloaded with provider-specific skill semantics in the shared UI.
  • The timeline displays the user's canonical T3 input, while provider-native lowering remains an adapter concern.
  • Unsupported provider constraints produce an explicit validation error.
  • No selected skill is silently sent as an inert textual hint.

Alternatives considered

Keep Claude user-invocation-only skills under /

This is the #7673 safety fix. It prevents a dangerous failure mode, but exposes provider internals and loses inline composition because slash commands only expand at the start of a message.

Teach users each provider's syntax

This is workable in raw provider CLIs, but undermines T3 as a multi-provider abstraction layer.

Continue sending $skill-name as plain text to every provider

This works natively for Codex but is not an explicit invocation for Claude. The model may refuse, ignore it, or choose a similarly named skill.

Risks or tradeoffs

  • Claude's native slash expansion may impose placement or single-invocation constraints. The adapter must model these honestly.
  • Structured invocation requires a contracts change and migration of web/mobile composer send paths.
  • Persisted canonical input and provider-native dispatched input may differ, so diagnostics should retain both representations.
  • Blindly rewriting text with regex would be fragile. The implementation should preserve the semantic composer node or equivalent structured metadata.

Related

Contribution

  • I am not currently committing to an implementation, but I can validate the UX against real Codex and Claude provider profiles.

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