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
- Preserve a selected composer skill as structured invocation metadata through the web send path.
- Keep
$ as the canonical skill picker and chip for Codex and Claude.
- Lower one explicit skill invocation correctly in the Codex and Claude adapters.
- Keep
/ reserved for T3/provider commands.
- Reject unsupported combinations clearly rather than sending inert text.
- 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
Before submitting
Area
apps/web,apps/mobile,packages/contracts, provider adaptersProblem 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-namefor skills/commandfor commandsThat model works naturally with Codex:
$lists skills and the resulting$skill-nameis 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-nametext. Claude does not treat that as a direct user invocation. A skill markeddisable-model-invocation: truetherefore refuses to run, while/skill-nameworks 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: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-namealways means explicitly invoke this skill./commandalways means execute this command.The important architectural change is to preserve skill invocation as structured data through dispatch instead of immediately flattening
ComposerSkillNodeto$skill-nametext. 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:$skill-namerepresentation.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:
Smallest useful scope
$as the canonical skill picker and chip for Codex and Claude./reserved for T3/provider commands.$skillaction 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
$explicitly invokes that skill on both Codex and Claude.$skill picker rather than requiring users to know Claude's internal slash syntax.$skillcan 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.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-nameas plain text to every providerThis 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
Related
$Contribution