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).
spec:
tools:
- ref: weather.get-forecast
as: get_forecastReusable 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.
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
$ phrony agents validate ./my-agent/agent.yaml
$ phrony agents publish ./my-agent/agent.yaml
$ phrony agents deploy default/my-agent@0.2.0Bump 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 worker using the Phrony SDK connects to the runtime, registers weather.get-forecast@1.0.0, and runs your handler on each invoke:
import os
from phrony.worker import Worker
worker = Worker(
worker_id="weather-worker-1",
runtime_addr=os.environ.get("PHRONY_RUNTIME_ADDR", "127.0.0.1:7777"),
)
@worker.tool("weather.get-forecast", version="1.0.0", max_concurrency=4)
async def get_forecast(args: dict, ctx) -> dict:
# Your integration: HTTP API, database, internal service, etc.
city = args["city"]
return {"temp_c": 12, "conditions": "cloudy", "city": city}
await worker.connect() # dial runtime, register handlers, process invoke messagesDispatch 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).
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