Recipes.
Six runnable examples, from a device-flow CLI agent to a multi-agent review pipeline.
Recipe 1: CLI agent with device-flow auth and streaming
A complete interactive CLI agent with device-flow auth, streaming, and multi-turn sessions.
import * as readline from 'node:readline/promises';
import { stdin, stdout } from 'node:process';
import { Runner, MatildaCore, createFileTokenStore, createSession } from '@maincode-ai/matilda-agent-sdk';
import { homedir } from 'node:os';
import { join } from 'node:path';
const { store, lock } = createFileTokenStore(join(homedir(), '.matilda', 'tokens.json'));
const runner = new Runner({
core: new MatildaCore({ baseUrl: 'https://matilda.maincode.com/api' }),
});
// Try to restore persisted tokens, fall back to interactive login
const restored = await runner.auth.restore({ clientId: 'matilda-code', tokenStore: store, tokenLock: lock });
if (!restored) {
console.log('Starting device flow authentication...');
await runner.auth.loginWithDeviceFlow({ clientId: 'matilda-code', tokenStore: store, tokenLock: lock });
console.log('Authenticated!');
}
const session = createSession({
name: 'cli-assistant',
purpose: 'general',
instructions: 'Be helpful, concise, and friendly.',
});
const rl = readline.createInterface({ input: stdin, output: stdout });
while (true) {
const input = await rl.question('\nYou: ');
if (!input.trim() || input.toLowerCase() === 'exit') break;
process.stdout.write('Agent: ');
for await (const event of session.stream(input)) {
if (event.type === 'message.delta') process.stdout.write(event.delta);
}
process.stdout.write('\n');
}
rl.close();Recipe 2: Client tools (weather + calculator)
An agent that uses client tools to answer questions requiring external data.
import { Runner, MatildaCore, stream, type ToolHandlers } from '@maincode-ai/matilda-agent-sdk';
const runner = new Runner({
core: new MatildaCore({ baseUrl: 'https://matilda.maincode.com/api' }),
});
if (!(await runner.auth.getTokens())) {
await runner.auth.loginWithDeviceFlow({ clientId: 'matilda-code' });
}
const clientTools = [
{ name: 'get_weather', description: 'Get current weather for a city', parameters: { type: 'object' } },
{ name: 'calculate', description: 'Evaluate a math expression', parameters: { type: 'object' } },
];
const toolHandlers: ToolHandlers = {
get_weather: async (args) => {
const city = (args.city as string) ?? 'unknown';
// In reality, call a weather API
return { content: JSON.stringify({ city, temp: 22, condition: 'sunny' }) };
},
calculate: async (args) => {
try {
const result = Function(`return (${args.expression})`)();
return { content: String(result) };
} catch {
return { content: 'Invalid expression', isError: true };
}
},
};
for await (const event of stream(
{ name: 'assistant', instructions: 'Use the available tools to answer.' },
'What is the weather in Sydney, and what is 15 * 23?',
{ toolHandlers, clientTools },
)) {
if (event.type === 'client.tool.requested') {
console.log(`→ ${event.name}(${JSON.stringify(event.args)})`);
}
if (event.type === 'client.tool.result') {
console.log(`← ${event.result}`);
}
if (event.type === 'message.delta') process.stdout.write(event.delta);
}Recipe 3: Multi-agent code review pipeline
Sequential pipeline: security review → performance review → synthesis.
import { Agent, Runner, MatildaCore } from '@maincode-ai/matilda-agent-sdk';
const runner = new Runner({
core: new MatildaCore({ baseUrl: 'https://matilda.maincode.com/api' }),
});
if (!(await runner.auth.getTokens())) {
await runner.auth.loginWithDeviceFlow({ clientId: 'matilda-code' });
}
const security = new Agent({
name: 'security',
purpose: 'analysis',
instructions: 'Review for vulnerabilities. Be specific.',
});
const performance = new Agent({
name: 'performance',
purpose: 'analysis',
instructions: 'Review for efficiency. Be specific.',
});
const synthesiser = new Agent({
name: 'synthesiser',
purpose: 'analysis',
instructions: 'Merge reviews into a prioritised action list. Use 🔴 🟡 🟢 priority.',
});
const code = 'function getUserData(userId, db) { var query = "SELECT * FROM users WHERE id = " + userId; }';
const [sec, perf] = await Promise.all([
runner.run(security, `Review:\n\`\`\`javascript\n${code}\n\`\`\``),
runner.run(performance, `Review:\n\`\`\`javascript\n${code}\n\`\`\``),
]);
const combined = `## Security\n${sec.finalOutput}\n\n## Performance\n${perf.finalOutput}`;
const result = await runner.run(synthesiser, combined);
console.log(result.finalOutput);Recipe 4: Dynamic instructions with metadata
An agent whose instructions adapt based on runtime metadata.
import { Agent, Runner, MatildaCore, run } from '@maincode-ai/matilda-agent-sdk';
const runner = new Runner({
core: new MatildaCore({ baseUrl: 'https://matilda.maincode.com/api' }),
});
if (!(await runner.auth.getTokens())) {
await runner.auth.loginWithDeviceFlow({ clientId: 'matilda-code' });
}
const agent = new Agent({
name: 'code-reviewer',
purpose: 'code',
instructions: ({ input, metadata }) => {
const lang = (metadata.language as string) ?? 'auto-detect';
const strictness = (metadata.strictness as string) ?? 'normal';
return [
'Review the following code.',
`Language: ${lang}`,
`Strictness: ${strictness}`,
'Focus on: correctness, security, and readability.',
'Cite line numbers when possible.',
].join('\n');
},
});
const result = await run(agent, 'function add(a, b) { return a + b }', {
metadata: { language: 'JavaScript', strictness: 'strict' },
});
console.log(result.finalOutput);Recipe 5: Stream resume with disconnect recovery
Start a stream, simulate a disconnect, and resume from the last cursor.
import { stream, resumeAgentStream, configureClient } from '@maincode-ai/matilda-agent-sdk';
configureClient({ baseUrl: 'https://matilda.maincode.com/api' });
let streamId: string | null = null;
let lastEventId: string | undefined;
let receivedText = '';
console.log('Starting stream...');
try {
for await (const event of stream({ name: 'writer' }, 'Write a very long essay about Australia.')) {
if (event.type === 'stream.started') streamId = event.streamId;
if (event.type === 'cursor') lastEventId = event.lastEventId;
if (event.type === 'message.delta') {
receivedText += event.delta;
// Simulate disconnect after 500 chars
if (receivedText.length > 500) {
console.log('\n--- Simulated disconnect ---');
break;
}
}
}
} catch (err) {
console.log('Disconnected:', err);
}
console.log(`Received ${receivedText.length} chars before disconnect.`);
// Resume from the last cursor
if (streamId) {
console.log('\n--- Resuming ---');
const result = await resumeAgentStream(streamId, lastEventId, {
onEvent: (event) => {
if (event.type === 'message.delta') process.stdout.write(event.delta);
},
});
console.log(`\nTotal output: ${result.finalOutput.length} chars`);
}Recipe 6: Custom Runner with file token store
A standalone Runner with persistent auth for CLI or long-running service use.
import {
Runner,
MatildaCore,
createFileTokenStore,
configureClient,
} from '@maincode-ai/matilda-agent-sdk';
import { homedir } from 'node:os';
import { join } from 'node:path';
const tokenPath = join(homedir(), '.matilda', 'tokens.json');
const { store, lock } = createFileTokenStore(tokenPath);
const runner = new Runner({
core: new MatildaCore({ baseUrl: 'https://matilda.maincode.com/api' }),
});
// Restore persisted tokens or login interactively
const restored = await runner.auth.restore({ clientId: 'matilda-code', tokenStore: store, tokenLock: lock });
if (!restored) {
await runner.auth.loginWithDeviceFlow({
clientId: 'matilda-code',
tokenStore: store,
tokenLock: lock,
});
}
// Runner is ready — tokens auto-refresh on 401
const result = await runner.run(
{ name: 'helper', instructions: 'Be concise.' },
'What is the capital of Australia?',
);
console.log(result.finalOutput);
// Later: logout clears the token store
// await runner.auth.logout();