“Software and cathedrals are much the same; first we build them, then we pray.” --Sam Redwine
Made with ❤️ by Jay Mathis
Intellibrix is a model-agnostic, TypeScript-native framework for building AI-capable software out of composable components. It pairs a small structural model (Structure → Brick → Program → Step → Action) with a typed agent loop, tools, memory, multi-agent composition and MCP support, plus ready-made bricks for agentic software engineering.
1.0 is a clean-break rewrite. Coming from 0.x? See MIGRATION.md.
provider('anthropic:claude-sonnet-5'), provider('openai:gpt-4.1'), or any OpenAI-compatible endpoint (Ollama, vLLM, OpenRouter).Requires Node 22+.
npm install intellibrix @intellibrix/ai-sdk zod @ai-sdk/anthropic
# or scaffold a project:
npx @intellibrix/cli init my-agent
import { provider } from '@intellibrix/ai-sdk'
import { Brick, Intelligence, defineTool } from 'intellibrix'
import { z } from 'zod'
const brick = new Brick({
name: 'assistant',
intelligence: new Intelligence({
provider: provider('anthropic:claude-sonnet-5'),
model: 'claude-sonnet-5',
system: 'You are a concise assistant.'
})
})
brick.use([defineTool({
name: 'get_time',
description: 'Get the current time as an ISO string',
input: z.object({}),
execute: async () => new Date().toISOString()
})])
const { text } = await brick.ask('What time is it?')
console.log(text)
Guides, a cookbook and the full API reference are at intellibrix.dev.
Brick is a software component that provides specific functionality.Structure is a collection of Bricks that share state (structure.state) and usage accounting, and can coordinate.Program is a named, optionally schema-typed workflow on a Brick. Every Program is automatically exposed to models as a tool (brick.tools()).Steps, which contain Actions, executed in sequence to process and transform data.Intelligence gives a Brick model access via a Provider. A Provider performs exactly one model step per call; runAgentLoop owns iteration, tool dispatch and approvals.defineTool) are typed functions a model may call. Attach them with brick.use(...), or get everything with brick.toolset().You aren't limited to these: extend a Brick and make it work however you want.
const intelligence = new Intelligence({ provider: provider('openai:gpt-4.1'), model: 'gpt-4.1' })
await intelligence.ask('Summarize this', { threadId: 'chat-1' }) // → { text, messages, steps, usage }
await intelligence.object(z.object({ sentiment: z.enum(['pos', 'neg']) }), 'I love it') // validated output
for await (const event of intelligence.stream('Tell me a story')) { /* StreamEvents */ }
await intelligence.embed('some text')
await intelligence.image('a shiny red apple') // if the provider supports it
Vendor adapters (@ai-sdk/anthropic, @ai-sdk/openai, @ai-sdk/google, @ai-sdk/openai-compatible) are optional peers, loaded lazily. Use compatibleProvider(model, { baseURL, apiKey }) for local or self-hosted models, or aiSdkProvider(languageModel) to wrap any AI SDK model.
Some open and free models print tool calls into their reply (<|tool_call_start|>[read_file(path='a.txt')]<|tool_call_end|>, or Hermes/Qwen-style <tool_call>{...}</tool_call>) instead of using native tool calling. Wrap the provider and they drive the agent loop like any other:
import { textToolCalls } from 'intellibrix'
const intelligence = new Intelligence({
provider: textToolCalls(compatibleProvider(model, { baseURL, apiKey })),
model
})
Native tool calls pass through untouched, markup is held back while streaming, and approvals and schema validation still apply. Pass parsers to add other formats, or knownToolsOnly to ignore calls to tools you didn't offer.
brick.program({
name: 'word_count',
description: 'Count the words in a piece of text.',
input: z.object({ text: z.string() }),
steps: [{ actions: [{ method: async ({ text }) => ({ words: text.split(/\s+/).filter(Boolean).length }) }] }]
})
await brick.run('word_count', { text: 'hello brick world' }) // validated, run directly…
await brick.ask('How many words are in "hello brick world"?') // …or called by the model as a tool
@intellibrix/structures)import { supervisor, router, sequential, parallel, handoffTool, asTool } from '@intellibrix/structures'
const team = supervisor({ supervisor: leadIntelligence, bricks: [researcher, writer], maxDepth: 3 })
await team.ask('Write a briefing on Structures')
supervisor: a lead model delegates to sub-bricks, each wrapped as a tool.router: one structured classification step, then dispatch to the matching brick.sequential / parallel: pipelines and fan-out.handoffTool: transfer control between bricks.structure:hop events let you reconstruct the full call graph of a run.@intellibrix/mcp)import { mcpTools, serveMcp } from '@intellibrix/mcp'
// Mount a remote server's tools into a Brick…
const { tools, close } = await mcpTools({ transport: 'stdio', command: 'npx', args: ['some-mcp-server'] })
brick.use(tools)
// …or expose your Brick/Structure to Claude Desktop, Cursor, etc.
await serveMcp(brick, { transport: 'stdio' })
Sampling and elicitation are supported. Or from the CLI: intellibrix mcp serve ./src/brick.ts.
KeyValueStore, ConversationMemory, VectorStore, with in-memory implementations in core.@intellibrix/memory-sqlite: zero-dependency node:sqlite conversation memory and vector store.@intellibrix/sql: SQL key-value store (Sequelize) and Postgres + pgvector PgVectorStore (HNSW).intellibrix/testing) validate your own store implementations.import { SQLiteConversationMemory } from '@intellibrix/memory-sqlite'
const intelligence = new Intelligence({
provider, model,
memory: new SQLiteConversationMemory({ path: './chat.db' })
})
await intelligence.ask('My name is Ada', { threadId: 'ada' })
await intelligence.ask('What is my name?', { threadId: 'ada' }) // remembers
onRunEvent emits run:*, model:*, tool:* and approval:* events.@opentelemetry/api is an optional peer).brick.usage).Checkpointer seam for durable execution, with recordProvider / replayProvider for deterministic fixtures.intellibrix/testing provides MockProvider and mockTool for offline tests.structure.events.on('add', ({ brick }) => console.log(`Added ${brick.id}`))
const structure = new Structure({ name: 'My Structure', logLevel: 'debug' }) // Pino, one shared transport
brick.schedule({
name: 'Nightly',
schedule: '0 0 * * *', // cron syntax or a Date
start: true,
method: () => console.log('Running nightly job')
})
brick.unschedule('Nightly')
Set INTELLIBRIX_LOG_STDERR to log JSON to stderr (required for stdio MCP servers).
Runnable examples live in examples/:
| Example | Shows |
|---|---|
coding-agent |
A terminal coding agent with jailed workspace tools and human approvals, backed by OpenRouter (OPENROUTER_API_KEY) |
supervisor |
Multi-agent delegation, running offline with MockProvider |
qa |
A custom Brick subclass with a Program |
mcp-server |
A Brick served over MCP |
// A coding agent with human-in-the-loop approvals
const brick = new TerminalBrick({
intelligence: new Intelligence({
provider: compatibleProvider('openrouter/free', {
baseURL: 'https://openrouter.ai/api/v1',
apiKey: process.env.OPENROUTER_API_KEY
}),
model: 'openrouter/free',
tools: workspaceTools({ root, shell: { allow: ['node', 'pnpm', 'git'] } }),
onToolApproval: async (call) => {
brick.print(`Approve ${call.toolName}(${JSON.stringify(call.input)})? [y/N] `)
return (await brick.input()).trim().toLowerCase() === 'y'
}
})
})
await chatRepl(brick)
| Package | Purpose |
|---|---|
intellibrix |
Core: Brick, Structure, Intelligence, agent loop, tools, events, approvals, memory interfaces, testing utilities |
@intellibrix/ai-sdk |
Provider adapter: provider('vendor:model'), compatibleProvider, aiSdkProvider |
@intellibrix/structures |
Multi-agent composition: supervisor, router, pipelines, handoffs |
@intellibrix/mcp |
MCP client (mount remote tools) and server (expose Bricks) |
@intellibrix/memory-sqlite |
node:sqlite conversation memory and vector store |
@intellibrix/sql |
SQL key-value store and pgvector VectorStore |
@intellibrix/workspace |
Jailed filesystem tools, allowlisted shell, git tools |
@intellibrix/agent-tools |
apply_patch, run_checks, todo, calculator, datetime, json_query, diff, memory, fetch_url, web_search and more for coding agents |
@intellibrix/sandbox |
Code execution in a local Podman/Docker container or a hosted sandbox (E2B, Daytona, Cloudflare) |
@intellibrix/github |
Issue, PR and review tools; HMAC-verified webhook bridge |
@intellibrix/express |
Express brick with /ask and SSE streaming routes |
@intellibrix/terminal |
TerminalKit brick and chatRepl |
@intellibrix/i18n |
i18next-powered internationalization brick |
@intellibrix/cli |
intellibrix init and intellibrix mcp serve |
You can also publish your own Bricks. To have one under the @intellibrix scope, contact dev@intellibrix.dev.
needsApproval gates shell, file writes, git commits and sandboxed code execution by default. Supply onToolApproval to decide, and a call can be approved, denied or edited. Tools behind serveMcp are denied unless you provide onToolApproval.Part may carry trust: 'trusted' | 'untrusted'. Workspace reads, GitHub data and MCP results are tagged untrusted, so approval policies can key off provenance to defend against indirect prompt injection.realpath, so symlinks can't escape.See the threat model for what each defense covers and its limits, and SECURITY.md to report a vulnerability.
node:sqlite with no external services.This is a pnpm monorepo (Node 22+). See CONTRIBUTING.md for how to contribute, and AGENTS.md if you are an AI coding agent.
git clone https://github.com/intellibrix/intellibrix.git # or your fork
cd intellibrix
pnpm install
pnpm -r typecheck
pnpm biome ci .
pnpm -r test
pnpm -r build
pnpm docs:site # docs site + typedoc API reference + llms.txt
Tests run offline using MockProvider; no API keys are needed.
MIT