Harness Engineering for AI Agents · Production Systems

The Skills System

12 min read
By the end of this reading you will be able to:
  • Implement a skill with a named hook point and an auto-trigger predicate, and register it in the skill registry
  • Distinguish explicit skill invocation (/skillname prefix) from auto-triggered invocation and explain when each is appropriate
  • Trace how a pre_synthesis skill modifies the synthesis prompt and how a post_wiggum skill produces a secondary artifact

What Skills Are

Skills are modular extensions that inject behavior into the pipeline at named hook points. They do not replace pipeline stages — they modify how those stages behave for specific task types or user intentions.

Five built-in skills:

Skill Hook Mode Description
/annotate pre_synthesis auto Injects the Nanda 8-move annotated abstract framework into synthesis
/kg post_synthesis auto Generates a D3.js knowledge graph from the output
/panel post_wiggum auto Runs a 3-persona parallel evaluation panel
/deep pre_research auto Forces MAX_SEARCH_ROUNDS, disables novelty gate
/cite pre_synthesis explicit Requires source URL attribution for each claim

The Four Hook Points

pre_research   → runs before gather_research()
                 modify search strategy: MAX_SEARCH_ROUNDS, disable novelty gate

pre_synthesis  → injected into the synthesis prompt
                 add task-specific formatting requirements, frameworks, citations

post_synthesis → runs after output is written
                 generate secondary artifacts: knowledge graphs, formatted exports

post_wiggum    → runs after the verification loop completes
                 secondary evaluation: panel assessment, quality dashboards

Hook point choice determines what the skill can affect. A pre_synthesis skill can only influence what the model produces — it cannot change the search results or the final format of a file that's already been written. A post_synthesis skill has access to the final output but runs too late to affect synthesis.

Skill Registry

from dataclasses import dataclass
from typing import Callable, Optional

@dataclass
class Skill:
    name: str
    hook: str                        # "pre_research" | "pre_synthesis" | etc.
    description: str
    prompt_injection: Optional[str]  # text to inject at the hook point
    handler: Optional[Callable]      # function to call at the hook point
    auto_trigger: Callable           # predicate(task, plan) -> bool
    explicit_only: bool = False      # if True, only activates via /skillname prefix

SKILL_REGISTRY: dict[str, Skill] = {
    "annotate": Skill(
        name="annotate",
        hook="pre_synthesis",
        description="Inject Nanda Annotated Abstract framework",
        prompt_injection=NANDA_FRAMEWORK_PROMPT,
        handler=None,
        auto_trigger=lambda task, plan: any(
            kw in task.lower()
            for kw in ["paper", "abstract", "survey", "review"]
        )
    ),
    "deep": Skill(
        name="deep",
        hook="pre_research",
        description="Force MAX_SEARCH_ROUNDS, disable novelty gate",
        prompt_injection=None,
        handler=lambda ctx: ctx.update({"max_rounds": MAX_SEARCH_ROUNDS,
                                         "novelty_gate": False}),
        auto_trigger=lambda task, plan: any(
            kw in task.lower()
            for kw in ["comprehensive", "exhaustive", "deep dive", "thorough"]
        )
    ),
    # ...
}

parse_skills() and auto_activate()

def parse_skills(task: str) -> tuple[str, set]:
    """Strip /skill tokens from task; return clean task + explicit activations."""
    tokens = re.findall(r'/([a-z-]+)', task)
    activated = {t for t in tokens if t in SKILL_REGISTRY}
    clean_task = re.sub(r'/[a-z-]+\s*', '', task).strip()
    return clean_task, activated

def auto_activate(task: str, plan: Plan, explicit: set) -> set:
    """Fire auto-trigger predicates; return full set of active skills."""
    active = set(explicit)
    for name, skill in SKILL_REGISTRY.items():
        if skill.explicit_only:
            continue
        if name not in active and skill.auto_trigger(task, plan):
            active.add(name)
            log(f"[auto-activate] /{name} triggered")
    return active

Building a Custom Skill

Adding a new skill requires three things:

1. Write the skill's handler or prompt injection:

# A post_synthesis skill that generates a one-page executive summary
EXEC_SUMMARY_PROMPT = """\
The following is a detailed technical document.
Produce a 200-word executive summary suitable for a non-technical audience.
Output ONLY the summary, no headers.
"""

def generate_exec_summary(output: str, output_path: str, producer_model: str):
    prompt = EXEC_SUMMARY_PROMPT + "\n\n" + output[:4000]
    summary = call_producer(prompt, producer_model)
    summary_path = output_path.replace(".md", "-summary.md")
    write_file(summary_path, summary)
    log(f"[exec-summary] written to {summary_path}")

2. Register in SKILL_REGISTRY:

"exec-summary": Skill(
    name="exec-summary",
    hook="post_synthesis",
    description="Generate a 200-word executive summary alongside the main output",
    prompt_injection=None,
    handler=generate_exec_summary,
    auto_trigger=lambda task, plan: False,  # explicit only
    explicit_only=True
)

3. Wire the handler call in agent.py:

# In the post_synthesis hook section of agent.py:
for skill_name in active_skills:
    skill = SKILL_REGISTRY[skill_name]
    if skill.hook == "post_synthesis" and skill.handler:
        skill.handler(output, output_path, producer_model)

That's it. The skill is now invokable with python agent.py "/exec-summary Research context engineering..." and can be tested in isolation by calling generate_exec_summary() directly.

Built-in Skills in Practice

# Annotate a paper with the Nanda 8-move framework:
python agent.py "/annotate https://arxiv.org/abs/2308.04079 output.md"

# Force comprehensive search (disable novelty gate):
python agent.py "/deep Survey all context engineering techniques 2023-2025..."

# Require source attribution for every claim:
python agent.py "/cite Explain the TRPO algorithm..."

# Knowledge graph (auto-triggers on 'knowledge graph' in task):
python agent.py "Build a knowledge graph of transformer attention mechanisms..."

# Panel evaluation (auto-triggers on high complexity):
# No prefix needed for high-complexity tasks — auto-activated
python agent.py "Comprehensive analysis of all major RL algorithms..."