# Build an agent skill

> Write, test and submit an Agent Skill: a folder with a SKILL.md and optional scripts that gives an IXO or Qi agent one repeatable, reviewable capability.

An Agent Skill is a folder that teaches an AI agent one repeatable capability. Its `SKILL.md` tells
the agent when to use the capability, what information it needs, which steps to follow, which tools
or scripts it may use, what output to produce, and how to handle errors, uncertainty and user
confirmation. In this guide you build a skill called `claim-evidence-checklist`, test its script,
validate it and submit it for review.

With a skill, an agent does not improvise from a prompt. It loads the skill, follows its
instructions, runs its documented scripts, and produces output that fits a real workflow. That
makes its behaviour repeatable and easier to review.

## When to build a skill

Build a skill when the capability is reusable. For example:

- **Evidence review checklist.** Compare the evidence a claim requires with the evidence submitted.
- **Document generator.** Produce structured output such as invoices, reports, attestations or
  summaries.
- **Data transformer.** Convert input files into a structured format that can be reviewed or
  submitted into a workflow.
- **Workflow assistant.** Take an agent through a known operational process with clear steps and
  outputs.
- **API interaction pattern.** Give an agent safe, documented instructions for an approved outside
  service.
- **IXO task helper.** Prepare claim metadata, evidence summaries, credential checklists or
  workflow reports.

A skill can help an agent prepare, inspect, summarise or generate. It does not replace protocol
permissions, backend services or governed state changes. An action that changes state on IXO still
goes through a declared API, MCP tool, SDK or governed workflow.

## Skill or something else?

Pick the building block that matches what you are building.

| You are building | Use |
| --- | --- |
| Reusable agent instructions, scripts, templates or generated files | An Agent Skill, the subject of this guide |
| A live tool interface that agents call to reach IXO services | An MCP tool. See [Model Context Protocol](/mcp/model-context-protocol) |
| A backend oracle service that observes state, evaluates evidence or triggers workflows | The Agentic Oracles ADK. See [Agentic Oracles](/articles/agentic-oracles) |
| A React interface where users talk to oracles | The [Oracles Client SDK](/sdk-reference/oracles-client-sdk) |
| A protocol-level state change or governed integration | [IXO Protocol](/protocols/ixo-protocol) and the [SDK reference](/sdk-reference/index), not a skill file alone |

## How skills work

Skills use progressive disclosure. At startup, an agent can discover skills from their metadata,
such as the skill name and description. When a skill is relevant, the agent loads its `SKILL.md`
instructions. If the skill includes scripts, the agent can run them and use their output without
loading the script source into its context.

So `SKILL.md` carries the weight. The agent relies on it to know when to use the skill, what
inputs to collect, how to run the scripts and how to read their results.

## Required structure

Every skill is a folder, and the folder must contain `SKILL.md`:

```text
skills/
└── your-skill-name/
    └── SKILL.md
```

A fuller skill can include prompts, scripts, examples, templates and its own license:

```text
skills/
└── your-skill-name/
    ├── SKILL.md
    ├── prompts/
    │   └── detailed.md
    ├── scripts/
    │   └── helper.py
    ├── examples/
    │   └── example-input.json
    ├── templates/
    │   └── template.html
    └── LICENSE.txt
```

## Naming rules

The folder name must match the `name` field in `SKILL.md`. Use lowercase letters, numbers and
single hyphens.

Use:

```text
claim-evidence-checklist
digital-mrv-report
invoice-creator
```

Avoid:

```text
ClaimEvidenceChecklist
claim_evidence_checklist
claim--evidence
-claim-review
claim-review-
```

## Before you start

You need:

- A checkout of the repository you are contributing the skill to. The commands below run from its
  root.
- Python, to run the helper script.
- Git, to submit the skill.

## Create your first skill

The skill in this example, `claim-evidence-checklist`, helps an agent produce a checklist that
compares the evidence a claim requires with the evidence submitted.

### 1. Create the folder

From the repository root:

