Files
everyinc--compound-engineer…/docs/solutions/skill-design/cross-harness-cross-model-tool-invocation.md
2026-07-13 12:20:01 +08:00

8.2 KiB

title, category, date, module, problem_type, component, severity, applies_when, tags, related_components
title category date module problem_type component severity applies_when tags related_components
Cross-harness/cross-model skills drive agent tool calls, not slash commands — describe the capability, verify it live skill-design 2026-07-11 skills/ce-babysit-pr design_pattern tooling medium
Authoring a skill, once, for multiple agent harnesses and models where the skill needs the agent to invoke a capability (schedule/loop, ask the user, invoke a sub-skill, run background work, drive a browser)
Deciding whether to name a specific tool/command in skill prose or describe the capability
About to assume a particular tool or slash command exists or behaves a certain way on Codex/Grok/Cursor/Claude Code
A skill's capability works on the harness/model you authored it in but fails on another
A skill can invoke a slash-command-like affordance interactively but not from within its own execution
cross-harness
cross-model
capability-over-tool
tool-vs-slash-command
empirical-verification
portable-skills
orchestration
ce-babysit-pr
development_workflow
tooling

Context

A skill authored once for many harnesses (Claude Code, Codex, Grok, Cursor, …) frequently needs the agent to invoke a harness capability — schedule a re-invocation, ask the user a blocking question, invoke another skill, run a background process, drive a browser. The tempting design is to hardcode the mechanism per harness: "on Codex call X, on Grok call Y." That path is brittle in two directions at once — cross-harness (tool names and availability differ) and cross-model (even on one harness, models differ in what they'll reach for and how a tool behaves). It also silently confuses two different things: what a skill can drive versus what a user can do.

This crystallized while designing ce-babysit-pr's self-sustaining loop, where a plan full of per-harness scheduler assumptions turned out to be partly wrong once tested — but the lesson is general to any capability a skill needs invoked.

Guidance

1. The reliable unit a skill can drive is an agent tool call, not a user affordance. Skill prose steers the agent; the agent invokes tools. It cannot press keys or type a slash command, so a user-typed command (e.g. Cursor's /loop) is not skill-invocable — verified live: the agent reported /loop "only loads instructions into context." The exception is a slash command the harness also exposes as a tool (Claude Code's Skill tool can invoke /loop, so that one counts). Design for tool calls; treat any "have the skill run /command" step as a smell to verify.

2. The tool surface varies by harness and model, and agents reach for the simplest sufficient tool, not the fanciest. Given a capability need with the mechanism unspecified, fresh agents on all four harnesses built a plain background shell loop — none reached for a first-class scheduler tool, even Grok, whose scheduler_create (durable, agent-callable) was right there; it explicitly skipped it as overkill. So designing around a specific "correct" tool is doubly wrong: it may not exist on another harness, and even where it does, the model won't necessarily pick it.

3. Therefore: name the known tool as a short-circuit, but describe the capability as the portable fallback. For a recognized harness, state the specific agent tool for an instant, unambiguous pick. Underneath it, describe what the tool must do ("a way to run a background process and be woken when it emits a line, without ending your turn"; "the platform's blocking-question capability"), so an agent whose tool is absent, renamed, or newer can still satisfy the need — and degrade explicitly when nothing fits. Both, not either: the named tool is speed, the capability description is robustness.

4. Verify per-harness/per-model tool behavior empirically, with live agents — not from your authoring runtime. Assumptions baked from one runtime ship wrong. Two live checks (fresh agents per harness, dispatched via orchestration) corrected real errors before they landed: Codex's CLI exposes no scheduler tool and a detached nohup is reaped the instant the tool call ends (only a runtime-owned handle survives); Cursor's /loop is not skill-invocable; Grok's scheduler_create is durable and agent-callable but goes unused. This operationalizes the "portable agent skill authoring" decentering principle: when a design rests on per-harness/per-model tool behavior, prove it with agents on those targets.

Why This Matters

The failure mode is expensive because it is invisible in-repo: confidently-wrong per-harness prose (a background process that silently dies, a slash command the skill can't trigger, a tool that isn't there) passes every unit test and static check — it only fails at runtime, on the harness/model you didn't author in. No amount of bun test catches it. Describing capabilities plus verifying with live agents is the only guard, and it applies to every capability a portable skill invokes, not just scheduling.

It also collapses complexity. Reframing ce-babysit-pr from "detect the harness → call its scheduler → guard a bundled driver script against nesting" to "describe the watch intent, let the agent build the loop with whatever it has" deleted a driver script, a tool-tier matrix, and a sentinel guard — because it stopped fighting what agents already do well.

One boundary the same experiments surfaced: agents pick the simplest sufficient tool, which for a trivial task is a dumb shell command. When the per-invocation work is actually agent reasoning (invoke a sub-skill, judge feedback), the prose must say so, or the agent takes the shell shortcut that can't do the reasoning.

When to Apply

  • Any skill authored once for multiple harnesses/models that needs the agent to invoke a capability — scheduling/looping, blocking questions, sub-skill invocation, background work, browser or MCP tools.
  • Whenever prose is about to say "call tool X" or "run /command" for a cross-harness action — first ask whether describing the capability works, keep the named tool only as a short-circuit, and verify X on the target harness+model.
  • Not needed for a single-harness skill, or for a capability already proven on the target runtime.

Examples

Slash command vs tool (the sharp distinction): "have the skill run /loop" is not portable — a skill can't type it, and on Cursor it isn't agent-invocable at all. "Use whatever agent tool re-invokes work on a cadence (Claude Code: ScheduleWakeup / the Skill-tool-invoked /loop; Grok: scheduler_create; else a background process the agent runs)" is portable, because it targets tool calls and names tools only as examples.

Capability over tool (asking the user): prose that says AskUserQuestion breaks off-Claude. ce-babysit-pr instead says "use the platform's blocking-question tool" and lists AskUserQuestion / request_user_input / ask_question / ask_user as examples with a chat fallback — one capability, many tools.

Live verification (the reusable technique): publish a controllable external artifact (an ht-ml.app page), dispatch a fresh agent per harness with intent-only instructions to watch it and react to a change, then change it and confirm each caught the change unattended with an unguessable value. Proof beats assumption for anything that varies by harness or model — and it is how "Codex nohup is reaped" and "Cursor /loop isn't skill-invocable" were caught before shipping.