Single SourceStudios Engage SSS
1,084 commits · 9 milestone tags · solo build

A canvas of wired AI specialists, resolved as a parallel directed acyclic graph at execution time.

Modular9 is a Next.js 16 application that turns a plain-English workflow description into a canvas of AI specialist nodes, each backed by a filesystem-registered plugin: a Zod-validated plugin.json, an optional COVENANT.md design contract, optional SKILL.md files. The canvas is not a linear chain. It resolves as a DAG at execution time: independent branches run in parallel, and multiple parents fan in to one child keyed by edge id, not target node id, so N converging outputs all survive instead of the last write clobbering the rest.

1,084 commits, 2026-02-24 to 2026-08-01
492 tests passed, 2 todo
Vercel + Render + Docker self-host
Solo build
165specialist plugins, 13 sub-packs
46native connectors, compile-time dispatch
910line DAG runner, one shared engine
91stackable custom skills
What it is

One DAG engine, three ways to run it.

Every node's behavior is composed at three layers: a base plugin system prompt, an ordered stack of user-selected custom-skill modifier blocks injected between that prompt and the incoming content, and an optional LogicSpec reasoning contract from @logic-md/core declaring a strategy, typed I/O, and quality gates.

cot react tot plan-execute got

One codebase runs two execution paths in production plus a third for local development, all dispatching through the same DAG engine so the deployed runtime never diverges from what resolves on a laptop.

Vercel web tier

Enqueue and return

The web tier enqueues a BullMQ job on Upstash Redis and returns immediately, avoiding serverless execution limits.

Render worker

No serverless timeout

A Render worker executes the DAG with no serverless timeout and streams events back over Redis to a Vercel SSE endpoint.

Local inline executor

No Redis dependency

Locally, the same DAG runs in-process through an inline executor, no Redis dependency required.

Source: ARCHITECTURE.md
Hard numbers

Every figure below traces to a file, a command, or a recorded test run.

MetricValueEvidence
Total commits (main)1,084git rev-list --count HEAD
First commit2026-02-24, 8f7315dgit log --reverse
Last commit2026-08-01, 29ccdb9git log -1
Commit authors2 emails, 1 persongit log --format=%ae
Annotated milestone tags9, v1.1 to v1.5.0git tag
TypeScript / TSX source402 files, 67,654 linesfind + wc -l
Test files58find *.test.ts(x)
Test cases459 across 127 describe()grep -rEo
Test suite result492 passed, 2 todoSTATUS.md
Specialist plugin directories165find src/plugins
Plugin manifests total204 (165 native + 39 dual-exported)find -name plugin.json
Plugins with COVENANT.md162 of 165comm -23
Plugin sub-packs13packs.ts
Native connectors46connectors/registry.ts
Custom skills91 (60 hand-authored + 31 generated)custom-skills.ts
One-click workflow templates25templates/index.ts
REST API route handlers34find src/app/api
DAG runner size910 linesdag-runner.ts
Connector executor size56 lines, dispatch table onlyconnector-executor.ts
Embedding modelnv-embedqa-e5-v5, 1024-dim, pgvector cosineembeddings.ts
Deploy targetsVercel, Render free-tier worker, Docker self-hostvercel.json, render.yaml
Live URLsinglesource.co.za/m9/README.md

Database row counts are not verifiable from this repository: PostgreSQL lives on Neon, remote, with no local .db or .sqlite file in the tree.

Architecture

One shared DAG engine, three callers, no parallel logic to maintain.

The canvas (src/lib/canvas/store.ts, 285 lines, Zustand) holds three node types, triggers, specialists, and connectors, plus a knowledge-base node. A specialist node's rendering and per-node settings live in src/components/canvas/nodes/specialist-node.tsx (721 lines). Execution is dispatched through src/lib/execution/dag-runner.ts (910 lines), extracted so the BullMQ worker (src/workers/execution.worker.ts, 568 lines) and the local inline executor (src/lib/execution/inline-executor.ts, 203 lines) both call one code path instead of maintaining parallel logic. The 2026-07-23 changelog entry for that extraction records the worker shrinking from 1,263 to 561 lines and the inline executor from 857 to 197.

910dag-runner.ts
56connector-executor.ts, from 5,038
516plugin registry, 165 dirs
294llm-gateway.ts

All model calls route through src/lib/execution/llm-gateway.ts (294 lines). Model identifiers are centralized in src/lib/execution/default-model.ts (114 lines): resolution is selectedModel ?? user.defaultModel ?? DEFAULT_MODEL, with no other file in the tree hardcoding a model id. Errors are classified by HTTP status, never response text, in src/lib/execution/error-normalizer.ts (222 lines), which reads both the NVIDIA path's status field and the Vercel AI SDK's statusCode field.

Connector dispatch (src/lib/execution/connectors/registry.ts) is a typed Record<ConnectorPluginId, ConnectorExecutor> of 46 entries, a missing entry is a compile error. This replaced a single 5,038-line switch statement in connector-executor.ts, now 56 lines, with the 46 executor bodies moved into 16 domain modules: github, workplace, google-workspace, email, social, web, media, cli, platform, google-apis, seo, and others.

