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_"
Scans local and attached resources into one registry.
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
Use a local tool for file edits, code generation, and workspace-specific automation.
Use a skill for repository review, release checks, or repeated operator guidance.
Use MCP when the capability is external, shared, and should stay decoupled from one workspace repo.
Use runtime approval defaults when the capability writes durable state or remote resources.
Where behavior should live
For implementation logic, integration code, tests, and workspace-specific behavior.
For named reusable runtime inputs, operating policy, and backend-neutral assembly.
For reusable execution guidance that should travel with the workspace.
For shared remote capability surfaces that should remain external services.