Examples
Five runnable scripts that walk progressively deeper into the SDK. All five live in packages/kit/examples/ in the open repo, are verified end-to-end against the production runtime, and copy-paste cleanly into your own project.
Set your credentials once:
# Generate one at https://console.agentnava.com → API keys
export AGENTNAVA_API_KEY=ank_live_…
# Optional — defaults to https://api.agentnava.com
export AGENTNAVA_BASE_URL=https://api.agentnava.com
1. Hello, agent
The smallest end-to-end lifecycle: push a spec, configure an agent, deploy it, start a session, send one message, stream the reply. About twenty lines.
import { AgentNava } from '@agentnava/kit';
const an = new AgentNava();
// 1) Push the spec. `instructions` is your AGENT.md — the system prompt.
const spec = await an.specs.push({
key: 'hello',
instructions: 'You are Hello — a friendly assistant. Be concise.',
});
// 2) Configure → a versioned agent.
const v = await an.agents.configure({
key: 'hello',
name: 'Hello',
modelClass: 'standard',
spec,
triggers: [{ kind: 'chat' }],
});
// 3) Deploy to a dev URL.
await an.agents.deployToTest(v.versionId);
// 4) Start a session and chat one turn.
const session = await an.sessions.start({ agentId: v.agentId, env: 'test' });
for await (const event of an.sessions.chat(session.id, 'Say hello.')) {
if (event.type === 'message-delta') process.stdout.write(event.delta);
}
Run: bun run examples/hello.ts
spec pushed: spec_4f1c9a@v1
agent version: ver_3da4cb (agt_43e7dc)
test url: http://localhost:8787/v1/test/agt_43e7dc
session: sess_1eb57f
Hello! I'm here to help — what's on your mind today?
2. Multi-turn memory
The runtime stores chat history per session. Send messages, the agent remembers what was said earlier — no extra wiring needed on your side.
// Same setup as above — push spec, configure, deploy, start session.
async function turn(session: { id: string }, message: string) {
process.stdout.write(`\n--- you → ${message} ---\n`);
for await (const e of an.sessions.chat(session.id, message)) {
if (e.type === 'message-delta') process.stdout.write(e.delta);
}
}
await turn(session, "My name is Sam. Please remember it.");
await turn(session, "What did I just tell you?");
await turn(session, "Repeat my name one more time.");
Run: bun run examples/multi-turn.ts
--- you → My name is Sam. Please remember it. ---
Got it, Sam. What can I help you with?
--- you → What did I just tell you? ---
You told me your name is Sam.
--- you → Repeat my name one more time. ---
Your name is Sam.
3. Versioned specs
Specs are immutable once pushed. Push a new version of the same key and you get spec_xyz@v2 alongside @v1 — old agent versions keep using the old spec until you reconfigure.
// v1
const v1Spec = await an.specs.push({
key: 'versioned-bot',
instructions: 'Respond in exactly five words. Always.',
});
const v1 = await an.agents.configure({
key: 'versioned-bot', name: 'Versioned', modelClass: 'standard',
spec: v1Spec, triggers: [{ kind: 'chat' }],
});
// v2 — same key, new instructions → new version
const v2Spec = await an.specs.push({
key: 'versioned-bot',
instructions: 'Respond in exactly ten words. Always.',
});
const v2 = await an.agents.configure({
key: 'versioned-bot', name: 'Versioned', modelClass: 'standard',
spec: v2Spec, triggers: [{ kind: 'chat' }],
});
console.log(`v1: ${v1.versionId} ← ${v1Spec.id}@v${v1Spec.version}`);
console.log(`v2: ${v2.versionId} ← ${v2Spec.id}@v${v2Spec.version}`);
Run: bun run examples/versioning.ts
Existing sessions pinned to v1 keep using the five-word spec. New sessions started against the agent's latest version use the ten-word spec. You can ship spec changes safely without disrupting running conversations.
4. Bring your own knowledge
Pass arbitrary text as a workflows file and the model will ground replies in it. Here we scrape a public site and feed it as the agent's source material.
import { AgentNava } from '@agentnava/kit';
const an = new AgentNava();
const URL = 'https://swatipetkar.com';
// 1) Scrape and convert to plain text.
const html = await fetch(URL).then((r) => r.text());
const text = htmlToText(html); // your own minimal stripper
// 2) Push a spec with the scraped content as a workflow file.
const spec = await an.specs.push({
key: 'aria',
instructions: 'You are Aria, a friendly assistant for Swati\'s website.',
workflows: [{ name: 'source', content: `# Source — ${URL}\n\n${text}` }],
});
const v = await an.agents.configure({
key: 'aria', name: 'Aria', modelClass: 'premium',
spec, triggers: [{ kind: 'chat' }],
});
await an.agents.deployToTest(v.versionId);
const session = await an.sessions.start({ agentId: v.agentId, env: 'test' });
for await (const e of an.sessions.chat(session.id, 'Who is Swati and what does she work on?')) {
if (e.type === 'message-delta') process.stdout.write(e.delta);
}
Run: bun run examples/aria-once.ts
For sites smaller than ~30 pages, the "stuff it into the system prompt" pattern works fine — modern models handle 100k+ tokens of context. For larger corpora, vector retrieval (planned in Knowledge) becomes necessary.
5. Claude Code-style skills
If you've structured your project like a Claude Code agent — AGENT.md at the root plus skills/<name>/SKILL.md folders — loadAgentDir reads the whole bundle in one call.
import { AgentNava, loadAgentDir } from '@agentnava/kit';
const an = new AgentNava();
// Reads:
// ./agents/concierge/AGENT.md (system prompt)
// ./agents/concierge/skills/*.md (auto-discovered)
// ./agents/concierge/subagents/*.md (delegated personas)
// ./agents/concierge/commands/*.md (user-invokable slash commands)
const spec = await an.specs.push(
loadAgentDir('./agents/concierge', { key: 'concierge' }),
);
const v = await an.agents.configure({
key: 'concierge', name: 'Concierge', modelClass: 'premium',
spec, triggers: [{ kind: 'chat' }],
});
await an.agents.deployToTest(v.versionId);
Run: bun run examples/with-claude-skills.ts
agents/concierge/
├── AGENT.md
├── skills/
│ ├── neighborhoods/SKILL.md
│ └── pricing/SKILL.md
└── commands/
└── compare-listings.md
Verified end-to-end
Every example here was run against the live production runtime at api.agentnava.com with the SDK on its current version. If something doesn't work for you, please tell us — we run the examples on each release.