```bash
mkdir -p skills/claim-evidence-checklist/scripts
mkdir -p skills/claim-evidence-checklist/examples
```

### 2. Add `SKILL.md`

Create:

```text
skills/claim-evidence-checklist/SKILL.md
```

Use this template:

````md
---
name: claim-evidence-checklist
description: Generate a review checklist for an IXO claim by comparing required evidence against submitted evidence and identifying gaps before human or oracle review.
license: Apache-2.0
compatibility: Claude, Qi Agents
allowed-tools: Read Write Bash
metadata:
  author: IXO
  version: "1.0.0"
  category: verification
---

# Claim Evidence Checklist

## Overview

This skill helps an AI agent prepare a structured evidence checklist for an IXO claim.

Use it when a user needs to review whether a claim has enough evidence for verification, attestation, dispute resolution, or escalation.

The skill does not verify the claim by itself. It prepares a checklist that can support human review, Agentic Oracle evaluation, or a governed IXO workflow.

## When to use this skill

Use this skill when the user asks to:

- review evidence for a claim
- identify missing evidence
- prepare a verification checklist
- compare submitted evidence against program requirements
- summarize evidence readiness before claim review
- support a digital MRV or outcomes verification process

Do not use this skill to make final verification decisions unless the surrounding workflow explicitly grants that authority.

## Inputs needed

Ask for or locate:

1. Claim ID or claim reference
2. Claim type
3. Entity or project the claim is about
4. Required evidence list
5. Submitted evidence list
6. Review rules or acceptance criteria, if available
7. Reviewer or verifier role, if relevant

If any required information is missing, ask for it or mark it as unknown.

## Workflow

Follow these steps:

1. Identify the claim and the entity it concerns.
2. List the evidence required for this claim type.
3. List the evidence that has been submitted.
4. Match submitted evidence against required evidence.
5. Mark each requirement as:
   - `present`
   - `missing`
   - `partial`
   - `unknown`
6. Summarize risks, gaps, and next actions.
7. Do not invent evidence.
8. Do not treat user-provided statements as verified IXO state unless they come from an approved source.
9. If a governed workflow action is required, direct the user to the relevant IXO API, SDK, MCP tool, or review process.

## Output format

Return a concise review report:

```text
Claim: [claim ID]
Claim type: [claim type]
Entity: [entity or project]

Evidence checklist:
- [status] [required evidence] — [submitted evidence or gap]

Summary:
- Present:
- Missing:
- Partial:
- Unknown:

Recommended next action:
- [request more evidence / send to verifier / escalate / continue review]
```

## Script

This skill includes a helper script:

```bash
python scripts/build_checklist.py examples/claim-review-input.json checklist.md
```

The script reads JSON input and writes a Markdown checklist. It classifies each requirement as present, missing, or optional-not-submitted (counted in `unknown`); extend the script if you need a `partial` state.

Use the script when the user provides structured claim and evidence data or asks for a file output.

## Script input format

```json
{
  "claim_id": "claim-001",
  "claim_type": "delivery-completed",
  "entity": "Clean Cooking Project A",
  "required_evidence": [
    {
      "type": "delivery_receipt",
      "description": "Signed delivery receipt from field partner",
      "required": true
    },
    {
      "type": "geo_photo",
      "description": "Geotagged installation photo",
      "required": true
    }
  ],
  "submitted_evidence": [
    {
      "type": "delivery_receipt",
      "title": "Signed delivery receipt",
      "reference": "evidence-123"
    }
  ]
}
```

## Script output

The script writes a Markdown checklist and prints a JSON summary.

Expected success output (matches what the script prints for the example input above):

```json
{
  "status": "success",
  "claim_id": "claim-001",
  "claim_type": "delivery-completed",
  "entity": "Clean Cooking Project A",
  "required": 2,
  "submitted": 1,
  "present": 1,
  "missing": 1,
  "unknown": 0,
  "output_file": "checklist.md"
}
```

## Safety and correctness rules

