Quick start

Quick start · Step 4

Add a tool binding

Declare a tool on your agent and dispatch it through an application worker.

Steps 1–3 gave you a manifest with no tools. Most agents call at least one capability—here you add a binding on the Agent and connect a worker that implements it.

Add a binding on the Agent

Add a spec.tools entry on your agent.yaml. The ref identifies the tool; as is the name the model sees. Put schema and side-effect class in the Tool file—bindings only need those fields when you narrow or override (see Tools).

agent.yaml (excerpt)
spec:
  tools:
    - ref: weather.get-forecast
      as: get_forecast

Reusable Tool document (optional)

For shared capabilities, define a separate kind: Tool file in a tools/ folder. The binding's ref uses namespace.name without a version suffix—the runtime resolves the Tool file's metadata.version. See Tool resource.

tools/weather.get-forecast.yaml
apiVersion: phrony.com/v1
kind: Tool

metadata:
  name: get-forecast
  namespace: weather
  version: 1.0.0

spec:
  description: Look up the weather forecast for a city.
  side_effect_class: read_only
  input_schema:
    inline:
      type: object
      properties:
        city:
          type: string
      required: [city]

Validate and publish

terminal
$ phrony agents validate ./my-agent/agent.yaml
$ phrony agents publish ./my-agent/agent.yaml
$ phrony agents deploy default/my-agent@0.2.0

Bump metadata.version whenever you publish a changed manifest.

Connect a worker

The runtime does not run your tool code. A worker process dials the runtime, registers weather.get-forecast@1.0.0, and handles invoke messages on the Work gRPC stream.

Tool dispatch

phrony-runtime

session

your worker

your code

Runtime dispatches invoke to your worker

A minimal TypeScript worker using the Phrony SDK connects to the runtime, registers weather.get-forecast@1.0.0, and runs your handler on each invoke:

worker.ts
import { Worker } from "@phrony/sdk";

const worker = new Worker({
  runtimeAddr: process.env.PHRONY_RUNTIME_ADDR ?? "127.0.0.1:7777",
  workerId: "weather-worker-1",
});

worker.registerTool({
  tool: "weather.get-forecast",
  version: "1.0.0",
  maxConcurrency: 4,
  async handler({ city }: { city: string }) {
    // Your integration: HTTP API, database, internal service, etc.
    return { temp_c: 12, conditions: "cloudy", city };
  },
});

await worker.connect(); // dial runtime, register handlers, process invoke messages

Dispatch flow, failure modes, and integrity checks: Tool dispatch.

What you end up with

Put it together: the Tool file defines the capability (description, schema, side-effect class); agent.yaml only wires it with ref and as. The binding ref must match the Tool identity (weather.get-forecast here).

agent.yaml
apiVersion: phrony.com/v1
kind: Agent

metadata:
  name: my-agent
  namespace: default
  version: 0.2.0

secrets:
  openai:
    fromEnv: OPENAI_API_KEY

spec:
  purpose: Answer questions clearly and concisely.
  instructions:
    text: |
      You are a helpful assistant. Be accurate and concise.
  model:
    provider: openai
    name: gpt-4o
  tools:
    - ref: weather.get-forecast
      as: get_forecast

output:
  format: text