Part 4 of 18 · Arunank Sharan · Kuzushi Labs · 1,217 words · 7 August 2026

← Series contents · Complete reading view

Skills and on-the-fly composition

“I need a place for next weekend” and “the Wi-Fi is not working” can both mention a property. They should not receive the same operational procedure. One starts a booking inquiry. The other may require troubleshooting and issue reporting for an existing stay.

The routing layer decides which capabilities the turn needs before the model starts working. In the client platform, that decision combined an agent identity, a model tier, skill instructions, message categories and a tool allowlist. The result was an assembled capability for this turn.

Agent configuration and matching skills combine into a bounded per-turn execution plan.

Give “skill” a concrete meaning

A skill was a routable bundle of trigger patterns, an instruction fragment and tool names, with context conditions where needed. It was not another autonomous assistant with its own personality and history.

{
  "capability": "example-maintenance-help",
  "audience": "guest",
  "triggers": ["leaking", "not working", "blocked"],
  "requires": "an identified stay",
  "prompt_fragment": "Record the issue and explain the returned outcome.",
  "tools": ["report_issue", "get_task_status", "escalate_to_host"]
}

The bundle keeps a capability separate from a persona. The same guest-facing voice can answer a property question, search inventory and explain a maintenance update without a sequence of artificial handoffs. Validate the bundle before publication: every referenced tool must exist, every prerequisite must have a provider, and the instruction fragment must fit within the audience’s authority.

The skill concept also gives an operator a manageable editing surface. Updating a booking procedure should not require rewriting the entire concierge persona.

A two-tier classifier

The classifier first uses deterministic patterns and context. When that is insufficient or ambiguous, a model-based classifier can supply a more flexible decision. The fallback must be bounded: a routing call that hangs can consume the whole conversational deadline before the main model is invoked.

This is not a claim that keywords are universally better. They are cheap, inspectable and effective for well-defined signals. They are weak on continuation and paraphrase. A guest replying “completely blocked” may be continuing a toilet complaint; the latest words alone are an incomplete classification input.

The design therefore has to account for context preconditions, explicit hints and continuation matching. A broad general-question skill should not absorb a more specific cancellation or complaint merely because it was registered first.

Failure Why it happens Useful correction
Complaint routed to FAQ Broad trigger wins too early Specificity and priority tests
Continuation loses its procedure Latest message omits the original noun Reconsider recent context and prior route
Correct classification, missing tools Selection and tool resolution use different rules One resolved route contract
Two skills repeat the same instructions Shared fragments are concatenated twice Stable fragment deduplication
Irrelevant skill joins the turn Matching ignores stay/context requirements Apply preconditions to every candidate

These are classifier failures, so they need a classifier dataset. Looking only at final answer scores hides where the wrong decision entered the pipeline.

Single-skill and multi-skill modes

There are two useful composition policies: select one primary skill, or combine several compatible skills. The correct choice depends on the request. A simple property question may need one capability; a complaint followed by “and what time is checkout?” may require two. Define the policy explicitly and evaluate each mode against the same multi-intent scenarios.

In multi-skill mode, matching capabilities contribute their instructions and tools. The primary classifier-selected skill must remain in the composition even if it came from an LLM decision rather than a regex hit. Otherwise the trace can report the right classification while the attempt receives none of that skill’s instructions.

The runtime also deduplicates identical fragments and tool names. This is not just tidiness. Repeated instructions waste context and can amplify conflicting guidance. Stable ordering makes the assembled prompt easier to compare across runs.

Compose tools within the agent’s authority

Combining skill tool lists must not widen the persona’s permissions. The conceptual rule is:

Effective tools = requested capability tools ∩ agent-permitted tools

Here is a small, executable form of the composition rule used throughout the teaching examples:

def compose_tools(agent_allowlist, skill_toolsets):
    permitted = set(agent_allowlist)
    ordered = dict.fromkeys(
        tool
        for toolset in skill_toolsets
        for tool in toolset
        if tool in permitted
    )
    return list(ordered)

assert compose_tools(
    ["search", "report_issue"],
    [["search"], ["report_issue", "refund", "search"]],
) == ["search", "report_issue"]

The empty case needs explicit semantics. “No tools selected” should remain a read-only conversational route or trigger a deliberate routing failure. If a general-purpose capability needs tools, give it an explicit permitted set. An accidental empty match must never expand authority to the entire catalog.

Exposing a tool is only one control. The executor still checks the allowlist when a call arrives. A model can emit an unexpected tool name even if it was absent from the prompt, and a custom caller can manufacture a tool-call object.

Resolve the model from configuration

The classifier proposes complexity; agent configuration determines the available base and complex models. The router resolves that combination once for the attempt.

A model tier is a product decision, not a synonym for importance. An urgent but structured issue can be handled by a fast model plus a deterministic dispatch flow. A long host analysis may need a stronger reasoning model. Sensitive writes need stronger policy controls regardless of which model is used.

The appropriate routing experiment compares task success, latency and cost by scenario family. Moving every request to a larger model can hide weak tool contracts temporarily while making the whole service slower and more expensive.

On-the-fly composition does not mean arbitrary execution

The system composes from published, known components. It does not allow a guest’s text to install a tool, edit an authorization rule or define a new backend endpoint.

There are three time scales:

  1. Deployment time: code handlers, adapters and contracts are shipped.
  2. Configuration time: approved prompts, tools, skills, models and agent settings are published and loaded.
  3. Request time: the runtime selects and combines those published capabilities for the current event.

Separating these time scales makes “dynamic” precise. The per-turn combination changes quickly. The authority to create executable capabilities remains controlled.

Resolve instruction conflicts at ownership boundaries

A booking skill may say “ask for dates first,” while a base fragment says “search first.” Adding more emphasis to both fragments does not solve the contradiction.

The better fix is to decide which component owns the decision. If a booking flow has explicit rules for missing dates, that behaviour belongs in the flow contract and its tool description. The skill should explain how to use the flow without restating another version of the same policy.

The same applies to tone and formatting. Channel fragments own presentation; skills own the procedure; code owns mandatory state transitions. This is how modularity survives beyond the first few skills.

Inspect the assembled result

The control portal’s assembly view makes the result visible: selected skills, resolved model, prompt-fragment sizes, tool exposure and retrieved context. That is more useful than showing only the name of a skill in a badge.

When a change fails, the first question is whether it reached the attempt. A correct draft that was never published, a published skill that was never reloaded and a routed skill excluded by a precondition produce similar guest-facing symptoms. They require different fixes.

The next article follows the resolved route into prompt and context assembly, where composability meets evidence, freshness and token cost.