- Do not invent claim state, evidence, permissions, or verification results.
- Separate user-provided information from verified IXO-backed state.
- Treat this checklist as decision support, not final attestation.
- Ask for clarification when required evidence or claim type is missing.
- Do not expose private claim data, credentials, or evidence outside the requested workflow.
- Do not submit, attest, reject, or dispute a claim unless the user explicitly asks and the required governed interface is available.
````

The next steps add the script and the example file that `SKILL.md` refers to.

### 3. Add a helper script

Create:

```text
skills/claim-evidence-checklist/scripts/build_checklist.py
```

Use this script:

```python
#!/usr/bin/env python3
"""
Build a Markdown evidence checklist for a claim.

Usage:
  python scripts/build_checklist.py <input.json> <output.md>

Example:
  python scripts/build_checklist.py examples/claim-review-input.json checklist.md
"""

import json
import sys
from pathlib import Path
from typing import Any, Optional


def load_json(path: str) -> dict[str, Any]:
    with open(path, "r", encoding="utf-8") as file:
        return json.load(file)


def normalize_type(value: Any) -> str:
    return str(value or "").strip().lower()


def build_checklist(data: dict[str, Any]) -> tuple[str, dict[str, Any]]:
    claim_id = data.get("claim_id", "unknown")
    claim_type = data.get("claim_type", "unknown")
    entity = data.get("entity", "unknown")

    required_evidence = data.get("required_evidence", [])
    submitted_evidence = data.get("submitted_evidence", [])

    if not isinstance(required_evidence, list):
        raise ValueError("required_evidence must be a list")

    if not isinstance(submitted_evidence, list):
        raise ValueError("submitted_evidence must be a list")

    submitted_by_type: dict[str, list[dict[str, Any]]] = {}

    for item in submitted_evidence:
        if not isinstance(item, dict):
            continue

        evidence_type = normalize_type(item.get("type"))
        if not evidence_type:
            continue

        submitted_by_type.setdefault(evidence_type, []).append(item)

    rows: list[str] = []
    missing = 0
    present = 0
    unknown = 0

    for requirement in required_evidence:
        if not isinstance(requirement, dict):
            unknown += 1
            rows.append("- unknown — Invalid evidence requirement entry")
            continue

        evidence_type = normalize_type(requirement.get("type"))
        description = requirement.get("description", evidence_type or "Unnamed evidence requirement")
        is_required = requirement.get("required", True)

        matches = submitted_by_type.get(evidence_type, [])

        if matches:
            present += 1
            references = ", ".join(
                str(match.get("reference") or match.get("title") or "submitted evidence")
                for match in matches
            )
            rows.append(f"- present — {description} ({references})")
        elif is_required:
            missing += 1
            rows.append(f"- missing — {description}")
        else:
            unknown += 1
            rows.append(f"- unknown — Optional evidence not submitted: {description}")

    recommended_action = (
        "Request missing evidence before verification."
        if missing > 0
        else "Ready for reviewer or verifier assessment."
    )

    markdown = "\n".join(
        [
            f"# Evidence Checklist: {claim_id}",
            "",
            f"Claim type: {claim_type}",
            f"Entity: {entity}",
            "",
            "## Checklist",
            "",
            *rows,
            "",
            "## Summary",
            "",
            f"- Present: {present}",
            f"- Missing: {missing}",
            f"- Unknown or optional: {unknown}",
            "",
            "## Recommended next action",
            "",
            recommended_action,
            "",
        ]
    )

    summary = {
        "status": "success",
        "claim_id": claim_id,
        "claim_type": claim_type,
        "entity": entity,
        "required": len(required_evidence),
        "submitted": len(submitted_evidence),
        "present": present,
        "missing": missing,
        "unknown": unknown,
    }

    return markdown, summary


def main(
    input_file: Optional[str] = None,
    output_file: Optional[str] = None,
    **kwargs: Any,
) -> dict[str, Any]:
    if not input_file:
        raise ValueError("input_file is required")

    if not output_file:
        raise ValueError("output_file is required")

    data = load_json(input_file)
    markdown, summary = build_checklist(data)

    output_path = Path(output_file)
    output_path.write_text(markdown, encoding="utf-8")

    summary["output_file"] = str(output_path)
    return summary


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python scripts/build_checklist.py <input.json> <output.md>", file=sys.stderr)
        sys.exit(1)

    try:
        result = main(input_file=sys.argv[1], output_file=sys.argv[2])
        print(json.dumps(result, indent=2))
    except Exception as error:
        print(f"Error: {error}", file=sys.stderr)
        sys.exit(1)
```

