The Standard Pipeline

The pipeline is not hardcoded — it is declared as metadata in skills/pipeline/default.skill.md, the library's main skill. This skill has name: default and role: main. It is the implicit terminal node of every inherit chain — when a chain ends without reaching default, the runtime automatically appends it. This ensures every tool gets the standard pipeline without requiring explicit $inherit: default.

Every metadata key resolves to a middleware tool by exact name match via findTool(). The pipeline is overridable: place a replacement tool earlier in the search path, or use $inherit: false to opt out of the default pipeline entirely.

# skills/pipeline/default.skill.md
---
name: default
metadata:
  # Annotations — control cascade behavior
  $private: [role, tags, visibility]
  $merge:
    paths: prepend
    mcp: shallow
    include: append
  $order:
    $pre-configure:
      before: [$configure]
    $configure:
      before: [$post-configure]
    $post-configure:
      before: [$pre-execute]
    $pre-execute:
      before: [$execute]
    $execute:
      before: [$post-execute]
    cwd:
      after: [$pre-configure]
      before: [$configure]
    workspace:
      after: [$pre-configure]
      before: [$configure]
    mcp:
      after: [$pre-configure]
      before: [$configure]
    gateway:
      after: [$pre-configure]
      before: [$configure]
    event:
      after: [$pre-configure]
      before: [$configure]
    paths:
      after: [$pre-configure]
      before: [$configure]
    params:
      after: [$pre-configure]
      before: [$configure]
    visibility:
      after: [$pre-configure]
      before: [$configure]
    returns:
      after: [$pre-configure]
      before: [$configure]
    model:
      after: [$pre-configure]
      before: [$configure]
    include:
      after: [$pre-configure]
      before: [$configure]
    role:
      after: [$pre-configure]
      before: [$configure]
    tags:
      after: [$pre-configure]
      before: [$configure]
    frontmatter:
      after: [$pre-configure]
      before: [$configure]
    directives:
      after: [$post-configure]
      before: [$pre-execute]
    trust:
      after: [$pre-execute]
      before: [$execute]
    validate-args:
      after: [$pre-execute]
      before: [$execute]
    validate-allowed-tools:
      after: [$pre-execute]
      before: [$execute]
    execute:
      after: [$execute]
    validate-returns:
      after: [execute]
      before: [agent-execute]
    agent-execute:
      after: [validate-returns]
      before: [$post-execute]
    log:
      after: [$pre-configure]
      before: [$configure]
    "$.paths[?(@ == '${locals.config.workspace:-./workspace}')]":
      before: ["$.paths[*]"]
    "$.paths[?(@.external)]":
      after: ["$.paths[*]"]

  # Values — plain YAML, merged through the cascade
  role: main
  tags: [meta-internal]
  visibility: hidden
  workspace: "${locals.config.workspace:-./workspace}"
  paths:
    - "${locals.config.workspace:-./workspace}"
    - "."
    - { external: "${locals.config.cwd}/.agent-apps/packages" }
    - { external: "${locals.config.library}" }
    - { ignore: "dist" }
    - { ignore: "node_modules" }
    - { ignore: ".git" }
    - { ignore: ".cache" }
    - { ignore: ".kiro" }
    - { ignore: "workspace" }
  gateway:
  validate-args:
  validate-allowed-tools:
  directives:
  execute:
  validate-returns:
  agent-execute:
  include: "${locals.config.library}/extensions/agent/agent-context.md"
---

The library main skill uses $private to keep role, tags, and visibility from propagating to child tools. $merge declares that paths uses prepend (child paths before parent), mcp uses shallow merge (child servers merge into parent's), and include uses append (child includes added after parent's). $order declares the pipeline ordering using six phase sentinels that form a fixed backbone: $pre-configure$configure$post-configure$pre-execute$execute$post-execute. Configuration middleware runs between $pre-configure and $configure. Validation and trust run between $pre-execute and $execute. Execution and post-processing run after $execute. Workspace is pinned to the front of paths with external entries at the end. All other metadata keys (the pipeline middleware) are public and propagate through the cascade. It has no $inherit — it IS the terminal node.

The include entry references the agent-context markdown file (providing channel description) and prepends its content to every agent-driven skill's prompt. This provides standard context without requiring each skill to declare it. Keys like cwd, mcp, event, trust, and log appear only in $order (for ordering constraints) — they are not value keys in the default pipeline. They activate when a user's skill declares them in its own metadata (e.g., log: { reporter: "agent" }).

The resulting chain for a typical invocation:

  1. $pre-configure sentinel — virtual anchor, does not execute.
  2. Configuration phase (between $pre-configure and $configure) — cwd, workspace, mcp, gateway, event, paths, params, visibility, returns, model, include, role, tags, frontmatter, log, and custom metadata middleware. paths sets target.locals.config.paths and calls target.manager.refresh() to re-resolve the current tool. include prepends included file content. log configures per-run log settings (reporter, scope, level) from cascade metadata. Middleware without explicit constraints defaults to after: [$configure], before: [$post-configure].
  3. $configure sentinel — virtual anchor, does not execute.
  4. $post-configure sentinel — virtual anchor, does not execute.
  5. directives (after: [$post-configure], before: [$pre-execute]) — Parses ctx.locals.prompt.expanded for remark directives, injects the matching tool for each.
  6. $pre-execute sentinel — virtual anchor, does not execute.
  7. Validation phase (between $pre-execute and $execute) — trust, validate-args, validate-allowed-tools. trust gates tool execution based on trust rules, prompting for approval via gateway-receive if needed. validate-allowed-tools checks whether the current tool is permitted by the caller's allowed-tools constraint — denied calls throw.
  8. $execute sentinel — virtual anchor, does not execute.
  9. execute (after: [$execute]) — Executes code tools and MCP tools. Calls the tool's fn directly on the target context — not through the orchestrator. Always calls next() afterward. If execute is absent from the chain (e.g., removed by auto-static cycle detection for middleware tools' own pipelines) and no middleware set a result, the runtime calls the tool's fn directly as a fallback.
  10. validate-returns (after: [execute]) — Validates the return value against the tool's returns JSON Schema, if declared.
  11. agent-execute (after: [validate-returns], before: [$post-execute]) — Invokes the agent for markdown tools with a prompt. Reads prompt, config, allowedTools, and returns from the served context and calls ctx.manager.invoke('agent', { prompt, config, allowedTools, returns }).
  12. $post-execute sentinel — virtual anchor, does not execute.

Debug, profile, and observe are not part of the default pipeline. They are activated via the $hook cascade annotation or injected middleware. See the Events & Hooks specification for details.

Content and frontmatter are loaded when a tool is first resolved by findTool(). The tool definition carries the markdown body and parsed YAML. The orchestrator sets ctx.locals.prompt, ctx.run.origin.frontmatter, and ctx.run.tool.* from the definition before building the chain.

Ask AI