@maats/flapjack
v0.4.0
Published
Flapjack AI agent SDK — embed agents in your product
Readme
@maats/flapjack
Flapjack AI agent SDK — embed agents in your product.
Install
npm install @maats/flapjackQuick Start
import { FlapjackClient } from '@maats/flapjack';
const client = new FlapjackClient({
apiKey: process.env.FLAPJACK_API_KEY!,
baseUrl: process.env.FLAPJACK_BASE_URL,
});
// List your agents
const agents = await client.listAgents();
// Create a conversation thread
const thread = await client.createThread(agents[0].id);
// Send a message and stream the response
for await (const event of client.sendMessage(thread.id, 'Hello!')) {
switch (event.type) {
case 'token':
process.stdout.write(event.delta);
break;
case 'tool_call':
console.log('\n[Tool]', event.tool.name);
break;
case 'done':
console.log('\n\nDone. Message ID:', event.messageId);
break;
case 'error':
console.error('Error:', event.code, event.detail);
break;
}
}React
Built-in hooks for React apps:
import { FlapjackProvider, useChat } from '@maats/flapjack/react';
function App() {
return (
<FlapjackProvider config={{
apiKey: process.env.NEXT_PUBLIC_FLAPJACK_API_KEY!,
baseUrl: process.env.NEXT_PUBLIC_FLAPJACK_BASE_URL,
}}>
<Chat agentId="your-agent-id" />
</FlapjackProvider>
);
}
function Chat({ agentId }: { agentId: string }) {
const { messages, sendMessage, isStreaming } = useChat(agentId);
return (
<div>
{messages.map((msg, i) => (
<div key={i}>{msg.role}: {msg.content}</div>
))}
<input
onKeyDown={(e) => {
if (e.key === 'Enter') {
sendMessage(e.currentTarget.value);
e.currentTarget.value = '';
}
}}
disabled={isStreaming}
placeholder="Type a message..."
/>
</div>
);
}Persistent Computer (Remote Control)
For app-platform integrations (Dassie-style) where every app gets its own agent with a preloaded Linux sandbox:
import { FlapjackClient, verifyWebhookSignature } from '@maats/flapjack';
const client = new FlapjackClient({ apiKey: process.env.FLAPJACK_API_KEY! });
// One call: agent + persistent sandbox + bootstrap. Idempotent on dassieAppId.
const { agent, bootstrapRunId } = await client.createAgentFromTemplate({
name: 'Grocery Tracker',
template: 'nextjs-fullstack',
repo: { url: 'https://github.com/acme/grocery', installCmd: 'pnpm install' },
envVars: [{ key: 'NODE_ENV', value: 'development' }],
webhookUrl: 'https://you.example.com/api/flapjack/webhook',
dassieAppId: 'app_abc',
});
// Live status pills data (cached server-side 10s)
const status = await client.getSandboxStatus(agent.id);
// Streaming exec (SSE, parsed into typed events)
for await (const ev of client.execSandbox(agent.id, { command: 'pnpm test' })) {
if (ev.type === 'stdout') process.stdout.write(ev.chunk);
if (ev.type === 'exit') console.log('exit', ev.exitCode);
}
// Verify inbound lifecycle webhooks (HMAC-SHA256)
const ok = await verifyWebhookSignature(rawBody, sigHeader, process.env.SECRET!);Templates: node-playwright · python-jupyter · nextjs-fullstack ·
rust-cargo · blank. See the sandbox API docs
and Dassie integration guide.
Pre-built Components
Drop-in chat UI with theming:
import { ChatPanel } from '@maats/flapjack/components';
import '@maats/flapjack/components/style.css';
<ChatPanel agentId="your-agent-id" />Exports
| Path | Description |
|------|-------------|
| @maats/flapjack | Core client and types |
| @maats/flapjack/react | React provider and hooks |
| @maats/flapjack/components | Pre-built UI components |
| @maats/flapjack/components/style.css | Component styles |
Documentation
Full docs at flapjack.chat/docs
License
MIT