### 4. Add example input

Create:

```text
skills/claim-evidence-checklist/examples/claim-review-input.json
```

Use this example:

```json
{
  "claim_id": "claim-001",
  "claim_type": "delivery-completed",
  "entity": "Clean Cooking Project A",
  "required_evidence": [
    {
      "type": "delivery_receipt",
      "description": "Signed delivery receipt from field partner",
      "required": true
    },
    {
      "type": "geo_photo",
      "description": "Geotagged installation photo",
      "required": true
    },
    {
      "type": "beneficiary_confirmation",
      "description": "Beneficiary confirmation record",
      "required": true
    }
  ],
  "submitted_evidence": [
    {
      "type": "delivery_receipt",
      "title": "Signed delivery receipt",
      "reference": "evidence-123"
    },
    {
      "type": "geo_photo",
      "title": "Installation photo",
      "reference": "evidence-456"
    }
  ]
}
```

### 5. Test the script

From the repository root:

```bash
cd skills/claim-evidence-checklist
python scripts/build_checklist.py examples/claim-review-input.json checklist.md
```

Expected terminal output:

```json
{
  "status": "success",
  "claim_id": "claim-001",
  "claim_type": "delivery-completed",
  "entity": "Clean Cooking Project A",
  "required": 3,
  "submitted": 2,
  "present": 2,
  "missing": 1,
  "unknown": 0,
  "output_file": "checklist.md"
}
```

Open `checklist.md` and check that it lists the present and missing evidence clearly.

### 6. Validate the skill

Return to the repository root:

```bash
cd ../..
./scripts/validate-skill.sh skills/claim-evidence-checklist
```

