Local tools

Workspace-local tools should live under resources/tools/ and export tool({...}). They are discovered at workspace startup and become selectable runtime resources.

resources/
  tools/
    write_file.mjs
    code_review.mjs

Local tools are the right place for repository-specific behavior, tightly scoped automation, or capabilities that should travel with one workspace.

Minimal local tool shape

import { z } from "zod";
import { tool } from "@botbotgo/agent-harness/tools";

export default tool({
  name: "write_file",
  description: "Write a file inside the workspace",
  inputSchema: z.object({
    path: z.string(),
    content: z.string(),
  }),
  async execute({ path, content }) {
    return { ok: true, path, bytes: content.length };
  },
});

Practical rule

Put implementation in the tool module, not in YAML. YAML should register and select the tool, not duplicate its execution logic.

Skills

Skills package repeatable operating knowledge. They should live under resources/skills/ and include a SKILL.md. Skills are not ad hoc prompt snippets. They are reusable repository-owned instructions that clarify how an agent should perform a recurring class of work.

Minimal skill package

resources/
  skills/
    repo-review/
      SKILL.md
# Repo Review

Use this skill when the task is to review one pull request or one repository slice.

- inspect changed files first
- identify concrete findings before summarizing
- prefer code references over broad opinions

A skill should encode repeatable operating guidance. If the content only makes sense for one prompt in one run, it probably belongs in the agent request, not in a shared skill package.

MCP servers

MCP servers are usually heavier shared resources than local function tools. They belong in catalogs when the capability should be centrally named, configured, and reused across agents.

Practical rule

Let workspace startup scan local and attached resources packages into one registry, then let agents whitelist the tools and skills they actually use, and select MCP tools with per-usage overrides when needed.

Catalog-style MCP server entry

apiVersion: agent-harness/v1alpha1
kind: McpServers
spec:
  - kind: McpServer
    id: awesome-github-mcp
    name: awesome-mcp/github-mcp
    description: MCP server for GitHub workflows and repository operations
    repositoryUrl: https://github.com/modelcontextprotocol/servers
    transport: stdio
    command: npx
    args:
      - -y
      - "@modelcontextprotocol/server-github"
    env:
      GITHUB_TOKEN: CHANGE_ME

The catalog should carry both the runtime fields and the human-facing metadata for a shared server preset. Treat id as the runtime identity; name, description, and repositoryUrl are catalog metadata.

The canonical agent-side spec.mcpServers shape is an object array so each agent can select remote tools and apply usage-specific overrides without mutating the shared catalog entry.

spec:
  mcpServers:
    - ref: mcp/awesome-github-mcp
      toolFilters:
        - "^issue_"
        - "^pull_request_"
    - ref: mcp/awesome-github-mcp
      name: github-with-token
      tools:
        - echo_text
      env:
        GITHUB_TOKEN: ${GITHUB_TOKEN}

Reserve MCP for shared remote capability surfaces. If the behavior is local, repository-specific, and easy to version in-tree, start with a local tool instead.

String shorthand such as - awesome-github-mcp is still accepted for compatibility, but the object form should be the documented and reviewed default.

How agents should wire extensions

The runtime should discover resources globally, but agents should still whitelist what they actually use. That keeps capability scope readable and makes approval and governance policy easier to reason about.

apiVersion: agent-harness/v1alpha1
kind: Agent
metadata:
  name: orchestra
spec:
  backend: deepagent
  modelRef: model/default
  tools:
    - tool/write-file
  skills:
    - repo-review
  mcpServers:
    - ref: mcp/awesome-github-mcp
      toolFilters:
        - "^issue_"
        - "^pull_request_"
Runtime startup

Scans local and attached resources into one registry.

Agent binding

Chooses a narrow allowed set by name instead of inheriting every available capability.

Governance and approvals

Extension power raises governance pressure. Sensitive durable memory writes and write-like MCP side effects should default to runtime-owned approval gates. Do not rely on every tool author to reinvent governance in isolation.

Operational consequence

The more remote and side-effectful a capability becomes, the more important it is that approval, inspection, and recovery remain runtime-owned instead of prompt-owned.

Common extension patterns

Local write helper

Use a local tool for file edits, code generation, and workspace-specific automation.

Shared review workflow

Use a skill for repository review, release checks, or repeated operator guidance.

Remote system access

Use MCP when the capability is external, shared, and should stay decoupled from one workspace repo.

Governed side effects

Use runtime approval defaults when the capability writes durable state or remote resources.

Where behavior should live

Use source code

For implementation logic, integration code, tests, and workspace-specific behavior.

Use YAML

For named reusable runtime inputs, operating policy, and backend-neutral assembly.

Use skills

For reusable execution guidance that should travel with the workspace.

Use MCP

For shared remote capability surfaces that should remain external services.