Skip to content

Tools vs Skills

ADL distinguishes two ways an agent can act. The distinction is the single most important concept in the schema, and it shapes how downstream generators wire your manifest into runnable code.

The short version

ToolSkill
Where it livesspec.tools[]spec.skills[]
ShapeFunction call with a JSON Schema for inputsMarkdown playbook
How the agent uses itThe model calls it as a functionThe model discovers it from a metadata listing and reads the playbook on demand at runtime
Generated asCode stubs in the target languageA bundled SKILL.md (or scaffolded blank with bare: true)
Best forDeterministic operations (DB query, API call, send email)Workflows, policies, response patterns expressed in natural language
Carries a license?NoYes (SPDX or Proprietary)

Why two concepts?

Real agents need both:

  • Some things are deterministic. "Look up this customer by ID" is a function call against a database. You want a typed input, a typed output, no creative interpretation by the LLM. That's a tool.
  • Some things are judgment-laden. "If the user reports an outage, triage it like this: first check our status page, then …" is a procedure written in prose. There's no triageOutage() function - you want the model to follow the approach. That's a skill.

Trying to express a skill as a tool produces a brittle, hard-to-test function with a giant instructions: string parameter. Trying to express a tool as a skill produces a model that hallucinates calls it can't actually make. The split keeps each in its lane.

Tools

yaml
spec:
  tools:
    - id: knowledge_search
      name: knowledge_search
      description: Search the company knowledge base
      tags:
        - knowledge
        - search
      schema:
        type: object
        properties:
          query:
            type: string
            description: The search query
        required:
          - query

The schema is free-form JSON Schema - it describes the tool's input arguments. The generator uses it to emit a typed function signature in your target language (e.g. a Go struct with json tags, a TypeScript interface, a Rust struct with serde derives) plus a stub function body for you to fill in.

A tool's id must match ^[a-zA-Z_][a-zA-Z0-9_]*$ - it becomes a symbol name in generated code.

Some ids are reserved as built-in tools that the generator implements for you (e.g. read, bash, write, edit). For those, name, description, tags, and schema may be omitted - the generator supplies them.

See Reference: tools for every field.

Skills

yaml
spec:
  skills:
    - id: incident-response
      bare: true
      name: incident-response
      description: How to triage a paged production incident, draft an initial
        response, and notify stakeholders.
      license: Apache-2.0
      tags:
        - operations
        - incident

A skill is a markdown playbook stored alongside the agent. At startup, only each skill's metadata (name and description from its SKILL.md frontmatter) is added to the system prompt - a short "menu" of what the agent knows how to do. When the model decides a skill is relevant, the runtime reads the full SKILL.md body and includes it in the conversation for the rest of the session.

This makes skills cheap to declare: a manifest can list many skills without bloating the startup prompt - only the ones the model actually reaches for spend tokens. See Reference: skills for the runtime mechanism.

Two sources:

  • bare: true - scaffold an empty SKILL.md for you to fill in locally. Use this for proprietary workflows or one-off playbooks.
  • From the registry - set source (and optionally version) to pull a published skill from the shared registry. Use this for common playbooks you don't want to maintain yourself.

Every skill carries a license (SPDX identifier or Proprietary), so the licence travels with the playbook regardless of where it's consumed. See Reference: License identifiers for the accepted set.

See Reference: skills for every field.

Picking between them

A quick decision tree:

  1. Does the action have side effects on an external system? (write to DB, call an API, send a notification) → almost certainly a tool.
  2. Is the "action" really a procedure the model should follow? (how to handle a refund request, how to escalate, what tone to use) → skill.
  3. Both? Many features split cleanly: a refund tool that issues the API call, plus a refund-policy skill that tells the model when and how to issue refunds.

When in doubt, ask: if I removed the LLM and called this from a script, would the script still make sense? If yes, it's a tool. If the "function" is "be a thoughtful assistant about X", it's a skill.