<Info>
  The repository you contribute to may ship a `scripts/validate-skill.sh` helper. If your checkout
  does not include it, make the same checks by hand, using the list below and the
  [Pre-submit checklist](#pre-submit-checklist).
</Info>

The validator checks that:

- The skill folder exists.
- The folder name uses the required format.
- `SKILL.md` exists.
- YAML frontmatter exists.
- The `name` field exists.
- The `name` field matches the folder name.
- The `description` field exists.
- The description length is within the allowed limit.

Fix any validation errors before you submit.

### 7. Submit the skill

Use the normal contribution flow:

```bash
git checkout -b add-claim-evidence-checklist
git add skills/claim-evidence-checklist
git commit -m "Add claim-evidence-checklist skill"
git push origin add-claim-evidence-checklist
```

Then open a pull request against the main repository. [Review and publishing](#review-and-publishing)
says what happens next.

## Check the result

Your skill is ready to submit when all of these are true:

- The script prints `"status": "success"` with the counts shown in step 5, and `checklist.md`
  exists.
- The validator passes, or you have made the same checks by hand.
- Everything in the [Pre-submit checklist](#pre-submit-checklist) holds.

## When something goes wrong

| What you see | What it means | What to do |
| --- | --- | --- |
| `Usage: python scripts/build_checklist.py <input.json> <output.md>` | The script was run with fewer than two arguments | Pass both the input file and the output file |
| `Error: required_evidence must be a list` or `Error: submitted_evidence must be a list` | The input JSON has the wrong shape | Make the field a JSON array, as in the example input |
| `./scripts/validate-skill.sh` is not found | Your checkout does not ship the validator | Make the validator's checks by hand, as in step 6 |
| The validator reports a name error | The folder name and the `name` field differ, or the name breaks the naming rules | Rename the folder or the field so that they match and follow the [naming rules](#naming-rules) |

## Writing a strong `SKILL.md`

`SKILL.md` is the agent's operating manual. A good one tells the agent exactly what to do, so it
does not have to guess.

<AccordionGroup>
  <Accordion title="Start with the purpose" icon="bullseye">
    Explain the capability in one or two sentences.

    Good:

    ```text
    This skill helps an agent prepare an evidence checklist for an IXO claim.
    ```

    Weak:

    ```text
    This skill helps with claims.
    ```
  </Accordion>
  <Accordion title="Define when to use it" icon="route">
    Give clear trigger conditions.

    Example:

    ```text
    Use this skill when the user asks to review evidence, identify missing documents, or prepare a claim for verification.
    ```
  </Accordion>
  <Accordion title="List required inputs" icon="list-check">
    Tell the agent what information it must collect before acting.

    Example:

    ```text
    Required inputs:
    - claim ID
    - claim type
    - required evidence list
    - submitted evidence list
    - reviewer role
    ```
  </Accordion>
  <Accordion title="Give step-by-step instructions" icon="list-ol">
    Avoid vague instructions. Make the workflow explicit.

    Example:

    ```text
    1. Identify the claim type.
    2. Load the required evidence list.
    3. Compare submitted evidence against each requirement.
    4. Mark each item present, missing, partial, or unknown.
    5. Produce a summary and recommended next action.
    ```
  </Accordion>
  <Accordion title="Specify the output format" icon="file-lines">
    Agents are more reliable when they know exactly what to produce.

    Use tables, JSON schemas, Markdown templates, or structured sections.
  </Accordion>
  <Accordion title="Document scripts" icon="terminal">
    If the skill includes scripts, document each script in `SKILL.md`.

    Include:
    - what the script does
    - how to run it
    - required inputs
    - expected outputs
    - common errors
  </Accordion>
  <Accordion title="Add safety rules" icon="shield-check">
    Tell the agent what not to do.

    For IXO and Qi workflows, make clear that the agent must not invent verified state, bypass permissions, expose private data, or perform state-changing actions outside declared interfaces.
  </Accordion>
</AccordionGroup>

## Script standards

Skills can include scripts for work that should be deterministic or reusable, or that is too
detailed to keep in the agent's context. Every script must meet three requirements:

<Steps>
  <Step title="It runs from the command line">
    The agent must be able to execute it through a shell command.

    ```bash
    python scripts/build_checklist.py input.json output.md
    ```
  </Step>

  <Step title="It exposes a returning main function">
    Python scripts should provide a `main()` function that accepts keyword arguments and returns a result (the tutorial script uses `typing.Optional` for path arguments).

    ```python
    from typing import Any, Optional

    def main(
        input_file: Optional[str] = None,
        output_file: Optional[str] = None,
        **kwargs: Any,
    ) -> dict[str, Any]:
        return {"status": "success", "output_file": output_file or ""}
    ```
  </Step>

  <Step title="It is documented in SKILL.md">
    The agent should not have to read the source code to understand normal usage.
  </Step>
</Steps>

Prefer standalone scripts with no external dependencies. If a script needs dependencies, document
them.

## Frontmatter reference

| Field | Required | Purpose |
| ----- | -------- | ------- |
| `name` | Yes | Skill identifier. Must match the folder name. |
| `description` | Yes | Short discovery description used by agents to decide when the skill is relevant. |
| `license` | No | License for the skill, such as `MIT` or `Apache-2.0`. |
| `compatibility` | No | Agent runtimes or environments the skill is designed for. |
| `allowed-tools` | No | Tool access the skill expects, such as `Read`, `Write`, or `Bash`. |
| `metadata` | No | Additional key-value information such as author, version, or category. |

Write the description with care. It is one of the first things an agent reads when it decides
whether the skill applies.

## IXO and Qi safety guidance

A skill shapes how an agent behaves. Write it as operational instructions, not as an open-ended
prompt. For IXO and Qi workflows:

- **Do not invent state.** If a claim, credential, domain or evidence record is not available,
  mark it as missing or unknown.
- **Respect authority.** Say which actions need a user, a reviewer, an oracle, a credential or a
  governed workflow.
- **Separate support from decision.** A skill can support review. It does not make a final
  attestation unless the workflow allows it. On IXO, a decision oracle produces facts and the IXO
  decision engine decides. See [Design an evaluator](/guides/users/design-an-evaluator).
- **Use declared interfaces.** Send state-changing actions through IXO APIs, SDKs, MCP tools or
  protocol workflows.
- **Protect sensitive data.** Keep secrets, credentials, private keys, access tokens and private
  evidence out of skill files.
- **Make outputs inspectable.** Prefer structured output that people, agents and workflow systems
  can review.

## Common skill patterns

### Instruction-only skill

For simple behaviour that needs no script: writing style guides, review checklists, workflow
instructions, question-answering procedures and data classification rules.

```text
skills/
└── greeting-assistant/
    └── SKILL.md
```

### Script-backed skill

For deterministic processing: generating files, transforming data, validating inputs, producing
structured reports, and calculating totals or metrics.

```text
skills/
└── report-generator/
    ├── SKILL.md
    ├── scripts/
    │   └── generate_report.py
    └── examples/
        └── input.json
```

### Template-backed skill

For output that follows a reusable document structure: invoices, attestations, MRV reports,
evidence summaries and governance briefs.

```text
skills/
└── attestation-summary/
    ├── SKILL.md
    ├── templates/
    │   └── summary-template.md
    └── examples/
        └── example.md
```

### IXO workflow skill

For a repeatable IXO or Qi workflow: claim intake, evidence readiness checks, handoff packets for
reviewers, programme rule checklists, and support for agentic oracle reviews.

```text
skills/
└── digital-mrv-claim-review/
    ├── SKILL.md
    ├── scripts/
    │   └── build_review_packet.py
    └── examples/
        └── mrv-claim-input.json
```

## Pre-submit checklist

Before you open a pull request, check that:

- The folder name matches the skill `name`.
- `SKILL.md` exists.
- `SKILL.md` has valid YAML frontmatter.
- `name` and `description` are present.
- The description says when the skill should be used.
- The instructions are clear, structured and complete.
- Scripts run from the command line.
- Scripts have a returning `main()` function.
- Scripts are documented in `SKILL.md`.
- The example inputs work.
- No secrets or credentials are included.
- No harmful or unsafe instructions are included.
- The local validator passes, when your repository provides `scripts/validate-skill.sh`.

When that script exists:

```bash
./scripts/validate-skill.sh skills/your-skill-name
```

## Review and publishing

After you open a pull request, the skill is reviewed before it is published. Review checks:

- correctness
- instruction quality
- security
- compliance with the skill structure
- safe script behaviour
- clear documentation

When the skill is approved and merged, it is packaged and published. The published skill gets a
content identifier, or CID, which agents can use to fetch that version of the skill. CIDs are
content-addressed, so any change to the skill creates a new CID.

## Next steps

<CardGroup cols={2}>
  <Card title="Model Context Protocol" icon="plug" href="/mcp/model-context-protocol">
    Use MCP when agents need live access to IXO tools and governed actions.
  </Card>
  <Card title="Agentic Oracles" icon="robot" href="/articles/agentic-oracles">
    How oracle services observe state, evaluate evidence and trigger workflow actions.
  </Card>
  <Card title="Oracles Client SDK" icon="message-bot" href="/sdk-reference/oracles-client-sdk">
    Build React interfaces where users work with agentic oracles.
  </Card>
  <Card title="Qi Intelligent Cooperating System" icon="diagram-project" href="/articles/qi-intelligent-cooperating-system">
    How people, agents, applications and services cooperate on IXO.
  </Card>
</CardGroup>
