Tool Extension Lifecycle

Tools are the smallest executable capability that an Aegis task session can call. A tool can read a repo file, run a bounded check, call a connector, write an artifact, inspect a source bundle, or perform another explicit operation on behalf of a workflow.

Adding a tool is a boundary change. Treat it as runtime work, not just a helper function.

Lifecycle

  1. Choose the tool family and owner module.
  2. Define the input and output contract.
  3. Declare the tool manifest.
  4. Assign permission tokens and action type.
  5. Implement the handler behind the right boundary helpers.
  6. Add negative tests before broad usage.
  7. Document operator-facing behavior.
  8. Verify capability inventory and profile reachability.

Choose An Owner Module

Prefer a focused module for a tool family instead of adding more code to src/tools/index.ts.

Current reference pattern:

Use the same shape for new families:

export function registerExampleTools(registry: ToolRegistryLike): void {
  registry.register<ExampleInput, ExampleOutput>({
    id: "example.read",
    actionType: "example-read",
    requiredAllowlist: ["example:read"],
    description: "Read example data.",
    target: (input) => input.id,
    describeResult: (result) => `${result.items.length} item(s)`,
    handler: async (input, context) => {
      return readExampleData(input, context);
    }
  });
}

Then call the family registration function from createToolRegistry().

Tool Manifest

Every tool needs a manifest with stable metadata:

Field Purpose
id Stable tool id. Use a namespace such as repo.read-text, gmail.search-messages, or artifact.write.
actionType Policy/audit class for the action, such as repo-read, repo-write, external-write, or repo-check.
requiredAllowlist Permission tokens that a task profile must hold before runtime can call the tool.
description Operator-facing capability description.
runtimeIsolation Optional explicit runtime isolation metadata. If omitted, the registry infers a conservative baseline from the action type, allowlist, id, and safety metadata.
target Short target string for policy, approval, trace, and UI context.
describeResult Optional concise summary for traces and task-session output.
preApprovalValidate Optional validation that must run before an approval checkpoint is created.
handler The only place that performs the operation.

High-risk generic tools should also declare visibility, riskLevel, and safety metadata so operators can distinguish typed safe paths from advanced escape hatches.

runtimeIsolation should name the runtime boundary a reviewer cares about:

Field Typical values
boundary local-process, workspace, network, external-service, none
networkEgress none, local-only, operator-configured, external-service, connector-api
filesystem none, repo-read, repo-write, workspace-artifacts, repo-and-workspace, source-package
secrets none, oauth-token, secret-registry, provider-credential
subprocess none, bounded-host-command, container

Use explicit metadata when inference would hide an important review fact, such as a connector API that only reads but still needs OAuth, a sandbox phase with operator-configured network access, or a tool that crosses both repo and artifact boundaries. Metadata is descriptive inventory first; handlers still need the normal containment, permission, approval, and token-access checks.

Permission Tokens

requiredAllowlist uses all-token semantics. A task profile must have every required token unless the runtime explicitly models an alternative permission set.

Good:

requiredAllowlist: ["repo:check", "verifier:command"]

This means a broad repo permission alone does not unlock host command execution.

Avoid:

requiredAllowlist: ["external-write"]

for connector-specific writes. Use connector-specific tokens such as gmail:modify, github:write, or a typed operation token when possible. Broad categories should not silently unlock concrete side effects.

Action Type And Policy

The actionType should match the real boundary crossed by the handler.

Boundary Typical action type
Repository read repo-read
Repository mutation repo-write
Bounded verifier command repo-check
Workspace artifact write workspace-write
External API read external-read or connector-specific read
External API mutation external-write or connector-specific write
Secret lookup operator-only helper path, not agent-callable

If a tool can mutate a repo, external system, device, payment, account, policy, secret, workflow, or Aegis itself, it needs explicit approval and negative tests proving agents cannot bypass that approval.

Handler Boundary Rules

Handlers should be thin and boundary-aware.

For repo tools, use resolveWithinRepoRoot() before reading, writing, or selecting a command cwd. That helper rejects sibling-prefix escapes and symlink escapes.

Approval Preview

For generic or dynamic write tools, validate the requested operation before runtime asks for approval. The preview should bind the approval to concrete inputs such as connector id, account id, method, path, target, summary, and expected side effect.

The generic OAuth API request tools in src/connectors/oauth-api-tools.ts are the current reference:

Tests

Every new tool family should have focused tests near the owning boundary.

Minimum test set:

Examples:

Operator Docs

Update docs when a tool changes what operators can do or approve.

Document:

For public-facing tool families, link the guide from the relevant workflow, connector, security, or architecture docs.

Capability Inventory

Registered tools appear in the capability inventory. Before calling a tool complete, verify that the inventory communicates:

This keeps tools inspectable before they are used by workflows or headless agents.

Review Checklist

Before merging a new or changed tool: