Search⌘ K
AI Features

Add Capabilities Through One Contract

Explore how to add a new capability through an extension contract in an AI agent harness. Understand how contracts unify tool schema, permissions, runners, and locks to maintain consistency across providers. Learn the importance of separating public schemas, authority checks, execution, and journaling for robust and verifiable tool integration.

Wren had just finished the booking-rule change when the agent asked for one last thing: run availability.test.js before it reported back.

The team added a test function to the OpenAI tool array. The next live run requested it. The executor replied denied: unknown tool test. Someone then added a runner to tools.ts, but the Anthropic adapter still did not advertise the new function. The tool existed in three places and was complete in none of them.

This is a Power failure. A tool is more than the function that runs it. The model needs to know its name and inputs. Policy needs to decide whether it may run. The executor needs an implementation. The journal needs a result. Tests need to prove those pieces agree.

This lesson gives those shared facts one home: an Extension Contract.

What are we building in this lesson?

Imagine an index card for each tool. The test card contains:

name: test
input: one test-file path
permission: policy.testable must be true
runner: node --test <path>
lock: none
The five fields one capability entry must declare

OpenAI and Anthropic read the public side of the card: name, description, and inputs. Wren’s executor reads the private side: permission, runner, and lock. No provider receives the private fields.

That is the whole map. One card describes one capability. Several parts of the harness read the part they own.

Why does a new tool need more than a runner?

A runner is the function that does the work. It is one row on the tool’s card.

Boundary

What It Needs from test

Failure When It Is Absent

Provider schema

name, description, path input

The model cannot ask for the tool.

Authority

policy check and path rule

The tool runs in a session that should not have it.

Runner

bounded command and timeout

The request cannot produce useful evidence.

Receipt

normal call and result events

The session cannot explain what happened.

Drift test

names and inputs compared across adapters

One provider changes while another stays stale.

The provider schema is not a permission grant. It tells a model what it may request. The permit decides what this session will allow. Keeping those jobs separate is what lets a course demo have test available while a read-only support session refuses it.

Clear one checkbox at a time below. Each field connects the tool to a different consumer. The broken card shows what happens when a capability exists in only part of the harness.

No single consumer can make test complete. The provider needs a public schema, authority needs a permit, execution needs a runner, and the journal needs call-result events. The contract keeps those connections visible without making one module perform every job.

Where does a partial capability fail?

It is tempting to fix the first broken surface and stop. That produces a different kind of half-tool.

If you add a schema only, the model requests an unknown tool. If you add a runner only, no model can reach it. If you attach a runner directly to a provider adapter, the other provider gets a different tool set. The problem is not that any one line is difficult. The problem is that the capability has no owner.

Use the comparison to follow test through the three designs.

The Extension Contract owns facts that must agree: name, ...