Skip to content

Tools

IO exposes a set of built-in tools to the orchestrator LLM via the GitHub Copilot SDK. The model decides when to call these tools based on the user's request. All tool calls are auto-approved — no user confirmation is needed.

Defining Tools

Tools are defined with the defineTool helper from @github/copilot-sdk and use Zod for parameter validation:

ts
import { defineTool } from "@github/copilot-sdk";
import { z } from "zod";

const myTool = defineTool("my_tool", {
  description: "A brief description of what this tool does",
  parameters: z.object({
    input: z.string().describe("The input to process"),
  }),
  handler: async ({ input }) => {
    return `Processed: ${input}`;
  },
});

The defineTool function takes a tool name and an options object with:

  • description — tells the LLM when to use this tool
  • parameters — a Zod schema that validates and types the incoming arguments
  • handler — an async function that receives the validated parameters and returns a string result

Built-in Tools

All tools are created in src/copilot/tools.ts via the createTools(deps) factory. The factory receives a ToolDeps object that injects wiki, squad, and other service functions.

Wiki Tools

ToolDescriptionParameters
wiki_readRead a page from IO's knowledge base wikipath: string — relative path to the wiki page
wiki_writeWrite or update a page in the knowledge basepath: string — relative path under pages/ ending in .md; content: string — Markdown content
wiki_searchSearch the knowledge base for matching pagesquery: string — search query
wiki_listList all wiki pages(none)
wiki_deleteDelete a wiki pagepath: string — relative path to the wiki page

Squad Tools

ToolDescriptionParameters
squad_createCreate a persistent project squad that remembers decisions and contextslug: string — unique identifier; name: string — display name; project_path: string — path to project directory; universe?: string — 80s universe theme (a-team, transformers, thundercats, gi-joe, aliens, ghostbusters). Auto-assigned if omitted.
squad_analyzeScan a project directory and return analysis of languages, frameworks, test tools, and CI/CD configurationproject_path: string — path to the project directory to analyze
squad_add_agentAdd a named specialist agent to a squad. Auto-assigns the next available character from the squad's universe.slug: string — squad slug; role_title: string — free-form role (e.g., "Frontend Architect"); charter: string — description of the agent's responsibilities; model_tier?: stringhigh, medium, or low (default: medium)
squad_agentsList the agent roster for a squad with character names, roles, and statusslug: string — squad slug
squad_remove_agentRemove a named agent from a squadslug: string — squad slug; character_name: string — the character name of the agent to remove
squad_reset_agentClear an agent's error state and return them to idle without removing them. Preserves charter, role title, character name, and lead/QA flags. Drops the cached Copilot session so the next task starts fresh. Safe no-op on non-error agents.slug: string — squad slug; character_name: string — character name of the agent to reset
squad_recallRecall a squad's context and past decisionsslug: string — squad slug
squad_statusList all squads and their status(none)
squad_log_decisionLog an important decision for a squadslug: string — squad slug; decision: string — the decision made; context?: string — reasoning
squad_delegateDelegate a task to a squad's worker agentslug: string — squad slug; task: string — the task to delegate; agent?: string — character name of a specific agent to target (e.g., "Hannibal", "Optimus Prime")
squad_set_leadDesignate an agent as the squad's team lead. The lead must be a dedicated PM / Senior Engineer with no domain responsibility — their sole job is coordinating, delegating, and reviewing. The lead automatically holds veto power on PR promotion.slug: string — squad slug; character_name: string — character name of the agent to make team lead
squad_set_qaMark a squad agent as a QA reviewer with veto power. QA agents must approve before a PR is promoted from draft to ready.slug: string — squad slug; character_name: string — character name of the agent; is_qa: boolean — whether this agent is a QA reviewer
squad_task_reviewsGet the peer reviews left on a completed task. Reviewers tagged ⭐ (lead) and 🛡️ (QA) hold veto power — any rejection from either blocks PR promotion.task_id: string — the task ID to fetch reviews for
squad_deleteDelete a squadslug: string — squad slug

Available Universes

When creating a squad, you can optionally specify one of six 80s pop culture universes. Each universe provides a pool of characters that are assigned to agents in order:

UniverseCharacters
a-teamHannibal, Face, B.A. Baracus, Murdock, Amy Allen, Frankie Santana
transformersOptimus Prime, Bumblebee, Ratchet, Prowl, Wheeljack, Jazz, Ironhide, Grimlock
thundercatsLion-O, Tygra, Panthro, Cheetara, WilyKit, WilyKat, Snarf
gi-joeDuke, Scarlett, Snake Eyes, Flint, Lady Jaye, Breaker, Doc, Roadblock
aliensRipley, Hicks, Bishop, Vasquez, Hudson, Newt, Apone, Drake
ghostbustersVenkman, Egon, Ray, Winston, Janine, Louis, Dana, Gozer

Each character comes with a personality description that influences the agent's communication style in its responses.

Squad Coverage Warnings

squad_status, squad_agents, and squad_delegate surface a ⚠️ warning when any of the following are missing:

  • A dedicated team lead designated via squad_set_lead whose role is coordination-only (PM / Senior Engineer with no domain responsibility). The warning also fires if a lead is set but their role title looks like a domain specialist (e.g. "Frontend Lead", "Test Manager").
  • A QA reviewer designated via squad_set_qa.
  • A test/quality engineer — an agent whose role_title contains test, qa, or quality.

Delegation is not blocked by these warnings, but the gap should be fixed before promoting work. The team lead, QA reviewers, and test engineers (when designated as QA) all hold veto power on PR promotion — any rejection from any of them keeps the PR as a draft.

Shell

ToolDescriptionParameters
shellRun a shell command on the user's machinecommand: string — the command to run; timeout_secs?: number — timeout in seconds (default: 60); working_dir?: string — working directory

WARNING

Shell commands execute with the IO process's permissions. Output is truncated to 8 000 characters.

Web

ToolDescriptionParameters
web_fetchFetch a URL and return its content as texturl: string — URL to fetch; max_length?: number — max characters to return (default: 5 000)

File Operations

ToolDescriptionParameters
file_opsRead, write, or list files on the local filesystemoperation: "read" | "write" | "list" — operation to perform; path: string — file or directory path; content?: string — content to write; recursive?: boolean — recurse into subdirectories

GitHub

ToolDescriptionParameters
githubInteract with GitHub (issues, PRs, comments) via gh CLIcommand: string — the gh CLI command to run

Skills

ToolDescriptionParameters
skill_listList installed skills(none)
skill_installInstall a skill from a git reporepo_url: string — git repository URL
skill_removeRemove an installed skillslug: string — skill slug
skill_searchSearch the skills.sh registryquery: string — search query

Configuration

ToolDescriptionParameters
config_updateUpdate an IO configuration value at runtimekey: string — config key; value: string — new value

System

ToolDescriptionParameters
check_updateCheck for and apply IO updates(none)

Adding a New Tool

  1. Define the tool in src/copilot/tools.ts inside the createTools() function using defineTool:
ts
const myTool = defineTool("my_tool", {
  description: "Describe what this tool does",
  parameters: z.object({
    input: z.string().describe("The input to process"),
  }),
  handler: async ({ input }) => {
    // Your logic here
    return `Result: ${input}`;
  },
});
  1. Add it to the returned array at the bottom of createTools():
ts
return [
  wikiRead, wikiWrite, wikiSearch,
  squadCreate, squadRecall, squadStatus, squadLogDecision,
  shell, webFetch, fileOps,
  myTool,  // ← add here
];

That's it — the orchestrator automatically picks up every tool in the array and exposes it to the LLM.

Tips

  • Name: Use snake_case — this is the identifier the LLM uses to call the tool
  • Description: Be specific — the LLM relies on this to decide when your tool is relevant
  • Parameters: Use Zod's .describe() on each field so the model knows what to pass
  • Error handling: Return an error string from the handler; the LLM will see the message and can retry or adjust

Tool Permissions

Tools execute with the same permissions as the IO process. When running as a daemon, ensure the process user has only the access it needs.

Released under the MIT License.