Skip to main content
When a skill needs another skill’s logic mid-conversation, it references it with @skill.<name>. The parent stays on the stack, the sub-skill runs, and the parent resumes with the sub-skill’s public memory available to it. That public memory stays after the sub-skill completes, so the parent can read it on later turns. It is cleared only when that same skill starts again in the session. If a result must last the whole conversation, write it to project memory instead.

The @skill.<name> reference

When the orchestrator reaches @skill.authentication, it parks Card Replace on the stack, runs Authentication to completion, then resumes Card Replace, which can now read Authentication’s public fields such as authenticated and party_id. Those leftover public values stay after complete so the parent can read them; they are cleared only if Authentication starts again. Session-long facts such as authenticated belong in project memory so they survive that next run (see precondition below). Write @skill.<name> when the parent needs another skill’s result to carry on, including when that request is still part of this skill’s task. The referenced skill has its own task. That is a delegation: the orchestrator runs the named skill and resumes the parent when it finishes. A task this skill does not handle is not a delegation, so leave the reference out. The orchestrator parks this skill and offers a resume. When to write the reference is in Writing prose. How each case parks and resumes the parent is in Jumps to blocks and skills.

Composition rules

  1. Default to small, focused skills. Each skill does one thing and exports results as public memory. Transaction lookup is its own skill, not embedded in disputes, refunds, and fraud review.
  2. Compose when you need context continuity. A dispute skill calls transaction-lookup as a sub-skill. The parent owns the conversation.
  3. The parent must have meaningful business logic of its own. If you strip out all the @skill.<name> references and the skill is empty, it’s not a skill. That’s the orchestrator’s job.

Depending on another skill’s outcome

Use a precondition when a skill must not start until session memory says it may — for example, card replacement should wait until the customer is authenticated.
skills/card_replace/skill.md
agent.yml
Card Replace declares precondition: customer_authenticated. In agent.yml, that name means: start Card Replace only when satisfied_when is true; until then, call the resolve_with skill (authentication). Unlike hidden: true, Card Replace stays in routing — the customer can still ask for it. When they do and they are not authenticated yet, the engine parks Card Replace as pending, runs authentication, then either promotes Card Replace or abandons the turn. If authentication is already the active skill (for example it doubles as the session opener), the engine parks Card Replace under that run instead of starting authentication again. Card Replace depends on the memory key authenticated, never on hiding itself from routing. The memory key is the whole contract, which is why it lives in the project-level memory.yml rather than inside either skill. Reach for precondition when a skill must not start before another has done its job; use @skill.<name> when a parent needs another skill’s result mid-conversation (see above).

Which one to use

Both take the id, not the display name: @skill.card_disambiguation for a skill in skills/card_disambiguation/, and @block.pick_card for a block declared as :::ordered_block id=pick_card. Tools need no token. They are already in the model’s schema while their skill is active, so name them in plain prose.