Implement tools
Register tools, health checks, and handlers with the @agentapps/sdk.
Implement your tools
Use createApp() from @agentapps/sdk to build your app.
Register a tool
app.tool(name, config)The config object includes:
- description — what the tool does
- parameters — JSON Schema describing the input
- annotations — declarative hints (see below)
- handler — async function that receives a
ToolContextand returns the result
Register a health check
app.health(handler)Produce an AppFactory
app.toFactory()Produces an AppFactory for the controller to use when spawning instances.
ToolContext capabilities
The ToolContext (ctx) passed to your handlers provides:
| Capability | Description |
|---|---|
ctx.log | Structured logging |
ctx.progress | Progress reporting |
ctx.stream | Streaming responses |
ctx.signal | AbortSignal for cancellation |
ctx.secrets.getSystem | Get system-level secrets |
ctx.secrets.getUser | Get user-level secrets |
ctx.auth.getStatus | Check auth status |
ctx.requestAuth | Request interactive OAuth authentication (returns AuthResult with accessToken) |
ctx.storage | Key-value storage scoped to installationId (get, set, delete, list) |
ctx.volume | Volume file storage — POSIX-style filesystem operations (list, read, write, delete, stat, getTempPath) |
ctx.share | Sharing layer — create and revoke public URLs for files in the volume (share, revoke) |
ctx.intent | Cross-app tool invocation via intents |
ctx.emit | Emit an event |
ctx.requestAuth | Request interactive auth |
ctx.openUrl | Open a URL in the user's browser |
ctx.storage — key-value storage
Persistent key-value store scoped to the current installation. Use it for preferences, cached data, and small app state.
// Store and retrieve a value
await ctx.storage.set('user:preferences', { theme: 'dark' });
const prefs = await ctx.storage.get('user:preferences');
// List keys with a prefix
const keys = await ctx.storage.list('user:');
// Delete a key
await ctx.storage.delete('user:preferences');ctx.volume — volume file storage
POSIX-style filesystem operations against the workspace volume. Paths are relative to the volume root (no leading slash). All installations in a workspace share the same volume.
// Write a file
await ctx.volume.write('output/report.json', new TextEncoder().encode(JSON.stringify(data)));
// Read it back
const bytes = await ctx.volume.read('output/report.json');
const content = bytes ? new TextDecoder().decode(bytes) : null;
// List a directory
const entries = await ctx.volume.list('output');
// Get file metadata
const stat = await ctx.volume.stat('output/report.json');
// Get a temp path (scoped to the current session)
const tmpPath = ctx.volume.getTempPath('scratch.json');ctx.share — public URL sharing
Create and revoke public URLs for files stored on the volume. Useful when your tool produces a file that the user needs to download or share.
// Create a public URL for a volume file
const result = await ctx.share.share('output/report.json', {
expiresIn: 3600, // expires in 1 hour
});
console.log(result.url); // https://...
// Revoke the URL when no longer needed
await ctx.share.revoke(result.url);ctx.intent — cross-app tool invocation
Call a tool on a bound app (declared in your app's requires manifest). The host resolves the binding, opens a session to the target app, calls the tool, and returns the result.
// Call the "send_message" tool on a bound messaging app
const result = await ctx.intent('messenger', 'send_message', {
channel: '#general',
text: 'Hello from my app!',
});Tool annotations
Annotations are declarative hints about the tool's behavior:
readOnlyHint— tool does not modify statedestructiveHint— tool may destroy dataidempotentHint— repeated calls with same args produce same resultopenWorldHint— tool interacts with external systems
Secrets
Always use SDK callbacks (ctx.secrets.getSystem / ctx.secrets.getUser). Never write .secrets/ files directly.
Next steps
- Test your app — run the conformance suite
- Advanced — events, OAuth, and cross-app intents