Documentation menu
Documentation

Write an agent

Start with one durable responsibility, then add the human surface and capabilities it actually needs.

Start from a fresh project

This guide is self-contained. Create an empty Ayjnt project, then replace the starter agent with the files shown below. Run commands from the new project directory unless a step says otherwise.

terminal
bunx ayjnt new try-writing-agents --empty
cd try-writing-agents
bun install

# remove agents/alive once you are ready to add the guide's files

The smallest useful agent

Create agents/<route>/agent.ts and default-export a class extending Ayjnt’s Agent. Code generation discovers it, creates the Durable Object binding, and routes requests from the folder path.

You may instead import Agent directly from agents. Discovery, routing, bindings, app.tsx, tools, and workflows work the same way. Use Ayjnt’s class when you want its peer-agent and session conveniences; use Cloudflare’s class when you want the upstream surface only.

agents/counter/agent.ts
import { Agent, callable } from "ayjnt";

type State = { count: number };

export default class CounterAgent extends Agent<State> {
  initialState: State = { count: 0 };

  @callable({ description: "Increase the counter." })
  increment(by = 1) {
    this.setState({ count: this.state.count + by });
    return this.state.count;
  }
}

Add a front door

Place app.tsx beside the agent for a browser interface. Add a root cli.ts for a terminal interface. Both receive typed access generated from the agent class.

Keep privileged work out of the model loop by default. Expose narrow tools, validate their input, declare side effects, and require a person before consequential actions.

  • agent.ts — isolated durable behavior in workerd
  • app.tsx — browser UI for people
  • tools.ts — deployable tools in workerd
  • tools.host.ts — explicitly permissioned Bun capabilities
  • workflow.ts — durable multi-step work

Run it and verify the result

Open the route shown in the guide, call the method once, and confirm the returned state survives a page refresh.

terminal
bun run build
bun run dev

# the local app is now available at http://localhost:8787