The plugin registry (src/lib/plugins/registry.ts, 516 lines) discovers, Zod-validates, and loads each of the 165 directories under src/plugins/. 39 of those plugins additionally carry a .claude-plugin/plugin.json, a dual export making the same specialist installable as a standalone Claude Code plugin. The author fields on those manifests show 13 authored natively as "Modular9", 7 from Composio, and the rest from named individuals or Anthropic, a mixed build-and-adapt sourcing strategy rather than 165 fully original prompts.

Two monorepo packages implement the standalone LOGIC.md tooling that Modular9 also runs internally: packages/cli (9 commands, 16 .logic.md templates) and packages/mcp (7 MCP tools, stdio and HTTP transport). A third package, packages/modular9-mcp, exposes Modular9's own workflows, templates, packs, plugins, and knowledge bases as 10 MCP tools for external agent clients.

Engineering decisions

Nine choices with load-bearing consequences.

DAG semantics

Fan-in keyed by edge id, not target node id

So N parents converging on one child all survive instead of the last writer overwriting the rest. Called out as load-bearing for the Adversarial Verification and Tournament Bracket templates.

LLM gateway

Provider selection is asymmetric by call type

The Composer resolves reliability-first, Anthropic, then OpenAI, then NVIDIA NIM, because one-shot structured-JSON generation is quality-critical and must not stall on a saturated shared endpoint. Utility calls, summaries, prompt improvement, resolve free-first and walk a cross-provider fallback chain instead.

Error handling

Errors are classified by HTTP status, never sniffed from text

Closes a class of bug where an AI SDK error's statusCode field was missed because only status was read. Fixed in commits f6342d7 and 3b50643.

Refactor

Connector dispatch moved from a runtime switch to a compile-time registry

5,038 lines to 56, split into 16 domain modules, verified as a pure move: 65 of 69 declarations byte-identical, the 4 differences intentional.

Failure policy

KB and connector node failures share one policy path

recordNodeFailure: connector failures halt the run by default; the knowledge-base node can opt into continuing so downstream specialists are not silently left to answer ungrounded unless the workflow author explicitly allows it.

Security

Webhook signatures moved to timestamped HMAC with a hard cutoff

Legacy body-only signatures are accepted with a deprecation warning until 2026-11-01T00:00:00Z, then rejected with HTTP 403 before signature comparison, closing a replay window instead of leaving an open-ended deprecation.

Toolchain

TypeScript 7.0.2 was attempted and reverted

tsc itself typechecks clean in about 0.6 seconds, but typescript-eslint@8.65 pins a peer range excluding TypeScript 7 and next build 16.2.4 rejects the TS7 package shape. The blocker is upstream, not in this codebase.

Deployment

Self-host is a first-class deployment path

A full Docker Compose stack, app, worker, postgres with pgvector, redis, caddy, exists for regulated or air-gapped environments, not an afterthought.

Transparency

Row-Level Security is deliberately not yet implemented

Tenant scoping is enforced in the application layer today, with an automated test suite covering it. The gap is stated rather than obscured.

Timeline

477 commits in April, the LOGIC.md milestone month.

82Feb
133Mar
477Apr
284May
76Jun
23Jul
9Aug, partial
2026-02 to 2026-03

Project initialization (8f7315d, "docs: initialize project", 2026-02-24) through early build-out.

2026-04

The heaviest single month and the LOGIC.md milestone sequence: M3 reasoning middleware (v1.1, 2026-04-03), M4 CLI extension (v1.2, 2026-04-03/04), M5 MCP server (v1.3, 2026-04-05/14), M6 Claude Code plugin (v1.4/v1.5.0, 2026-04-05/17).

2026-06

LLM gateway correctness pass, provider stamping, the statusCode fix, cross-provider fallback chains, inline/worker parity fixes, plus an open-source presentation pass: README rewrite, ARCHITECTURE.md, CONTRIBUTING.md, root SECURITY.md.

2026-07-17 to 07-23

Smart Skill Router (91-skill embedding index), connector shell-out hardening (NotebookLM and Claude Code executors moved off /bin/sh -c to argv execFile), a full security and architecture audit (M9_FABLE_REPORT.md) followed by a 9-phase remediation plan, engine extraction into shared dag-runner.ts, and webhook replay protection.

2026-08-01

A ranked-risk cycle, P1 through P5, eight commits (350dd57 to 7fc9d17), pinning the toolchain, taking lint and typecheck from decorative to CI-gated (135 warnings and 246 tsc errors to zero), fixing a path-traversal vulnerability in getDocBySlug, splitting the connector executor, and shipping usage metering end to end.

Boundary

What this page does not cover.

Boundary This page covers only what is verifiable from the repository at commit 29ccdb9 (2026-08-01). It does not cover production database contents, live traffic, or usage numbers, and it does not cover anything on the roadmap-not-yet-in-place list in SECURITY.md: SOC 2, structured audit logging, Postgres row-level security, RBAC and team workspaces, or auth-endpoint rate limiting. It is not a security audit or a performance benchmark. It does not verify that the deploy targets, the live demo URL, or migration 0012_usage_metering.sql are currently applied against a live database; per STATUS.md, that migration was still unapplied as of the last recorded status.

Evidence: compiled from the modular9 repository on 2026-08-03. Every number on this page traces to a file path or command output in the source tree. Last updated: 2026-08-03.

Single Source

Every number on the dossier and whitepaper pages traces to a file path or command output in the source tree.

LinkedIn Facebook (c) 2026 Single Source Studios (Pty) Ltd