Skip to content

Architecture

draw is one database module with clients around it. Every write, from a person or an agent, goes through the same rules in that module.

This is a real board, not a picture. Pan and zoom it here, or open it read-only.

Part Source What it does
Database module module/ Holds the tables and the board rules. It is the single source of truth.
MCP Worker mcp/ Serves the agent tools, checks sign-in, holds temporary file captures and relays live traffic. It writes as the calling user.
Canvas and embeds client/ The board editor, and the read-only viewer shown above. Both stay connected to the module.
Dashboard web/ Lists and manages boards and workspaces. Its server side starts repository imports.
Import runner importer/ Reads one public GitHub commit and returns an architecture graph to the dashboard. It has no database connection.
Coding agent plugin/ Any MCP client. The plugin adds a skill, hooks and the MCP config.
redcrayon CLI helper/ Uploads the files an agent cites, and forwards traffic summaries during a tap.
Your running app Sends traces to the CLI during a tap. Raw traces stay on your machine.

An agent draws a node. These excerpts show the same edit at each step.

The Worker writes as the calling user, not as a shared service account:

mcp/src/app.ts
const db = database(env, () => mint(env, principalSubject(principal)), stats);
mcp/src/tools.ts
t.ctx.db.call('create_node', { boardId, ...input }, t.signal)

The module checks the rules. The canvas calls the same create_node, so a person and an agent get the same answer. This excerpt is shortened:

module/src/index.ts
function assertOnGrid(field: string, value: number): void {
if (value % GRID !== 0) {
// refuses the write: "grid rule: x = 6 is not divisible by 4; ..."
}
}

Open clients then receive the change. The canvas subscribes to the board’s tables, and the viewer on this page subscribes to its published scene:

client/src/subscribe.ts
conn.subscriptionBuilder().onApplied(onApplied).onError(onError).subscribe(all(CORE_TABLES));
client/src/embed.ts
.subscribe([boardMode ? 'SELECT * FROM embedded_board' : 'SELECT * FROM embedded_chart']);

A sign-in provider is optional. Postgres stores long-term activity history, and the self-host stack includes it.