Getting started with agents

This page takes you from an empty workspace to a running agent you can chat with, all on your machine. If you have never run the CLI before, set up Node 24 and Docker first with the CLI getting started guide, then come back here.

An agent lives inside a workspace, a folder that can hold many agents and workflows side by side. The steps below assume you have a workspace already (stackbone init my-workspace). If you don't, create one first.

1. Scaffold an agent

From inside your workspace, add an agent by name:

stackbone add agent support

This writes a deep-agents/support/ folder with a single index.ts file. The command is fully offline: the agent becomes a member of the workspace stackbone init already linked, so no sign-in is required. It only writes new files, it never edits your existing code, and re-running it is safe as long as nothing collides (pass --force to overwrite a name that does).

The folder it creates follows the convention the runtime scans for:

deep-agents/support/
  index.ts   # model, system prompt, and tools: the whole agent

2. Write the agent

index.ts default-exports defineDeepAgent from @stackbone/sdk/deep. Give it a model id and a system prompt:

deep-agents/support/index.ts
import { defineDeepAgent } from '@stackbone/sdk/deep';

export default defineDeepAgent({
  model: 'openai/gpt-4o-mini',
  systemPrompt: [
    'You are the support agent for Acme.',
    'Answer order questions in two sentences or fewer.',
    "If you can't find an order, say so plainly and ask for the order number.",
  ].join('\n'),
});

model is a bare model id string. defineDeepAgent resolves it through your org's managed model key, which the runtime injects as OPENROUTER_API_KEY, so you never wire a provider client by hand. Pass a built LangChain chat-model instance instead of a string to target a provider directly.

3. Add a tool

A tool is a plain LangChain tool built with tool(...) from @langchain/core/tools. Its handler can reach the ambient stackbone client like any other code in your workspace. Here is a tool that looks up an order in the agent's own database:

deep-agents/support/index.ts
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { defineDeepAgent } from '@stackbone/sdk/deep';
import { stackbone } from '@stackbone/sdk';
import { eq } from '@stackbone/sdk/db';
import { orders } from './schema';

const lookupOrder = tool(
  async ({ orderId }: { orderId: string }) => {
    const [order] = await stackbone.database
      .select()
      .from(orders)
      .where(eq(orders.id, orderId))
      .limit(1);
    return order ? JSON.stringify(order) : 'not_found';
  },
  {
    name: 'lookup_order',
    description: 'Look up an order by its id.',
    schema: z.object({ orderId: z.string() }),
  },
);

export default defineDeepAgent({
  model: 'openai/gpt-4o-mini',
  systemPrompt: [
    'You are the support agent for Acme.',
    'Use lookup_order when the user gives an order number.',
    'Answer order questions in two sentences or fewer.',
  ].join('\n'),
  tools: [lookupOrder],
});

The model decides when to call the tool from its description and schema. Keep the description plain and the schema tight, and the agent calls it at the right moment.

4. Run the local emulator

stackbone dev

stackbone dev builds every agent it discovers in-process, brings up a local Postgres, Redis, and MinIO stack, and starts the emulator at http://127.0.0.1:4242. It hot-reloads when you edit a file, so you can leave it running while you work. The boot banner prints a cloud Studio deeplink (the recommended way in) and a local fallback URL.

5. Talk to the agent

An agent speaks the standard OpenAI Chat Completions and Anthropic Messages APIs, so any client built for either works against it with nothing but a base URL and a key. Pick the agent with the request's model field, which is the agent's folder name:

curl http://127.0.0.1:4242/openai/v1/chat/completions \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer local-dev' \
  -d '{"model":"support","messages":[{"role":"user","content":"Where is order 123?"}]}'

Locally, any non-empty bearer key is accepted. The call is stateless by default: send the full messages[] array each time, exactly like calling OpenAI or Anthropic directly. To have the server keep the transcript for you instead, send an x-stackbone-session header with a key you choose. To keep replaying the history yourself but still group the turns into one session, send x-stackbone-conversation instead. See the agent protocol for the full contract, including streaming and the Anthropic wire.

From Studio. Open the Studio deeplink from the boot banner and chat with your agent in the Playground. Studio reaches the local emulator over the tunnel, so you get the same surface you would get in the cloud.

6. Call the agent from a workflow

Inside a workflow step, reach this agent by name with callDeepAgent from @stackbone/sdk/workflow. It runs one turn of the agent in the same process, no HTTP hop, and resolves with { text }:

import { callDeepAgent } from '@stackbone/sdk/workflow';

async function askSupport(question: string) {
  'use step';
  return callDeepAgent('support', question);
}

callDeepAgent must be called from inside a 'use step' function, so the turn becomes a durable checkpoint. See Calling an agent from a workflow for the full detail.

Where to go next

  • Examples: complete agents you can copy: a greeter, a config-driven agent, and one backed by retrieval.
  • What is an agent: the authoring and discovery model in full.
  • Workflow + Agents: wire this agent into a durable workflow.

The platform for agent developers.Build, ship and observe agentsthat survive prod.

© 2026 · STACKBONEBUILT WITH ❤️ FROM CANADA AND SPAIN