James Madison University, class of 2023. Computer information systems, in the business school.
James Madison University
B.B.A. Computer Information Systems, 2023
“
You have shown a speed and ability to solve problems that I have not seen in my students before.
Dr. Dmytro BabikProfessor of Information Systems, James Madison University
NARAMLAP 1/5
Lap 2Spa-Francorchamps, Belgium
CGIFederal.
My day job since 2022: AI software for Medicare and Medicaid programs.
CGI Federal
Jun 2022 to now
Senior Consultant
I work in the Health and Social Services unit. I built the AI prototypes that led to a contract award from the Centers for Medicare & Medicaid Services. I also built the tracking systems and the dashboards leadership uses to see the team’s work.
He has been integral in the development of tracking systems and dashboards, automating and displaying team function at an executive level.
William HallDirector of Emerging IP, CGI Federal
Lap 3Sakhir, Bahrain
Formwork.
Co-founded in 2024. Commercial contractors hire it for sales, marketing and software. I build the software.
Formwork
Nov 2024 to now
Technical Co-Founder & CTO
Formwork does sales, marketing and software for commercial construction contractors. I built all of its technology, and I decide how it fits together across the three units. It started as Sunrise Systems.
Runs Formwork day to day: clients, projects, tasks and invoices in one place, synced with the books. After each meeting, Claude drafts the follow-up tasks.
Live · runs Formwork
DeltaPortal
Delta Construction’s project system, which replaced Procore: RFIs, bidding, contracts, chat and Autodesk files. Architects and subs reply from a link.
Live · Delta Construction
DeltaEstimatingPortal
Shows Delta’s estimators what they’re bidding and when: each bid gets a slot with a name, dates and hours, beside the client account.
Construction project platform. Running project teams on big projects right now: real-time chat, RFIs, submittals and bids in one place, always showing who owes the next move.
In use on live projects
Fig.A project platform for design-build teams, in use on big projects today, made for the people on site with a phone or an iPad.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AClients
Web appNext.js 15 · React 19UI+
UI · Next.js 15 · React 19
The app people use on site and in the office, built mobile-first for phones and iPads. Types are generated from the Java DTOs, so the front end and back end can’t drift.
Talks to
→ Public API (HTTPS · JWT)
→ Live sockets (live)
Respond by linkone-time token pagesUI+
UI · one-time token pages
Pages that outside architects, subs and reviewers open from an emailed link to answer an RFI or a submittal, or to submit a bid. No account needed.
Talks to
→ Public API (token)
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude Desktop or any MCP client, signed in as a real user through OAuth. It only gets what that person could do in the app.
Talks to
→ MCP endpoint (MCP)
→ OAuth server (OAuth)
BGateway
Public APISpring Boot · WebFluxSERVICE+
SERVICE · Spring Boot · WebFlux
The only door in. It checks the JWT, resolves the user, their company and the client IP once, and forwards each request with trusted identity headers.
Talks to
← Web app (HTTPS · JWT)
← Respond by link (token)
→ Projects (REST)
→ RFIs (REST)
→ AI service (proxy)
Live socketsWebSocketsREALTIME+
REALTIME · WebSockets
Held by the gateway: chat, notifications, presence and which conversation each tab is reading. Drawn in full below.
Talks to
← Web app (live)
← Redis 7 (pub/sub)
MCP endpointJSON-RPCAI+
AI · JSON-RPC
The MCP transport, also in the gateway. Claude’s tool calls arrive here and run as the signed-in user.
Talks to
← Claude (MCP)
→ Tool registry (as the user)
AI serviceNode · FastifyAI+
AI · Node · Fastify
Runs the assistant and the agents’ turns: streams the model, loads the tool list, applies each company’s model policy, evaluates agent hooks once per turn, and transcribes voice notes.
Talks to
← Public API (proxy)
→ Tool registry (list · call)
→ Claude · OpenRouter (stream)
← Agents (turns)
CPlatform
Projectsdashboard · directorySERVICE+
SERVICE · dashboard · directory
The centre of the model. Everything else belongs to a project and its team, and the dashboard is built around what the job needs today.
Talks to
← Public API (REST)
← Procore (import)
RFIsball in courtSERVICE+
SERVICE · ball in court
Requests for information, with drafts. Status rules move the ball: open sits with the assignee’s company, answered or returned goes back to the asker, closed clears it.
Talks to
← Public API (REST)
← Tool registry
→ Notifications (ball moved)
→ PostgreSQL 16 (SQL)
Submittalsrevisions · ball in courtSERVICE+
SERVICE · revisions · ball in court
Submittals go round in revisions, with grant-based access, private drafts and a ball held by named people, until one is approved.
Biddingpackages · levelingSERVICE+
SERVICE · packages · leveling
Bid packages per trade, bids with a schedule of values and alternates, leveling, and the award.
Talks to
→ Financials (award → contract)
Drawingssplit · diff · presenceSERVICE+
SERVICE · split · diff · presence
Splits a plan-set PDF into one sheet per page, renders a pixel diff between revisions, holds markups and pins, and shows who else is on the sheet.
Talks to
→ Object storage (sheets · overlays)
Chatreal timeSERVICE+
SERVICE · real time
Project, group and direct conversations with mentions and attachments. Drawn in full below.
Talks to
→ Redis 7 (publish)
Financialscontracts · SOV · pay appsSERVICE+
SERVICE · contracts · SOV · pay apps
Contracts with schedules of values, change events and change orders, and pay applications on the AIA G702/G703 forms. Contract sums are derived, never stored.
Talks to
← Bidding (award → contract)
Agentscommands · skills · hooksAI+
AI · commands · skills · hooks
Each company’s AI agents: a built-in set of construction commands, its own skills, hooks evaluated on every turn with an audit trail, and delegation to named agents only.
Talks to
→ AI service (turns)
Notificationsin-app · emailSERVICE+
SERVICE · in-app · email
Tells the right people when something moves, like a ball changing hands, in the app and by email.
Talks to
← RFIs (ball moved)
→ Redis 7 (publish)
Tool registry199 MCP toolsAI+
AI · 199 MCP tools
Every action an AI may take, declared on the service method itself with a schema derived from its DTO, one error path, and the caller’s permissions checked on every call.
Talks to
← MCP endpoint (as the user)
← AI service (list · call)
→ RFIs
Documentslibrary · PDFSERVICE+
SERVICE · library · PDF
One library for files and generated documents at company and project level, each with a share list, rendered to PDF on the server.
Talks to
← Workflows (renders)
→ Autodesk APS (folders · files)
OAuth serverOAuth 2.1SERVICE+
SERVICE · OAuth 2.1
Lets MCP clients such as Claude Desktop sign in as a user. Redirect addresses are checked strictly so the consent step can’t be abused.
Talks to
← Claude (OAuth)
Sales & CRMleads · estimatingSERVICE+
SERVICE · leads · estimating
Leads with statuses each company sets, client accounts, contacts, follow-ups, the estimating schedule, and won/lost analysis.
Talks to
← Missive (webhooks)
Workflowstriggers · cronJOB+
JOB · triggers · cron
Workflow definitions wired step to step, checked so each output fits the next input, and run on triggers or a schedule.
Talks to
→ Documents (renders)
Catalogue ingestionfrom past documentsAI+
AI · from past documents
Reads a company’s past project documents and proposes budget and qualification catalogue entries for a person to accept.
DData
PostgreSQL 16Liquibase migrationsSTORE+
STORE · Liquibase migrations
The system of record for every module, with versioned schema migrations.
Talks to
← RFIs (SQL)
Redis 7cache · pub/subSTORE+
STORE · cache · pub/sub
Caching, plus the pub/sub channels that carry chat, notification, presence and viewing events between instances.
Talks to
← Notifications (publish)
← Chat (publish)
→ Live sockets (pub/sub)
Object storageS3-compatibleSTORE+
STORE · S3-compatible
Files: drawing sheets and thumbnails, diff overlays, photos and documents, served through short-lived signed links.
Talks to
← Drawings (sheets · overlays)
EOutside
Procoreone-way importEXTERNAL+
EXTERNAL · one-way import
Projects are imported from Procore over OAuth. Nothing is written back.
Talks to
→ Projects (import)
MissivewebhooksEXTERNAL+
EXTERNAL · webhooks
The shared inbox. Its webhooks bring email activity into sales.
Talks to
→ Sales & CRM (webhooks)
Claude · OpenRoutermodelsEXTERNAL+
EXTERNAL · models
The models behind the assistant and the agents, chosen per company within the platform’s policy.
Talks to
← AI service (stream)
Autodesk APSOAuth · filesEXTERNAL+
EXTERNAL · OAuth · files
Autodesk Platform Services: linked projects, folders and files.
Talks to
← Documents (folders · files)
Connections
Web app → Public API · HTTPS · JWT
Respond by link → Public API · token
Web app → Live sockets · live
Claude → MCP endpoint · MCP
Claude → OAuth server · OAuth
Public API → Projects · REST
Public API → RFIs · REST
Public API → AI service · proxy
MCP endpoint → Tool registry · as the user
AI service → Tool registry · list · call
AI service → Claude · OpenRouter · stream
Agents → AI service · turns
Tool registry → RFIs
RFIs → Notifications · ball moved
Bidding → Financials · award → contract
Notifications ⇢ Redis 7 · publish
Chat ⇢ Redis 7 · publish
Redis 7 ⇢ Live sockets · pub/sub
RFIs → PostgreSQL 16 · SQL
Drawings → Object storage · sheets · overlays
Workflows → Documents · renders
Documents → Autodesk APS · folders · files
Procore ⇢ Projects · import
Missive ⇢ Sales & CRM · webhooks
Inside: real-time chat and presence
Every server can hold someone’s open tab, so nothing is sent tab to tab. Events go through Redis once, each server pushes them to the tabs it holds, and the app keeps track of what each tab is actually looking at.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
ATabs
Open tabsone socket eachUI+
UI · one socket each
Every open tab is its own WebSocket session. It reports which conversation it is showing and whether the person is active or idle.
Talks to
→ Socket handler (WebSocket)
← Fan-out (push)
Drawing vieweravatarsUI+
UI · avatars
Shows who else is on the same sheet right now.
Talks to
→ Presence relay (open · keep-alive)
BGateway
Socket handlerper-session stateREALTIME+
REALTIME · per-session state
Tracks viewing per session, not per user: when a tab closes it re-resolves from the person’s remaining tabs, so a closed tab never leaves a stale “still reading”.
Talks to
← Open tabs (WebSocket)
→ Viewing state (viewing)
Fan-outchannel subscribersREALTIME+
REALTIME · channel subscribers
Subscribes to the chat, notification and system channels and pushes each event to the sessions this server holds.
Talks to
← Chat events
← Notifications
→ Open tabs (push)
Presence relayJWT handshakeREALTIME+
REALTIME · JWT handshake
Relays “I’m on this sheet” to the platform. The user comes from the authenticated handshake, never the message, and every keep-alive re-proves access.
Talks to
← Drawing viewer (open · keep-alive)
→ Drawing presence (relay)
CChannels
Chat eventsRedis pub/subQUEUE+
QUEUE · Redis pub/sub
Chat events, published once for every server to hear.
Talks to
← Chat service (publish once)
→ Fan-out
NotificationsRedis pub/subQUEUE+
QUEUE · Redis pub/sub
Notification events on their way to open tabs.
Talks to
→ Fan-out
← Chat notifications (publish)
← Ball in court (ball moved)
Viewing stateRedis pub/subQUEUE+
QUEUE · Redis pub/sub
Which conversation each person is reading, shared between servers.
Talks to
← Socket handler (viewing)
→ Viewing registry (subscribe)
PresenceRedis pub/subQUEUE+
QUEUE · Redis pub/sub
Who is on which sheet, and last-seen updates.
Talks to
← Drawing presence (roster)
DPlatform
Viewing registryin memorySERVICE+
SERVICE · in memory
Per-server and deliberately not persisted: after a restart it refills from the next broadcasts.
Talks to
← Viewing state (subscribe)
← Chat notifications (reading?)
Chat servicemessages · mentionsSERVICE+
SERVICE · messages · mentions
Stores the message, works out the recipients and publishes the event once.
Talks to
→ Chat events (publish once)
→ Chat notifications
Chat notificationsskips readersSERVICE+
SERVICE · skips readers
Notifies everyone except the sender and anyone already reading the conversation, respecting each person’s settings; mentions also go by email.
Talks to
← Chat service
→ Viewing registry (reading?)
→ Notifications (publish)
Drawing presencepermission-checkedSERVICE+
SERVICE · permission-checked
Owns the access check and the roster of who is on each sheet.
Talks to
← Presence relay (relay)
→ Presence (roster)
Ball in courtRFIs · submittalsSERVICE+
SERVICE · RFIs · submittals
Status rules decide who holds the ball. Only an official answer moves it; a change of holder notifies the new one.
Talks to
→ Notifications (ball moved)
Connections
Open tabs → Socket handler · WebSocket
Socket handler ⇢ Viewing state · viewing
Viewing state ⇢ Viewing registry · subscribe
Chat service ⇢ Chat events · publish once
Chat events ⇢ Fan-out
Notifications ⇢ Fan-out
Fan-out ⇢ Open tabs · push
Chat service → Chat notifications
Chat notifications → Viewing registry · reading?
Chat notifications ⇢ Notifications · publish
Ball in court ⇢ Notifications · ball moved
Drawing viewer → Presence relay · open · keep-alive
Presence relay → Drawing presence · relay
Drawing presence ⇢ Presence · roster
Two flows
An RFI changes hands
Step through it and the parts it runs through light up above.
By count
actions Claude can take in it
199
Notes
N.1Nobody updates ball-in-court by hand. It follows the RFI: while it’s open it sits with the company that has to answer, once it’s answered it goes back to whoever asked, and closing it clears it.
N.2Only an official answer moves the ball. A quick clarifying reply joins the thread and leaves the ball where it is.
N.3The assistant sees exactly what you can see and nothing more. It works through the same actions you have.
N.4Awarding a bid carries its schedule of values onto a payable contract, in a separate step that can never undo the award if it fails.
Fig.Swipe across to see all of it. MATTER’s core data model.
Sales CRM. Turns a cold lead list into deals: it fills in missing contacts, runs email and LinkedIn sequences, and sorts replies so only real leads reach a person.
Live · Formwork and its clients
Fig.Cold outreach for Formwork and its clients, from a raw lead list to a deal in the CRM.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APeople
Campaign managersNext.js 15 · React 19UI+
UI · Next.js 15 · React 19
Formwork’s team: lead lists, campaigns, sequences and the CRM, across every client, each client’s data kept apart.
Talks to
→ Lead lists (CSV)
SDR deskcalls · follow-upsUI+
UI · calls · follow-ups
Where reps work the follow-up queue, approve drafted replies and log calls.
Talks to
→ Reply approvals (approve)
Client portalper clientUI+
UI · per client
Each client sees their own campaigns, leads, pipeline and campaign health.
Talks to
→ CRM (their pipeline)
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude, connected with a personal token, working the same data through MCP.
Talks to
→ MCP server (MCP · token)
BApp
Lead listsCSV · domain dedupeSERVICE+
SERVICE · CSV · domain dedupe
Uploaded lists, cleaned and matched to companies by web domain. Uploading never marks anyone as contacted.
Talks to
← Campaign managers (CSV)
→ Enrichment (gaps)
→ Sequences (filtered)
Enrichmentwaterfall per fieldSERVICE+
SERVICE · waterfall per field
Fills each missing field (email, phone, title, location) by trying providers in priority order, with rate limits and caching.
Talks to
← Lead lists (gaps)
← Enrichment drain (queued)
→ Data providers (in turn)
Sequencesemail · LinkedInSERVICE+
SERVICE · email · LinkedIn
A sequence filters a live list into the leads it will contact, then hands them to the sender for its channel.
Talks to
← Lead lists (filtered)
→ Smartlead (push)
→ Valley
Webhook intakeevents · repliesSERVICE+
SERVICE · events · replies
Receives the senders’ events. Only these can mark a contact as reached, which keeps the numbers honest.
Talks to
← Smartlead (webhooks)
← Valley (webhooks)
← Nylas (webhooks)
→ Reply triage (replies)
MCP server100 tools by roleAI+
AI · 100 tools by role
Tools grouped by area and composed per role: an admin sees all of them, other roles only their own. Tokens are stored hashed.
Talks to
← Claude (MCP · token)
CRMcompanies · contactsSERVICE+
SERVICE · companies · contacts
Warm contacts and their companies, with status, temperature, notes and a relationship score from 0 to 100.
Talks to
← Reply approvals (promote)
→ Opportunities (deal)
← Client portal (their pipeline)
→ PostgreSQL
Opportunitiesproposal → won / lostSERVICE+
SERVICE · proposal → won / lost
Deals, from proposal to won or lost.
Talks to
← CRM (deal)
Reply approvalsdrafted answersSERVICE+
SERVICE · drafted answers
Real leads queue here with a reply drafted. A person approves it before it goes.
Talks to
← Reply triage (real leads)
← Reply pre-drafts (drafts)
← SDR desk (approve)
→ Smartlead (reply)
→ CRM (promote)
Reply triagerules → ClaudeAI+
AI · rules → Claude
Cheap rules catch bounces, unsubscribes and warmup mail first. Claude sorts the rest into six kinds, and says unsure rather than guess.
Talks to
← Webhook intake (replies)
→ Claude · OpenAI (classify)
→ Slack (alert)
→ Reply approvals (real leads)
Research & prepClaude · FirecrawlAI+
AI · Claude · Firecrawl
Researches a contact or their company and preps a sales meeting, and answers questions about the CRM.
Talks to
→ Vector store
CJobs
Enrichment draincronJOB+
JOB · cron
Works through queued enrichment in the background.
Talks to
→ Enrichment (queued)
Reply pre-draftscronJOB+
JOB · cron
Drafts answers ahead of time for confident real leads, so the queue is ready when someone opens it.
Talks to
→ Reply approvals (drafts)
Sender synccronJOB+
JOB · cron
Pulls campaign stats from Smartlead and sends replies scheduled for later.
Talks to
→ Smartlead
DData
PostgreSQLPrismaSTORE+
STORE · Prisma
Every client’s leads, lists, campaigns and CRM, scoped by client.
Talks to
← CRM
Vector storePostgres · embeddingsSTORE+
STORE · Postgres · embeddings
A separate database of contact embeddings for semantic search in the assistant.
Talks to
← Research & prep
EOutside
Data providersProxycurl · Findymail …EXTERNAL+
EXTERNAL · Proxycurl · Findymail …
Proxycurl, Findymail, Apollo and Hunter, among others, tried in turn for each missing field.
Talks to
← Enrichment (in turn)
SmartleademailEXTERNAL+
EXTERNAL · email
Sends the email sequences, and sends approved replies on the same thread.
Talks to
← Sequences (push)
→ Webhook intake (webhooks)
← Reply approvals (reply)
← Sender sync
ValleyLinkedInEXTERNAL+
EXTERNAL · LinkedIn
Runs the LinkedIn sequences.
Talks to
← Sequences
→ Webhook intake (webhooks)
NylasmailboxesEXTERNAL+
EXTERNAL · mailboxes
Connected mailboxes, for replies that arrive outside a sequence.
Talks to
→ Webhook intake (webhooks)
Claude · OpenAImodelsEXTERNAL+
EXTERNAL · models
Claude for triage, drafting and research; OpenAI for embeddings.
Talks to
← Reply triage (classify)
Slacktriage alertsEXTERNAL+
EXTERNAL · triage alerts
Triage posts real leads to the team’s channels.
Talks to
← Reply triage (alert)
Connections
Campaign managers → Lead lists · CSV
Lead lists → Enrichment · gaps
Enrichment drain ⇢ Enrichment · queued
Enrichment → Data providers · in turn
Lead lists → Sequences · filtered
Sequences → Smartlead · push
Sequences → Valley
Smartlead ⇢ Webhook intake · webhooks
Valley ⇢ Webhook intake · webhooks
Nylas ⇢ Webhook intake · webhooks
Webhook intake → Reply triage · replies
Reply triage → Claude · OpenAI · classify
Reply triage ⇢ Slack · alert
Reply triage → Reply approvals · real leads
Reply pre-drafts ⇢ Reply approvals · drafts
SDR desk → Reply approvals · approve
Reply approvals → Smartlead · reply
Reply approvals → CRM · promote
CRM → Opportunities · deal
Client portal → CRM · their pipeline
Claude → MCP server · MCP · token
Sender sync ⇢ Smartlead
Research & prep → Vector store
CRM → PostgreSQL
Inside: reply triage
Most replies to cold email are noise. Triage stores every reply first, lets cheap rules catch the obvious, has Claude sort the rest, and only ever lets a person send, with the CRM updated before the one step that can’t be undone.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AArrive
Smartleadreply webhooksEXTERNAL+
EXTERNAL · reply webhooks
Replies to the email sequences, including ones from a colleague of the person emailed.
Talks to
→ Webhook event
Nylasmailbox webhooksEXTERNAL+
EXTERNAL · mailbox webhooks
Replies that land in connected mailboxes.
Talks to
→ Webhook event
Webhook eventstored firstSTORE+
STORE · stored first
Every reply is saved before it is classified, so nothing is lost and anything can be reclassified later.
Talks to
← Smartlead
← Nylas
→ Field extraction
BSort
Field extractionevery known aliasSERVICE+
SERVICE · every known alias
Smartlead has used several names for each field over time; extraction tries all of them.
Talks to
← Webhook event
→ Rules
Ruleswarmup · bounces · vendorsSERVICE+
SERVICE · warmup · bounces · vendors
Catch warmup mail, auto-replies, unsubscribes and bounces without a model call. Vendor domains an admin pins are a hard rule.
Talks to
← Field extraction
→ Classifier (undecided)
ClassifierClaude Haiku · six kindsAI+
AI · Claude Haiku · six kinds
Sorts what the rules can’t decide into a real lead, unsure, vendor mail, automated, spam or warmup noise, with a confidence and a one-line reason. A bid invitation from a platform counts as real money.
Talks to
← Rules (undecided)
→ Confidence floor
Confidence floorlow → unsureSERVICE+
SERVICE · low → unsure
A low-confidence answer becomes unsure, so a person sees it.
Talks to
← Classifier
→ Hot channel (lead · unsure)
→ Vendor channel (vendor)
→ Firehose
→ Review queue (real leads)
Kill switcheverything to peopleSERVICE+
SERVICE · everything to people
One setting sends every reply to the hot channel for a person to read.
Talks to
→ Hot channel (override)
CRoute
Hot channelreal leads · unsureEXTERNAL+
EXTERNAL · real leads · unsure
Slack, for replies a person should see now.
Talks to
← Confidence floor (lead · unsure)
← Kill switch (override)
Vendor channelSlackEXTERNAL+
EXTERNAL · Slack
Vendor mail, kept apart.
Talks to
← Confidence floor (vendor)
Firehoseevery replyEXTERNAL+
EXTERNAL · every reply
Every classification, whatever the category, as an audit trail.
Talks to
← Confidence floor
Review queueone per replySERVICE+
SERVICE · one per reply
Real leads queue for a drafted answer; creating the entry twice for the same reply is impossible.
Talks to
← Confidence floor (real leads)
→ Draft + suggestions
DAnswer
Pre-draftscronJOB+
JOB · cron
Drafts ahead of time for confident real leads; everything else drafts when someone opens it.
Talks to
→ Draft + suggestions
Draft + suggestionsreply · tags · temperatureAI+
AI · reply · tags · temperature
One call writes the reply and suggests tags (only from the client’s existing ones, never invented), a CRM status and a temperature from cold to burning.
Talks to
← Review queue
← Pre-drafts
→ Approve
ApproveCRM first, send lastUI+
UI · CRM first, send last
The reversible work (status, temperature, tags) is applied first; the send, which can’t be undone, comes last.
Talks to
← Draft + suggestions
→ Thread resolver
Thread resolvercolleague repliesSERVICE+
SERVICE · colleague replies
Finds the right thread even when the person replying was never in the campaign, using the id the original webhook carried.
Talks to
← Approve
→ Send or schedule
Send or scheduleSmartlead inboxSERVICE+
SERVICE · Smartlead inbox
Sends now or at a set time on the same thread, logs it, and marks the contact as replied.
Talks to
← Thread resolver
Connections
Smartlead ⇢ Webhook event
Nylas ⇢ Webhook event
Webhook event → Field extraction
Field extraction → Rules
Rules → Classifier · undecided
Classifier → Confidence floor
Confidence floor → Hot channel · lead · unsure
Confidence floor → Vendor channel · vendor
Confidence floor ⇢ Firehose
Kill switch → Hot channel · override
Confidence floor → Review queue · real leads
Review queue → Draft + suggestions
Pre-drafts ⇢ Draft + suggestions
Draft + suggestions → Approve
Approve → Thread resolver
Thread resolver → Send or schedule
Two flows
A lead list becomes a pipeline
Step through it and the parts it runs through light up above.
By count
channels: email and LinkedIn
2
kinds of reply, sorted
6
actions Claude can take in it
100
Notes
N.1Nobody counts as contacted until the email has actually gone out, so the numbers a client sees are real.
N.2An invitation to bid sent by a bid platform is automated, but it’s still real money. The sorter is told that, and when it isn’t sure it says so and a person looks.
N.3Clients get their own portal with their campaigns, leads and pipeline.
Sound-design instrument. A synth with six ways to make sound that plays in a browser tab or inside your DAW. Hunt breeds new patches from the ones you keep, so you find sounds by ear.
Invite-only for now · demos public
Fig.A sound-design instrument: six engines, in a browser tab or inside your DAW.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APlay
Browser tabNext.js 16 · ReactUI+
UI · Next.js 16 · React
The instrument in a browser. The public build keeps everything in the browser, with no accounts and nothing stored on a server.
Talks to
→ React UI
→ Server routes (gate)
MIDI · keyboardWebMIDI · computer keysUI+
UI · WebMIDI · computer keys
Play from a controller or the computer keyboard, in a chosen key and scale. Every browser API is optional; missing ones fail quietly.
Talks to
→ React UI (notes)
Your DAWVST3 · standaloneEXTERNAL+
EXTERNAL · VST3 · standalone
Ableton or any VST3 host, on Apple Silicon, loading the plugin build.
Talks to
← Bounce · record (drag WAV)
← JUCE plugin (VST3)
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude can list engines and presets, make and change patches, and write chord progressions.
Talks to
→ MCP endpoint (MCP)
BInterface
Bounce · recordWAV · drag outSERVICE+
SERVICE · WAV · drag out
Renders a sound offline to WAV, or records it, then lets you drag the file onto a DAW track (in Chrome) or download it.
Talks to
← React UI
→ Your DAW (drag WAV)
React UIone UI for bothUI+
UI · one UI for both
The same interface in the browser and inside the plugin: engines, macros, the XY pad, presets and Hunt.
Talks to
← Browser tab
← MIDI · keyboard (notes)
← Hunt (six takes)
→ AudioWorklet (params · notes)
→ Bounce · record
→ JUCE plugin (bundled)
Huntmutate · breed · tasteSERVICE+
SERVICE · mutate · breed · taste
Six variations at a time, judged by ear. Keeping some nudges the next generation toward them, within limits, and the nudge fades unless you keep choosing it.
Talks to
← Presets (seeds)
→ Names & glyphs (name · mark)
→ React UI (six takes)
Names & glyphsfrom parametersSERVICE+
SERVICE · from parameters
A patch’s name and mark are computed from its parameters, so the same sound gets the same name everywhere, with nothing stored.
Talks to
← Hunt (name · mark)
MCP endpoint13 tools · JSON-RPCAI+
AI · 13 tools · JSON-RPC
A plain HTTP POST endpoint. The protocol layer knows nothing about music; every tool body is a tested function.
Talks to
← Claude (MCP)
→ Six engines (patches)
CSound
Presets84 across the banksSTORE+
STORE · 84 across the banks
Starting points for every engine, plus a percussion bank.
Talks to
→ Hunt (seeds)
DSP coreTypeScript · referenceSERVICE+
SERVICE · TypeScript · reference
The synthesis itself, in plain TypeScript: no browser APIs and no allocation in the render loops.
Talks to
← AudioWorklet (renders)
→ Six engines
→ Parity check (goldens)
Six enginesanalog · FM · physical …SERVICE+
SERVICE · analog · FM · physical …
Analog, FM, physical modelling, granular, wavetable and sampler voices, under one voice manager.
Talks to
← DSP core
→ FX & character
← MCP endpoint (patches)
FX & charactertwo chainsSERVICE+
SERVICE · two chains
An effects chain and a character chain, available on every engine.
Talks to
← Six engines
DHosts
AudioWorkletseparate realmREALTIME+
REALTIME · separate realm
Runs the DSP on the browser’s audio thread. It is bundled on its own and only hears what the page posts to it.
Talks to
← React UI (params · notes)
→ DSP core (renders)
C++ enginehand portSERVICE+
SERVICE · hand port
The same DSP in C++, kept in step with the TypeScript.
Talks to
← JUCE plugin (process)
→ Parity check (compared)
JUCE pluginWebView UI insideSERVICE+
SERVICE · WebView UI inside
Wraps the C++ engine as a VST3 and serves the React UI from inside the binary. Parameters are only ever appended, so saved automation never moves.
Talks to
← React UI (bundled)
→ C++ engine (process)
→ Your DAW (VST3)
EBuild
Server routespasscode gate · sign-upsSERVICE+
SERVICE · passcode gate · sign-ups
The private build sits behind a passcode; the public one has none. One setting decides, not a fork.
Talks to
← Browser tab (gate)
→ PostgreSQL (SQL)
PostgreSQLsign-upsSTORE+
STORE · sign-ups
Email sign-ups from the landing page.
Talks to
← Server routes (SQL)
Parity check197 golden rendersJOB+
JOB · 197 golden renders
Renders fresh goldens from the TypeScript and measures the C++ against them on every build.
Talks to
← DSP core (goldens)
← C++ engine (compared)
Connections
Browser tab → React UI
MIDI · keyboard → React UI · notes
Presets → Hunt · seeds
Hunt → Names & glyphs · name · mark
Hunt → React UI · six takes
React UI → AudioWorklet · params · notes
AudioWorklet → DSP core · renders
DSP core → Six engines
Six engines → FX & character
React UI → Bounce · record
Bounce · record → Your DAW · drag WAV
React UI → JUCE plugin · bundled
JUCE plugin → C++ engine · process
JUCE plugin → Your DAW · VST3
DSP core → Parity check · goldens
C++ engine → Parity check · compared
Claude → MCP endpoint · MCP
MCP endpoint → Six engines · patches
Browser tab → Server routes · gate
Server routes → PostgreSQL · SQL
Inside: the engines and Hunt
Each engine is a description plus a voice; the interface, the plugin parameters and Hunt are all built from the description. Hunt breeds sounds from a single seed, so a whole session can be replayed from one number.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
ADescribe
Engine registryone line per engineSERVICE+
SERVICE · one line per engine
Adding an engine is one line here plus its module. No app code changes.
Talks to
→ Descriptors
Descriptorsparams · ranges · groupsSTORE+
STORE · params · ranges · groups
Every parameter with its range, default, curve and group. Linear and exponential parameters are normalised differently so a step means the same thing to the ear.
Talks to
← Engine registry
→ Built interface (builds)
→ Voice manager (params)
Built interfacefrom descriptorsUI+
UI · from descriptors
The controls draw themselves from the descriptor.
Talks to
← Descriptors (builds)
BVoices
Voice managerpolyphonySERVICE+
SERVICE · polyphony
Owns polyphony so engines never think about it. Every voice is allocated up front, so playing a note allocates nothing.
Talks to
← Descriptors (params)
→ Analog (voices)
← Smoothing
→ Granular
Analogantialiased saw · ladderSERVICE+
SERVICE · antialiased saw · ladder
Subtractive voice with an antialiased sawtooth, so the top end sounds clean rather than harsh, into a ladder filter.
Talks to
← Voice manager (voices)
FMvelocity → brightnessSERVICE+
SERVICE · velocity → brightness
Frequency modulation where playing harder opens the timbre, like a real tine, and nothing you do can push a preset past the brightness it was voiced at.
Physicalmembrane · wood · metal · glassSERVICE+
SERVICE · membrane · wood · metal · glass
A bank of resonant modes shaped like a drum head, a wooden bar, a bell or glass. Bowed excitation is bounded so it can never build up forever.
Talks to
→ Effects chain (mix)
Granularshared buffersSERVICE+
SERVICE · shared buffers
Grain clouds panned across the field, sharing one buffer across voices instead of megabytes per note, with tapered windows so grains never click.
Talks to
← Voice manager
Wavetablesine → metallicSERVICE+
SERVICE · sine → metallic
Tables that run from pure to complex: sine, triangle, soft organic, square, saw, two vocal formants and metallic.
Sampleryour samplesSERVICE+
SERVICE · your samples
Every voice plays one shared sample; swapping a 30 MB recording is a single reference swap between audio blocks.
CSignal
Smoothingevery parameterSERVICE+
SERVICE · every parameter
Every parameter passes through a smoother. Unsmoothed changes cause zipper noise, the most common reason a digital synth sounds cheap.
Talks to
→ Voice manager
Effects chainchorus · delay · reverbSERVICE+
SERVICE · chorus · delay · reverb
Where the signal becomes stereo. Each unit is skipped when its mix is silent.
Talks to
← Physical (mix)
→ Character chain
Character chainbounded ±1.2SERVICE+
SERVICE · bounded ±1.2
Effects that make a listener ask what that was, allocation-free and guarded against denormals, and bounded so nothing can push the output past ±1.2.
Talks to
← Effects chain
DHunt
Seedone numberSERVICE+
SERVICE · one number
A deterministic generator: the same seed gives the same hunt on every machine, so a session can be shared as a single number.
Talks to
→ Mutate
Mutatesix distinct takesSERVICE+
SERVICE · six distinct takes
Walks the current patch to six variations, retrying until they sound distinct from each other.
Talks to
← Seed
← Breed
→ Lineage (what changed)
Breedtwo kept parentsSERVICE+
SERVICE · two kept parents
Crosses two patches you kept, with a little jitter.
Talks to
→ Mutate
← Taste (bias)
Tastebounded · blended · fadingSERVICE+
SERVICE · bounded · blended · fading
Turns what you keep into a direction for the next generation: capped so it can’t pin a parameter, blended so one odd keep doesn’t define you, and fading unless you keep choosing it.
Talks to
→ Breed (bias)
Lineage“brighter”, “looser”SERVICE+
SERVICE · “brighter”, “looser”
Names the one or two things that changed in a player’s words, and keeps the trail of moves that found a sound.
Talks to
← Mutate (what changed)
→ Name & glyph
Name & glyphfrom parametersSERVICE+
SERVICE · from parameters
Computed from the parameter values, so the same sound always has the same name and mark.
Talks to
← Lineage
Connections
Engine registry → Descriptors
Descriptors → Built interface · builds
Descriptors → Voice manager · params
Voice manager → Analog · voices
Smoothing → Voice manager
Voice manager → Granular
Physical → Effects chain · mix
Effects chain → Character chain
Seed → Mutate
Breed → Mutate
Taste → Breed · bias
Mutate → Lineage · what changed
Lineage → Name & glyph
Two flows
Finding a sound
Step through it and the parts it runs through light up above.
By count
engines
6
presets
84
actions Claude can take in it
13
Notes
N.1A patch’s name and glyph come from how it sounds. The same sound is called the same thing on every machine, and a heavy dark patch can’t come out called Bright Tide.
N.2Hunt shows no knobs. You choose by ear, and each patch keeps the moves that found it, written the way a player would say them.
N.3The plugin and the browser make the same sound, so a patch you find in a tab sounds identical in your DAW.
AI testing platform. Point it at a GitHub repo and it tests the app for you: riskiest journeys first, in a real browser, with what broke explained in plain English.
Live · in development
Fig.An AI tester for small teams that ship fast: connect a repo and it tests the app the way a person would.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AClients
DashboardNext.js · live mapUI+
UI · Next.js · live map
Projects, the system map, plans, runs with replays and failure analysis, and a chat panel.
Talks to
→ API routes (HTTPS)
← Live stream (live)
GitHubOAuth · App · webhooksEXTERNAL+
EXTERNAL · OAuth · App · webhooks
Sign-in, repo access through an installed App, webhooks on changes, and checks and comments back on pull requests.
Talks to
→ API routes (webhooks)
← Reporter (PR check)
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Trigger runs, read the system map, plans and results, and search failures from Claude.
Talks to
→ MCP server (MCP)
BAPI
API routesNextAuth · RESTSERVICE+
SERVICE · NextAuth · REST
Workspaces, projects, plans and runs, plus the webhook receivers for GitHub, Linear, Slack and billing.
Talks to
← Dashboard (HTTPS)
← GitHub (webhooks)
→ indexing (enqueue)
Live streamSSE · pub/subREALTIME+
REALTIME · SSE · pub/sub
Streams indexing progress, run events and browser screenshots to the dashboard as they happen.
Talks to
← Executor (screenshots)
→ Dashboard (live)
Orchestratorbudgets · contextSERVICE+
SERVICE · budgets · context
Coordinates the agents through a run: token budgets per agent, and context picked by similarity rather than sent whole.
Talks to
→ execution (run)
← scheduler (schedule)
← MCP server (trigger)
MCP server7 toolsAI+
AI · 7 tools
Run, map, plan, results, health, failure search and a code audit, over MCP.
Talks to
← Claude (MCP)
→ Orchestrator (trigger)
CQueues
indexingBullMQQUEUE+
QUEUE · BullMQ
Jobs to clone and index a repo.
Talks to
← API routes (enqueue)
→ Analyst (worker)
executionBullMQQUEUE+
QUEUE · BullMQ
Jobs to run test cases in a browser.
Talks to
← Orchestrator (run)
→ Executor (worker)
reportingBullMQQUEUE+
QUEUE · BullMQ
Jobs to analyse results and send reports.
Talks to
← Executor (results)
→ Reporter (worker)
schedulerBullMQQUEUE+
QUEUE · BullMQ
Recurring runs on a schedule.
Talks to
→ Orchestrator (schedule)
DAgents
Analystsystem mapAI+
AI · system map
Turns a repo into a system map: framework, routes, components and their links.
Talks to
← indexing (worker)
→ Indexer
→ Planner (system map)
Plannerjourneys · casesAI+
AI · journeys · cases
Rebuilds user journeys from the map, finds coverage gaps and writes test cases. Plans are cached.
Talks to
← Analyst (system map)
→ Prioritiser
→ Claude · GPT (plan)
Executorruns · evidenceAI+
AI · runs · evidence
Drives a real browser step by step, classifies each failure, and captures screenshots, video and DOM snapshots.
Talks to
← execution (worker)
→ Playwright · Stagehand (CDP)
→ Self-healer
→ Object storage (evidence)
→ Live stream (screenshots)
→ reporting (results)
Reporterplain EnglishAI+
AI · plain English
Explains failures, spots patterns across runs, and files them where the team works.
Talks to
← reporting (worker)
→ GitHub (PR check)
→ Linear · Slack
Indexertree-sitter · regex fallbackSERVICE+
SERVICE · tree-sitter · regex fallback
Parses source with tree-sitter, falls back to patterns when it can’t, detects the framework, and indexes incrementally.
Talks to
← Analyst
→ PostgreSQL (map · embeddings)
Prioritiser40 · 35 · 25SERVICE+
SERVICE · 40 · 35 · 25
Scores each case on criticality (40%), risk (35%) and coverage gap (25%), and boosts journeys like sign-in and checkout.
Talks to
← Planner
Self-healerselector memorySERVICE+
SERVICE · selector memory
Finds a moved element by stored fix, text, label or role before asking a model, and saves what worked.
Talks to
← Executor
→ PostgreSQL (saved fixes)
EData
PostgreSQLpgvectorSTORE+
STORE · pgvector
Projects, maps, plans, runs and healed selectors, with embeddings for retrieval.
Talks to
← Indexer (map · embeddings)
← Self-healer (saved fixes)
Redisqueues · pub/subSTORE+
STORE · queues · pub/sub
Backs the job queues, rate limits and live events.
Object storageS3 / R2STORE+
STORE · S3 / R2
Screenshots, videos and DOM snapshots from every run.
Talks to
← Executor (evidence)
FOutside
Claude · GPTrouted by taskEXTERNAL+
EXTERNAL · routed by task
Different models for mapping, planning, running and reporting, chosen per task.
Talks to
← Planner (plan)
Playwright · Stagehandremote CDPEXTERNAL+
EXTERNAL · remote CDP
A real headless browser over CDP, or a cloud browser when configured.
Talks to
← Executor (CDP)
Linear · Slackissues · alertsEXTERNAL+
EXTERNAL · issues · alerts
Where failures become issues and alerts.
Talks to
← Reporter
Connections
Dashboard → API routes · HTTPS
GitHub ⇢ API routes · webhooks
API routes ⇢ indexing · enqueue
indexing ⇢ Analyst · worker
Analyst → Indexer
Indexer → PostgreSQL · map · embeddings
Analyst → Planner · system map
Planner → Prioritiser
Planner → Claude · GPT · plan
Orchestrator ⇢ execution · run
scheduler ⇢ Orchestrator · schedule
execution ⇢ Executor · worker
Executor → Playwright · Stagehand · CDP
Executor → Self-healer
Self-healer → PostgreSQL · saved fixes
Executor → Object storage · evidence
Executor ⇢ Live stream · screenshots
Live stream ⇢ Dashboard · live
Executor ⇢ reporting · results
reporting ⇢ Reporter · worker
Reporter → GitHub · PR check
Reporter → Linear · Slack
Claude → MCP server · MCP
MCP server → Orchestrator · trigger
Inside: the executor and self-healing
Real apps change under their tests. The executor checks it’s allowed to run, orders tests by what they depend on, and when a button has moved it climbs a ladder of cheap fixes before it ever asks a model, then remembers the answer.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
ABefore
Environment checknever productionSERVICE+
SERVICE · never production
Refuses production environments outright, checks the target is reachable, and decrypts the test credentials.
Talks to
→ Dependency order
Dependency orderparallel groupsSERVICE+
SERVICE · parallel groups
Sorts tests by their prerequisites into groups that run in parallel, one group after another, breaking any cycles first.
Talks to
← Environment check
→ Auth reuse
→ API tests (contracts)
Auth reuseskip repeat loginsSERVICE+
SERVICE · skip repeat logins
Once signed in, later tests skip their opening login steps. Tests of the login itself always start fresh.
Talks to
← Dependency order
→ Step executor
API testsplain HTTPSERVICE+
SERVICE · plain HTTP
Contract tests run without a browser or a model loop, falling back to the browser when they need the UI.
Talks to
← Dependency order (contracts)
BRun
Step executorone step at a timeAI+
AI · one step at a time
Acts on the page step by step and classifies any failure: missing element, not clickable, timeout, wrong assertion, wrong page.
Talks to
← Auth reuse
← Provider guard (abort)
→ Browser (act)
→ Stored fix (broken selector)
→ Flaky registry (retries)
→ Baselines (on pass)
→ Evidence
BrowserPlaywright · StagehandEXTERNAL+
EXTERNAL · Playwright · Stagehand
A real browser over CDP, with Stagehand’s element and prompt caching when it is used.
Talks to
← Step executor (act)
Provider guardstop, don’t pile upSERVICE+
SERVICE · stop, don’t pile up
If the AI provider fails on billing, auth or quota, the run stops rather than recording a false failure for every remaining test.
Talks to
→ Step executor (abort)
CHeal
Stored fixapproved firstSERVICE+
SERVICE · approved first
A fix that worked before for this selector, approved ones first, then others above 0.85 confidence.
Talks to
← Step executor (broken selector)
→ Visible text (miss)
Visible textheuristicSERVICE+
SERVICE · heuristic
Finds the element by the words on it.
Talks to
← Stored fix (miss)
→ Label (miss)
Labelaria-labelSERVICE+
SERVICE · aria-label
Finds it by its accessible label.
Talks to
← Visible text (miss)
→ Role (miss)
Rolerole-basedSERVICE+
SERVICE · role-based
Finds it by what it is: a button, a link, a field.
Talks to
← Label (miss)
→ Model (miss)
Modelselector sub-agentAI+
AI · selector sub-agent
Last resort: a model reads the page’s interactive elements and the selectors that failed, and proposes a new one.
Talks to
← Role (miss)
→ Selector memory (saved)
DAfter
Selector memorysaved fixesSTORE+
STORE · saved fixes
Every heal is stored with its strategy and confidence, so the next run starts from it.
Talks to
← Model (saved)
Flaky registryquarantineSERVICE+
SERVICE · quarantine
A test that fails then passes with no code change is flaky, not broken; after five such flips with under half its recent runs passing, it is quarantined.
Talks to
← Step executor (retries)
Baselinesscreens · API shapesSTORE+
STORE · screens · API shapes
After a passing run, screenshots and API response shapes are kept to compare the next run against.
Talks to
← Step executor (on pass)
Evidencescreens · video · DOMSTORE+
STORE · screens · video · DOM
Everything a person needs to see what happened, kept per step.
Talks to
← Step executor
Connections
Environment check → Dependency order
Dependency order → Auth reuse
Dependency order → API tests · contracts
Auth reuse → Step executor
Provider guard → Step executor · abort
Step executor → Browser · act
Step executor → Stored fix · broken selector
Stored fix → Visible text · miss
Visible text → Label · miss
Label → Role · miss
Role → Model · miss
Model → Selector memory · saved
Step executor → Flaky registry · retries
Step executor → Baselines · on pass
Step executor → Evidence
Two flows
Testing your app
Step through it and the parts it runs through light up above.
By count
agents: analyst, planner, executor, reporter
4
actions Claude can take in it
7
Notes
N.1When a button moves, Orbit tries the cheap ways to find it first: its text, its label, its role. It only asks a model as a last resort, and it remembers the answer.
N.2It can break things on purpose, like a dropped request or a slow server, to see how the app copes.
Agent operations platform. A team of AI agents that works on a schedule. They read a company’s systems, draft the work and bring every decision to a person to approve.
Live · private
Fig.A team of AI agents that does a company’s routine work on a schedule, remembers what it learns, and brings every decision to a person.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AWeb
StageThree.js roomUI+
UI · Three.js room
The home screen: each agent a node with live presence, lines where one hands work to another, an artifact shelf and a chat dock.
Talks to
← Live socket (live)
Decisionsj · k · a · rUI+
UI · j · k · a · r
One queue for every pending approval, gate and proposal, triaged from the keyboard, with a log of what was settled today.
Talks to
→ Engine API (approve · reject)
LibraryartifactsUI+
UI · artifacts
Every typed artifact an agent has produced, addressable by key.
Live socketsocket.ioREALTIME+
REALTIME · socket.io
One shared connection per app; the Stage, chat and live thought streams all listen on it.
Talks to
← Redis (pub/sub)
→ Stage (live)
Slackfast-path chatEXTERNAL+
EXTERNAL · fast-path chat
Talk to the agents from Slack, answered by the cheaper runtime.
Talks to
→ Kernel (chat)
BEngine
Engine APInode:httpSERVICE+
SERVICE · node:http
The engine’s HTTP API, on Node’s own http module rather than a framework.
Talks to
← Decisions (approve · reject)
→ Governance
SignalsGitHub · Linear · healthJOB+
JOB · GitHub · Linear · health
Gatherers that collect what changed (code, tickets, business numbers, tool health, memory) before each tick.
Talks to
→ Heartbeat (what changed)
HeartbeatBullMQ · 12 lanesJOB+
JOB · BullMQ · 12 lanes
Health hourly, the inbox every two hours, reviews each morning, weekly analysis, nightly research. Lanes that share resources never overlap, and a circuit breaker pauses an agent that keeps failing.
Talks to
← Team templates (seeds)
← Signals (what changed)
→ Orchestrator (tick)
→ Kernel (cheap lanes)
→ Autoresearch (nightly)
OrchestratorOpus · Agent SDKAI+
AI · Opus · Agent SDK
The top-level agent. It reads the signals, opens and claims a task, and delegates to the specialists.
Talks to
← Heartbeat (tick)
→ 14 sub-agents (delegates)
→ Task loop (claims)
14 sub-agentsHaiku · Sonnet · OpusAI+
AI · Haiku · Sonnet · Opus
Sentinel, Analyst, Scribe, Custodian, Oracle, Architect, Strategist and the rest, each with its own model, tools, budget and yes-or-no checks.
Talks to
← Orchestrator (delegates)
→ Agent runner
→ Governance (proposals)
← Autoresearch (prompts)
← Self-healing (revisions)
→ Anthropic · OpenRouter
KernelOpenRouter · cappedAI+
AI · OpenRouter · capped
A second, cheaper runtime for the frequent lanes, with a hard budget per tick, a turn limit, and only the MCP servers that lane needs.
Talks to
← Heartbeat (cheap lanes)
→ MCP registry (subset)
← Slack (chat)
Team templatesfiveSERVICE+
SERVICE · five
Seeds a team, its schedule and its autonomy defaults in one action.
Talks to
→ Heartbeat (seeds)
Governanceapprovals · autonomySERVICE+
SERVICE · approvals · autonomy
Approval records and the autonomy mode (supervised, assisted or full) that decides what is approved automatically. New agents are capped at 20 per workspace and three a day.
Talks to
← Engine API
← 14 sub-agents (proposals)
Agent runnerone run, start to endSERVICE+
SERVICE · one run, start to end
Checks the budget, loads the agent’s past experience, filters its tools, runs it with a live thought stream, retries on failure, then writes the run to memory.
Talks to
← 14 sub-agents
→ MCP registry (tools)
→ Event mesh (output)
→ Mnemos (write · recall)
→ Costs (checks)
Task loopclaim · settleSERVICE+
SERVICE · claim · settle
The work record. The engine claims a task before delegating and settles whatever is still open when a run ends, so the record is right even if an agent forgets.
Talks to
← Orchestrator (claims)
Event meshagent → agentREALTIME+
REALTIME · agent → agent
Each run’s output is classified and published, so a Sentinel alert lands in the Orchestrator’s triage and an Architect deploy sets off a Sentinel check.
Talks to
← Agent runner (output)
→ Redis (publish)
MCP registry~60 built-in toolsAI+
AI · ~60 built-in tools
Assembles each agent’s tools from the healthy servers, minus the tools that agent is blocked from.
Talks to
← Agent runner (tools)
← Kernel (subset)
→ Dev tools (MCP)
→ Company systems (MCP)
← Integration hub (compiled)
Autoresearch03:00 nightlyJOB+
JOB · 03:00 nightly
Simulates five outputs, grades them on yes-or-no checks, mutates the prompt, simulates five more, and promotes only at five percent better. Every experiment is logged.
Talks to
← Heartbeat (nightly)
→ 14 sub-agents (prompts)
Self-healingbinary evalsJOB+
JOB · binary evals
Scores every run and drafts a prompt revision when quality drops. A revision may change at most a fifth of the prompt, and after three failed revisions in a row a person is asked.
Talks to
→ 14 sub-agents (revisions)
Coststick · day · monthSERVICE+
SERVICE · tick · day · month
Token budgets per agent per tick, per day and per month, under a global cap.
Talks to
← Agent runner (checks)
Integration hubspec → MCPSERVICE+
SERVICE · spec → MCP
Compiles a REST or GraphQL connector from its spec into an in-process MCP server at install time.
Talks to
→ MCP registry (compiled)
← Any API (spec)
CMemory
Mnemosmemory serviceSERVICE+
SERVICE · memory service
The memory, as its own service: written after every run, consolidated on a schedule, searched before the next. Drawn in full below.
Talks to
← Agent runner (write · recall)
→ Neo4j
→ PostgreSQL (vectors)
DData
PostgreSQLPrisma · pgvectorSTORE+
STORE · Prisma · pgvector
Agents, runs, tasks, approvals, budgets and experiments, plus the memory’s embeddings.
Talks to
← Mnemos (vectors)
Neo4jknowledge graphSTORE+
STORE · knowledge graph
The graph of what the agents have learned.
Talks to
← Mnemos
RedisBullMQ · pub/subSTORE+
STORE · BullMQ · pub/sub
The heartbeat’s queues and the event channels.
Talks to
← Event mesh (publish)
→ Live socket (pub/sub)
EReach
Anthropic · OpenRoutermodelsEXTERNAL+
EXTERNAL · models
Claude through the Agent SDK; other models through OpenRouter.
Talks to
← 14 sub-agents
Dev toolsin-process MCPEXTERNAL+
EXTERNAL · in-process MCP
GitHub, Linear and Railway: code, tickets and deploys.
Talks to
← MCP registry (MCP)
Company systemsHTTP MCPEXTERNAL+
EXTERNAL · HTTP MCP
C0, ContentSphere and OutreachSphere, read through their own MCP servers.
Talks to
← MCP registry (MCP)
Any APIREST · GraphQLEXTERNAL+
EXTERNAL · REST · GraphQL
Any API added through the hub.
Talks to
→ Integration hub (spec)
Connections
Decisions → Engine API · approve · reject
Engine API → Governance
Team templates → Heartbeat · seeds
Signals → Heartbeat · what changed
Heartbeat ⇢ Orchestrator · tick
Heartbeat ⇢ Kernel · cheap lanes
Heartbeat ⇢ Autoresearch · nightly
Orchestrator → 14 sub-agents · delegates
Orchestrator → Task loop · claims
14 sub-agents → Agent runner
Agent runner → MCP registry · tools
Agent runner ⇢ Event mesh · output
Agent runner → Mnemos · write · recall
Agent runner → Costs · checks
Kernel → MCP registry · subset
Slack → Kernel · chat
14 sub-agents → Governance · proposals
Autoresearch ⇢ 14 sub-agents · prompts
Self-healing ⇢ 14 sub-agents · revisions
MCP registry → Dev tools · MCP
MCP registry → Company systems · MCP
Integration hub → MCP registry · compiled
Any API → Integration hub · spec
Mnemos → Neo4j
Mnemos → PostgreSQL · vectors
Event mesh ⇢ Redis · publish
Redis ⇢ Live socket · pub/sub
Live socket ⇢ Stage · live
14 sub-agents → Anthropic · OpenRouter
Inside: the memory
Memory isn’t a log. Everything an agent produces is read for what it’s about, merged with what is already known, consolidated every six hours, faded when unused, and searched by meaning, keyword and connection when it’s needed again.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AIn
Run outputsuccessful runsSERVICE+
SERVICE · successful runs
What an agent produced, sent to memory after the run.
Talks to
→ Extract
Experienceevery runSERVICE+
SERVICE · every run
A record of each run, failures included, so an agent can learn from what it has done.
Talks to
→ Knowledge graph (Experience node)
Documentsfiles · URLs · YouTubeSERVICE+
SERVICE · files · URLs · YouTube
Outside material ingested on request.
Talks to
→ Extract
From toolsMCP ingestAI+
AI · MCP ingest
Anything an agent chooses to remember through its memory tools.
Talks to
→ Extract
Scenariosworld modelsSERVICE+
SERVICE · world models
A seed document becomes a model: actors with interests, tensions between them, dynamics and assumptions.
Talks to
→ Knowledge graph (world model)
BWrite
Extractontology-awareAI+
AI · ontology-aware
Pulls out entities and relationships using the known types and their properties. Runs on a local model when one is available, Haiku otherwise.
Talks to
← Run output
← Documents
← From tools
→ Deduplicate
Deduplicatespelling · meaningSERVICE+
SERVICE · spelling · meaning
Matches each entity to one already known: by fuzzy name (bigram similarity of 0.75 or more), then by meaning.
Talks to
← Extract
→ Score
Scoreconfidence · half-lifeSERVICE+
SERVICE · confidence · half-life
Confidence comes from the source; lifespan from the type: 7 days for a signal, 90 for a client, 365 for a principle. Use keeps a memory fresh.
Talks to
← Deduplicate
→ Store
Storemerge · never dropSERVICE+
SERVICE · merge · never drop
Writes nodes idempotently with bounded concurrency. If extraction fails, the raw text is kept as an observation rather than lost.
Talks to
← Score
→ Embed
→ Knowledge graph (MERGE)
Embed1536 dimensionsAI+
AI · 1536 dimensions
Embeds each node for search. In production a failed embedding is an error, never a placeholder that would quietly poison recall.
Talks to
← Store
→ Connect
→ Embeddings
Connectauto-linkSERVICE+
SERVICE · auto-link
Links new nodes to related ones already in the graph.
Talks to
← Embed
→ Knowledge graph (edges)
CStores
Knowledge graphL0 raw · L1 distilledSTORE+
STORE · L0 raw · L1 distilled
Nineteen core kinds of memory in Neo4j (new kinds can appear), from signals and bugs to decisions and principles, each fact able to say when it became true and when it stopped.
Talks to
← Experience (Experience node)
← Scenarios (world model)
← Store (MERGE)
← Connect (edges)
← Compression (L0 → L1)
← Reflection (insights)
← Summaries
← Past experience (experiences)
EmbeddingspgvectorSTORE+
STORE · pgvector
The vectors behind semantic search, cleaned up when a node is archived so it can’t haunt results.
Talks to
← Embed
← Decay (archive)
← Hybrid search (dense)
DKeep
Compressionevery 6 hJOB+
JOB · every 6 h
Clusters similar memories, checks the cluster really is similar (cosine 0.65 or more), and replaces it with one distilled L1 memory. High-value memories are never compressed.
Talks to
→ Knowledge graph (L0 → L1)
Reflectionafter compressionJOB+
JOB · after compression
Reads 12 to 60 recent observations, decisions and experiences together and writes up to eight new insights or patterns.
Talks to
→ Knowledge graph (insights)
SummariesrollingJOB+
JOB · rolling
Keeps a short summary on each node from its properties and its recent connections.
Talks to
→ Knowledge graph
DecaydailyJOB+
JOB · daily
Recomputes each memory’s freshness from its half-life and last use; below 0.05 it is archived. A node with no timestamp is left alone, never archived on a guess.
Talks to
→ Embeddings (archive)
ERecall
Past experiencebefore each runSERVICE+
SERVICE · before each run
The agent’s own past runs, ranked by overlap with the task at hand, added to its prompt so it builds a view from what it has actually done.
Talks to
→ Knowledge graph (experiences)
HyDEhypothetical answerAI+
AI · hypothetical answer
For abstract questions, drafts a likely answer and searches with that instead. Direct lookups skip it.
Talks to
→ Hybrid search
Hybrid searchdense + keyword · RRFSERVICE+
SERVICE · dense + keyword · RRF
Runs semantic and keyword search and fuses the two rankings.
Talks to
← HyDE
→ Embeddings (dense)
→ Graph walk
Graph walk2 hopsSERVICE+
SERVICE · 2 hops
Expands each hit two steps through the graph, so related context comes along.
Talks to
← Hybrid search
→ Filters
Filterstime · type · truthSERVICE+
SERVICE · time · type · truth
Drops archived and invalidated facts, and can answer as of a past date.
Talks to
← Graph walk
→ Rerank
Rerankagainst the questionAI+
AI · against the question
A model reorders the shortlist against the original question, not the expanded one.
Talks to
← Filters
Connections
Run output → Extract
Documents → Extract
From tools → Extract
Experience → Knowledge graph · Experience node
Scenarios → Knowledge graph · world model
Extract → Deduplicate
Deduplicate → Score
Score → Store
Store → Embed
Embed → Connect
Store → Knowledge graph · MERGE
Embed → Embeddings
Connect → Knowledge graph · edges
Compression ⇢ Knowledge graph · L0 → L1
Reflection ⇢ Knowledge graph · insights
Summaries ⇢ Knowledge graph
Decay ⇢ Embeddings · archive
Past experience → Knowledge graph · experiences
HyDE → Hybrid search
Hybrid search → Embeddings · dense
Hybrid search → Graph walk
Graph walk → Filters
Filters → Rerank
Two flows
How an agent remembers
Step through it and the parts it runs through light up above.
By count
agent roles
15
heartbeat lanes
12
built-in tools
~60
kinds of memory, each with its own lifespan
19
team templates
5
autonomy modes
3
Notes
N.1Every kind of memory has its own lifespan. A signal fades in a week, a client in three months, a principle in a year, and anything that keeps getting used stays fresh.
N.2Memory can answer “what did we believe in March?” Facts carry when they became true and when they stopped, and recall can ask about a past date.
N.3If a model can’t make sense of something, it is still kept as a raw note. Nothing an agent learns is silently dropped.
N.4The agents react to each other. A Sentinel alert lands in the Orchestrator’s triage, and an Architect deploy sets off a Sentinel check.
Open-source Claude Code plugins. Free Claude Code plugins for contractors. Tell Claude about your company once, and it drafts estimates, bid packages, RFIs and daily logs in your brand.
Live · open source
Fig.Free Claude Code plugins for contractors: tell Claude about your company once, and it writes the paperwork in your brand.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AInstall
Your forkgit repoEXTERNAL+
EXTERNAL · git repo
Fork the repo, configure it once, and push it to a private repo. Teammates clone it and get the company’s skills with no setup.
Talks to
→ Claude Code (marketplace add)
Claude Codeplugin marketplaceEXTERNAL+
EXTERNAL · plugin marketplace
The marketplace file registers six plugins; each installs on its own.
Talks to
← Your fork (marketplace add)
→ /initialize (installs)
claude.ai · Coworkskill zipsEXTERNAL+
EXTERNAL · skill zips
The same skills as standalone packages, for the web app.
Talks to
← Skill packages (upload)
BSetup
/initializeten sectionsUI+
UI · ten sections
A conversational interview, one section at a time. Each answer is written into the template tokens of every skill that uses it; re-run one section and only its tokens change.
Talks to
← Claude Code (installs)
→ Company config (writes)
Company configlocal MarkdownSTORE+
STORE · local Markdown
The company’s answers, kept in local config. Capabilities are read at run time rather than substituted.
Talks to
← /initialize (writes)
→ contractor-brand (tokens)
→ contractor-estimating (defaults)
contractor-brandcolors · fonts · voiceSERVICE+
SERVICE · colors · fonts · voice
Keeps every document on-brand: colors, type, logos and how the company sounds.
Talks to
← Company config (tokens)
→ contractor-docs (brand)
CSkills
contractor-estimating13 skillsSERVICE+
SERVICE · 13 skills
The preconstruction pipeline: ROM, plan takeoff, conceptual budget, scope check, sub bid packages, bid leveling, formal bid, contract and subcontract.
Setup rewrites a company’s own files, so it is run like a change to production: planned, shown as an exact diff, approved, backed up, applied, and checked byte for byte, with nothing ever reported as done that wasn’t.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AInterview
Ten sectionsone at a timeUI+
UI · one at a time
Company, services, brand colors, type, logos, voice, contact, ideal client, capabilities and estimating defaults, each with a default you can accept.
Talks to
→ Staged answers
Section re-runonly its tokensUI+
UI · only its tokens
Re-run one section and only that section’s values change.
Talks to
→ Staged answers
BPlan
Staged answersoutside live filesSERVICE+
SERVICE · outside live files
Answers and full proposed files are staged away from the real ones and validated first.
Talks to
← Ten sections
← Section re-run
→ Change plan
Change planbefore hashes · contextsSTORE+
STORE · before hashes · contexts
Every file, its hash before, the exact text and context of each replacement, and the fields that change. No global find-and-replace.
Talks to
← Staged answers
→ Diff + approval
Diff + approvalbound to the planUI+
UI · bound to the plan
The exact diff is shown, and approval is tied to that plan; change the plan and it needs approving again.
Talks to
← Change plan
→ Snapshot (approved)
CApply
Snapshotbackups firstJOB+
JOB · backups first
Backs up every target and verifies the backups before anything is touched.
Talks to
← Diff + approval (approved)
→ Recheck
Recheckstale hash voids itSERVICE+
SERVICE · stale hash voids it
Checks each file still matches its hash from the plan. If it changed since approval, the approval no longer counts.
Talks to
← Snapshot
→ Exact edits
Exact editsper file, per contextSERVICE+
SERVICE · per file, per context
Applies only the approved edits.
Talks to
← Recheck
→ Readback
Readbackafter hashes · fieldsSERVICE+
SERVICE · after hashes · fields
Reopens every changed file and compares it to the approved result, byte for byte and field by field.
Talks to
← Exact edits
→ Receipt (pass)
→ Needs a person (fail)
DOutcome
Needs a personnever a false successSERVICE+
SERVICE · never a false success
Any failure, interruption or missing backup stops here, with the backups kept.
Talks to
← Readback (fail)
→ Resume
Resumebefore · after · conflictSERVICE+
SERVICE · before · after · conflict
On restart each file is classed from its actual bytes; finished edits are never repeated, and nothing is rolled back over someone else’s changes.
Talks to
← Needs a person
Receiptmeasured, not claimedSTORE+
STORE · measured, not claimed
Reports only what was measured: sections, changed files, checkpoint and any tokens still unfilled.
Talks to
← Readback (pass)
Connections
Ten sections → Staged answers
Section re-run → Staged answers
Staged answers → Change plan
Change plan → Diff + approval
Diff + approval → Snapshot · approved
Snapshot → Recheck
Recheck → Exact edits
Exact edits → Readback
Readback → Receipt · pass
Readback → Needs a person · fail
Needs a person → Resume
Two flows
An idea becomes a formal bid
Step through it and the parts it runs through light up above.
By count
plugins
6
skills
38
agents
3
setup sections
10
Notes
N.1Setup is a ten-minute interview: name, colors, logos, how you talk, who your clients are. Every document after that uses it.
N.2Every skill is plain Markdown. You can open one and change how it works.
N.3Push your configured copy to a private repo and your whole team gets your company’s skills with no setup.
N.4A finished document can’t be saved with a blank {{TOKEN}} left in it.
Content system. Each client’s newsletters, LinkedIn posts and web copy, planned from their brand and drafted from prompts written for them. The client approves every piece.
Live · internal
Fig.A content studio for Formwork’s clients: newsletters, LinkedIn posts and web copy, planned from each brand and approved by the client.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APeople
Writers · adminsNext.js 15UI+
UI · Next.js 15
Formwork’s content team: brand, plans, pieces, approvals and the calendar, one client at a time.
Talks to
→ Content pieces (edit)
Client portalper clientUI+
UI · per client
Clients read their pieces, comment and approve.
Talks to
→ Review (approve)
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude, connected with a scoped key, working the same content through MCP.
Talks to
→ MCP server (MCP · key)
BApp
Brand strategyversionedSERVICE+
SERVICE · versioned
Each client’s positioning, pillars and voice, with every version kept.
Talks to
→ Personas
→ Content plans (informs)
Personasaudiences · frameworksSERVICE+
SERVICE · audiences · frameworks
Who the client is talking to, and the messaging frameworks for each audience.
Talks to
← Brand strategy
Transcriptsclient callsSERVICE+
SERVICE · client calls
Calls with the client, kept as source material for topics.
Talks to
→ Content plans (topics)
Content plansmonthlySERVICE+
SERVICE · monthly
The month’s topics per channel, drawn from the strategy and the calls.
Talks to
← Brand strategy (informs)
← Transcripts (topics)
→ Content pieces (pieces)
→ C0 (deliverables)
MCP server112 tools · scoped keysAI+
AI · 112 tools · scoped keys
A fresh server per request, with only the tool groups the key’s scopes allow. Keys are stored hashed.
Talks to
← Claude (MCP · key)
← Six specialists (own tools)
Prompt matrixclient × content typeSERVICE+
SERVICE · client × content type
The instructions for every pairing of client and kind of content.
Talks to
→ Generation (instructions)
Generationdraft · rewriteAI+
AI · draft · rewrite
Drafts and rewrites pieces from the matrix, with the client’s context.
Talks to
← Prompt matrix (instructions)
→ Content pieces (drafts)
→ Claude · OpenAI (generate)
Content piecesdrafts · versionsSERVICE+
SERVICE · drafts · versions
One piece per channel, with versioned drafts, comments and a status.
Talks to
← Content plans (pieces)
← Generation (drafts)
← Writers · admins (edit)
→ Review
→ PostgreSQL (SQL)
Reviewteam → clientSERVICE+
SERVICE · team → client
Internal review, then the client’s. A piece can’t enter review without real draft copy.
Talks to
← Content pieces
← Client portal (approve)
→ Calendar (approved)
→ Slack (notify)
CalendarscheduledSERVICE+
SERVICE · scheduled
Approved pieces, on the dates they go out.
Talks to
← Review (approved)
CAgents
OrchestratorClaude Agent SDKAI+
AI · Claude Agent SDK
The in-app agent. It hands work to the right specialist.
Talks to
→ Six specialists (delegates)
→ Claude · OpenAI
Six specialistsstrategy → campaignsAI+
AI · strategy → campaigns
Specialists from strategy and writing to prompts and campaigns, each limited to the tools its job needs, plus one tool to hand work to another.
Talks to
← Orchestrator (delegates)
→ MCP server (own tools)
DData
PostgreSQLPrismaSTORE+
STORE · Prisma
Clients, strategy, plans, pieces, versions and comments.
Talks to
← Content pieces (SQL)
EOutside
Claude · OpenAImodelsEXTERNAL+
EXTERNAL · models
The models behind drafting and the agents.
Talks to
← Generation (generate)
← Orchestrator
C0deliverables APIEXTERNAL+
EXTERNAL · deliverables API
Formwork’s operations system, where each piece is also a tracked deliverable.
Talks to
← Content plans (deliverables)
SlacknotificationsEXTERNAL+
EXTERNAL · notifications
Tells the team when work needs them.
Talks to
← Review (notify)
Connections
Brand strategy → Personas
Brand strategy → Content plans · informs
Transcripts → Content plans · topics
Content plans → Content pieces · pieces
Prompt matrix → Generation · instructions
Generation → Content pieces · drafts
Generation → Claude · OpenAI · generate
Writers · admins → Content pieces · edit
Content pieces → Review
Client portal → Review · approve
Review → Calendar · approved
Review ⇢ Slack · notify
Content plans → C0 · deliverables
Claude → MCP server · MCP · key
Orchestrator → Six specialists · delegates
Six specialists → MCP server · own tools
Orchestrator → Claude · OpenAI
Content pieces → PostgreSQL · SQL
Inside: specialist agents and the prompt matrix
The in-app agent isn’t one model with every tool. An orchestrator hands work to specialists that each see only their own tools, and every draft starts from instructions written for that client, that kind of content and that reader.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AAsk
Agent chatin the appUI+
UI · in the app
Where the team asks for plans, drafts and campaigns in plain words.
Talks to
→ Orchestrator
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude outside the app, using the same tools through a scoped key.
Talks to
→ Tool subsets (MCP)
BLead
Orchestratorstreams · tool roundsAI+
AI · streams · tool rounds
Streams its answer, runs tool calls in rounds up to a limit, and delegates to one of six specialists.
Talks to
← Agent chat
← Agent prompts (instructions)
→ Strategist (delegates)
→ Creator
→ Campaign manager
→ Prompt engineer
Agent promptseditableSTORE+
STORE · editable
Each agent’s instructions live in the database, so they can be tuned without a deploy, with built-in defaults if the database is unavailable.
Talks to
→ Orchestrator (instructions)
CSpecialists
Strategistbrand · audiencesAI+
AI · brand · audiences
Brand strategy, audiences, messaging frameworks, pillars and client context.
Talks to
← Orchestrator (delegates)
Creatorpieces · draftsAI+
AI · pieces · drafts
Writes and manages pieces: LinkedIn posts, newsletters, case studies, articles.
Talks to
← Orchestrator
→ Client prompts (reads)
Campaign managerplans · calendar · shootsAI+
AI · plans · calendar · shoots
Content plans, the editorial calendar, photo and video shoots, assets, and updates from construction projects.
Talks to
← Orchestrator
Prompt engineerprompts · personasAI+
AI · prompts · personas
Designs the prompt matrix and personas, and tunes generation quality.
Talks to
← Orchestrator
→ Tool subsets
Tool subsetsper specialistSERVICE+
SERVICE · per specialist
Each specialist gets its own list of tools plus one to hand work to another; nothing else is offered to it.
Talks to
← Claude (MCP)
← Prompt engineer
DMatrix
Client promptsclient · type · personaSTORE+
STORE · client · type · persona
Instructions written for one client and one kind of content, optionally for one persona. These win when they exist.
Talks to
← Creator (reads)
→ Draft (first choice)
Default matrixfallbackSTORE+
STORE · fallback
The house prompts, used when a client has none of its own.
Talks to
→ Draft (fallback)
Drafttraced to its promptAI+
AI · traced to its prompt
The generated draft records which prompt produced it, so a bad draft can be traced to its instructions.
Talks to
← Client prompts (first choice)
← Default matrix (fallback)
Connections
Agent chat → Orchestrator
Agent prompts → Orchestrator · instructions
Orchestrator → Strategist · delegates
Orchestrator → Creator
Orchestrator → Campaign manager
Orchestrator → Prompt engineer
Claude → Tool subsets · MCP
Prompt engineer → Tool subsets
Creator → Client prompts · reads
Client prompts → Draft · first choice
Default matrix → Draft · fallback
Two flows
A topic becomes a published piece
Step through it and the parts it runs through light up above.
By count
specialist agents
6
rounds of review: team, then client
2
actions Claude can take in it
112
Notes
N.1Prompts are a matrix of client by kind of content. A newsletter for one contractor and a LinkedIn post for another start from different instructions.
N.2Six specialist agents, from strategy to campaigns. Each gets only the tools its job needs, plus one to hand work to another.
01.8
C0
Internal operations system. Runs Formwork day to day: clients, projects, tasks and invoices in one place, synced with the books. After each meeting, Claude drafts the follow-up tasks.
Live · runs Formwork
Fig.How Formwork runs: sales, clients, work, money and meetings in one place, with a portal for each kind of person.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APortals
ExecutiveportalUI+
UI · portal
The whole firm: money, clients, people and objectives.
Talks to
→ Middleware (cookie)
Manager · memberportalsUI+
UI · portals
Managers see their team; members see their own tasks and time.
ClientportalUI+
UI · portal
Clients see their services, billing, content, outreach and tasks.
Talks to
→ Middleware
ProspectportalUI+
UI · portal
A prospect’s own view of what Formwork offers them.
ClaudeMCP clientEXTERNAL+
EXTERNAL · MCP client
Claude over MCP, with tools scoped to the person’s role.
Talks to
→ MCP server (MCP)
BApp
MiddlewareJWT · role routesSERVICE+
SERVICE · JWT · role routes
Checks the session cookie, routes each role to its portal, and catches a role that changed since sign-in.
Talks to
← Executive (cookie)
← Client
→ Clients (by role)
ProspectsproposalsSERVICE+
SERVICE · proposals
Prospects and proposals, until one converts to a client.
Talks to
→ Clients (converts)
Clientsservices · healthSERVICE+
SERVICE · services · health
Each client and the services they buy, with one health score from 0 to 100.
Talks to
← Middleware (by role)
← Prospects (converts)
→ Projects · tasks
→ Invoices · expenses (bills)
→ Sales & content (outreach · content)
Projects · taskstime logsSERVICE+
SERVICE · time logs
The work for each service, with dependencies and time logged.
Talks to
← Clients
← Task drafting (drafts)
→ PostgreSQL (SQL)
→ Airtable (dual write)
Invoices · expensespaymentsSERVICE+
SERVICE · payments
Invoices, payments and expenses, allocated to clients and services.
Talks to
← Clients (bills)
← Plaid (bank feeds)
← Bank matching (matches)
MCP server250+ tools by roleAI+
AI · 250+ tools by role
Tools composed by role: a client sees about ten, an executive over two hundred.
Talks to
← Claude (MCP)
← Chat agent (catalogue)
→ Knowledge base (kb tools)
MeetingstranscriptsSERVICE+
SERVICE · transcripts
Each meeting and its transcript, with a badge until its drafted tasks are approved.
Talks to
→ Task drafting (transcript)
→ Knowledge base (mined)
Task draftingClaudeAI+
AI · Claude
Drafts follow-up tasks from a transcript, with the context around the meeting.
Talks to
← Meetings (transcript)
→ Projects · tasks (drafts)
→ Claude · OpenRouter
Knowledge basefacts · reviewAI+
AI · facts · review
Claims mined from meetings, embedded and merged into facts. New ones are candidates until a second model verifies them.
Talks to
← Meetings (mined)
← MCP server (kb tools)
Bank matchingconfidence tiersSERVICE+
SERVICE · confidence tiers
Matches each cash line from the books to an invoice, a subscription or a person, with a confidence score. Only the surest can be approved in bulk.
Talks to
← QuickBooks (webhooks)
→ Invoices · expenses (matches)
Chat agentsearch · describe · runAI+
AI · search · describe · run
Above a threshold it gets a category index and three meta-tools instead of every schema, and loads only the tools it means to call.
Talks to
→ MCP server (catalogue)
CJobs
Due-date checksscheduledJOB+
JOB · scheduled
Flags tasks coming due and invoices gone overdue.
Talks to
→ Slack (alerts)
Scheduled emailscheduledJOB+
JOB · scheduled
Sends reports and scheduled emails.
DData
PostgreSQLprimary · PrismaSTORE+
STORE · primary · Prisma
Where every read comes from.
Talks to
← Projects · tasks (SQL)
Airtabledual writeSTORE+
STORE · dual write
Writes for tasks, time and money also land here, so the rollups people already use stay right.
Talks to
← Projects · tasks (dual write)
EOutside
QuickBooksOAuth · webhooksEXTERNAL+
EXTERNAL · OAuth · webhooks
The books. Its webhooks bring each change across.
Talks to
→ Bank matching (webhooks)
Plaidbank feeds · webhooksEXTERNAL+
EXTERNAL · bank feeds · webhooks
Live bank balances and transactions.
Talks to
→ Invoices · expenses (bank feeds)
Sales & contentFormwork’s own appsEXTERNAL+
EXTERNAL · Formwork’s own apps
OutreachSphere and ContentSphere, read for each client’s outreach and content.
Talks to
← Clients (outreach · content)
SlackalertsEXTERNAL+
EXTERNAL · alerts
Where the due-date and overdue alerts land.
Talks to
← Due-date checks (alerts)
Claude · OpenRoutermodelsEXTERNAL+
EXTERNAL · models
The models behind drafting, the knowledge base and the agent.
Talks to
← Task drafting
Connections
Executive → Middleware · cookie
Client → Middleware
Middleware → Clients · by role
Prospects → Clients · converts
Clients → Projects · tasks
Clients → Invoices · expenses · bills
Meetings → Task drafting · transcript
Task drafting → Projects · tasks · drafts
Meetings → Knowledge base · mined
Task drafting → Claude · OpenRouter
QuickBooks ⇢ Bank matching · webhooks
Plaid ⇢ Invoices · expenses · bank feeds
Bank matching → Invoices · expenses · matches
Claude → MCP server · MCP
Chat agent → MCP server · catalogue
MCP server → Knowledge base · kb tools
Projects · tasks → PostgreSQL · SQL
Projects · tasks ⇢ Airtable · dual write
Due-date checks ⇢ Slack · alerts
Clients → Sales & content · outreach · content
Inside: meetings, tasks and what Formwork knows
A meeting does two jobs. It becomes tasks people approve, and it teaches the firm something: claims are pulled out, matched to the people and companies they’re about, deduplicated, checked by a second model, and fed back into the next meeting about that client.
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
AIn
Transcriptper meetingUI+
UI · per meeting
The meeting’s transcript, internal or with a client.
Talks to
→ Meeting context
Meeting contextpeople · services · goalsSERVICE+
SERVICE · people · services · goals
Who was there, the client and their active services, and the firm’s current objectives and projects, so tasks land in the right place.
Talks to
← Transcript
→ Tasks + summary
Account memorywhat we already knowAI+
AI · what we already know
What the firm already knows about this client, injected before analysis. A knowledge-base failure never blocks the meeting.
Talks to
→ Tasks + summary (injected)
→ Search (account spine)
BAnalysis
Tasks + summaryClaude · in parallelAI+
AI · Claude · in parallel
Writes the meeting summary and the follow-up tasks at the same time, each with an assignee, a service, a project and a due date.
Talks to
← Meeting context
← Account memory (injected)
→ Approval (drafts)
→ Slack
→ Claim extraction (transcript)
Approvalbadge until approvedUI+
UI · badge until approved
Drafted tasks wait for a person. Until they are approved the meeting shows a badge.
Talks to
← Tasks + summary (drafts)
Slacksummary · tasksEXTERNAL+
EXTERNAL · summary · tasks
The summary and the drafted tasks are posted to Slack.
Talks to
← Tasks + summary
CLearn
Claim extractionHaiku · Sonnet if unsureAI+
AI · Haiku · Sonnet if unsure
Picks out claims worth keeping about the industry, the client or the business, tagged from a fixed vocabulary of 22 topics. Internal meetings need more confidence to count.
Talks to
← Tasks + summary (transcript)
→ Entity resolution (mentions)
→ Dedup (claims)
Entity resolutionnames · aliasesSERVICE+
SERVICE · names · aliases
Maps “Logan”, “Logan Smith” and “chief estimator” to the same person, following merges; a new name starts as a candidate for review.
Talks to
← Claim extraction (mentions)
→ Entity graph
Deduphash · cosine 0.92SERVICE+
SERVICE · hash · cosine 0.92
An exact restatement or a near-duplicate becomes a new citation on the existing fact instead of a new row.
Talks to
← Claim extraction (claims)
→ Facts
Auto-reviewsecond modelAI+
AI · second model
Verifies or rejects new facts. Nothing is verified on the way in; borderline ones stay for a person to spot-check.
Talks to
→ Facts (verify)
Latest winssupersededSERVICE+
SERVICE · superseded
When a newer claim replaces an old one, the old one is marked superseded rather than deleted.
Talks to
→ Facts
DRecall
Factspgvector · 1024-dSTORE+
STORE · pgvector · 1024-d
Canonical facts with their citations, embedded with one locked model whose name is stored beside each vector for future migrations.
Talks to
← Dedup
← Auto-review (verify)
← Latest wins
← Search
Entity graphtyped edgesSTORE+
STORE · typed edges
People, companies and projects, linked to the account they belong to.
Talks to
← Entity resolution
Searchverified-onlySERVICE+
SERVICE · verified-only
Semantic search with metadata filters, verified facts only by default so agents don’t retrieve noise, plus a keyed account spine, newest first.
Talks to
→ Facts
← kb tools
← Account memory (account spine)
kb toolsMCPAI+
AI · MCP
Search, expand an entity, add or verify a fact, and the review queue, for any agent.
Talks to
→ Search
Connections
Transcript → Meeting context
Meeting context → Tasks + summary
Account memory → Tasks + summary · injected
Tasks + summary → Approval · drafts
Tasks + summary ⇢ Slack
Tasks + summary → Claim extraction · transcript
Claim extraction → Entity resolution · mentions
Claim extraction → Dedup · claims
Entity resolution → Entity graph
Dedup → Facts
Auto-review ⇢ Facts · verify
Latest wins → Facts
Search → Facts
kb tools → Search
Account memory → Search · account spine
Two flows
A meeting becomes work
Step through it and the parts it runs through light up above.
N.1Client health is one number from 0 to 100, computed in one place, so the members list, the invoice header and the exec dashboard never disagree.
N.2Clients get their own portal with their services, billing, content, outreach and tasks.
N.3Bank lines are matched to invoices and people with a confidence score. Only the surest matches can be approved in bulk.
01.9
Delta Portal
Custom enterprise platform. Delta Construction’s project system, which replaced Procore: RFIs, bidding, contracts, chat and Autodesk files. Architects and subs reply from a link.
Live · Delta Construction
Fig.Delta Construction’s project system, for its own team and for the architects and subs it works with.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APeople
Delta’s teamweb · phones · iPadsUI+
UI · web · phones · iPads
Delta’s project managers, engineers and field staff, in the app.
Talks to
→ Public API (HTTPS)
→ Live sockets (live)
Architects & subsemailed linksUI+
UI · emailed links
People outside Delta. They answer RFIs and submit bids from a link, without an account.
Talks to
→ Public API (emailed link)
BGateway
Public APISpring Boot · JWTSERVICE+
SERVICE · Spring Boot · JWT
Checks who is asking and forwards each request with their identity. Link tokens are checked here too.
Talks to
← Delta’s team (HTTPS)
← Architects & subs (emailed link)
→ Project (REST)
→ Bid packages (REST)
Live socketsWebSocketsREALTIME+
REALTIME · WebSockets
Pushes chat and notifications to open apps as they happen.
Talks to
← Delta’s team (live)
← Redis (pub/sub)
CProject
Projectteam · directorySERVICE+
SERVICE · team · directory
Everything hangs off a project and the companies and people on it.
Talks to
← Public API (REST)
→ Bid packages (packages)
→ PostgreSQL (SQL)
← Procore (import)
RFIsball in courtSERVICE+
SERVICE · ball in court
Questions to the design team, with the ball moving between companies as the RFI is answered.
Submittalsrevise & resubmitSERVICE+
SERVICE · revise & resubmit
Submittals go round in revisions until approved.
Drawingssheets · revisionsSERVICE+
SERVICE · sheets · revisions
Plan sets split into sheets, with revisions side by side.
Talks to
→ Object storage (files)
→ Autodesk APS (linked files)
Chatreal timeSERVICE+
SERVICE · real time
Project conversations, live.
Talks to
→ Redis (publish)
Bid packagesinvites · levelingSERVICE+
SERVICE · invites · leveling
A trade’s scope packaged for bidding, with the subs invited to it.
Talks to
← Public API (REST)
← Project (packages)
→ Bids (collects)
BidsSOV · alternatesSERVICE+
SERVICE · SOV · alternates
Each sub’s bid, with a schedule of values and any alternates, levelled against the others.
Talks to
← Bid packages (collects)
→ Contracts (awarded)
ContractsSOV from the awardSERVICE+
SERVICE · SOV from the award
The awarded bid’s schedule of values is carried onto a payable contract on the same project.
Talks to
← Bids (awarded)
Notificationsin-app · emailSERVICE+
SERVICE · in-app · email
Tells people when something they own moves.
Talks to
→ Redis (publish)
DData
PostgreSQLSTORE+
STORE
The record of every project, RFI, bid and contract.
Talks to
← Project (SQL)
Object storageS3-compatibleSTORE+
STORE · S3-compatible
Drawings, attachments and photos.
Talks to
← Drawings (files)
Redispub/subSTORE+
STORE · pub/sub
Carries chat and notification events to the sockets.
Talks to
← Chat (publish)
← Notifications (publish)
→ Live sockets (pub/sub)
ELinks
Procoreone-time importEXTERNAL+
EXTERNAL · one-time import
Projects came across from Procore once. Nothing writes back.
Talks to
→ Project (import)
Autodesk APSfolders · filesEXTERNAL+
EXTERNAL · folders · files
Delta’s Autodesk folders and files, linked to the project.
Talks to
← Drawings (linked files)
Connections
Delta’s team → Public API · HTTPS
Architects & subs → Public API · emailed link
Delta’s team → Live sockets · live
Public API → Project · REST
Public API → Bid packages · REST
Project → Bid packages · packages
Bid packages → Bids · collects
Bids → Contracts · awarded
Chat ⇢ Redis · publish
Notifications ⇢ Redis · publish
Redis ⇢ Live sockets · pub/sub
Project → PostgreSQL · SQL
Drawings → Object storage · files
Drawings → Autodesk APS · linked files
Procore ⇢ Project · import
One flow
A bid package becomes a subcontract
Step through it and the parts it runs through light up above.
Notes
N.1It replaced Procore. Projects were brought over from Procore once; nothing writes back to it.
N.2People outside Delta answer RFIs and submit bids from an emailed link, so the people who owe a reply don’t need a login.
N.3Chat is live, and you aren’t notified about a conversation you’re already reading.
01.10
Delta Estimating Portal
Bid pipeline & CRM. Shows Delta’s estimators what they’re bidding and when: each bid gets a slot with a name, dates and hours, beside the client account.
Live · Delta Construction
Fig.Delta’s bid pipeline: what the estimators are working on, for whom, and when.
Architecture
Choose any box for what it does, what it’s built with and what it talks to. Solid lines are requests; dashed lines are webhooks, queues, pub/sub and schedules.
APeople
Delta’s teamweb appUI+
UI · web app
The people who log leads and look after client accounts.
Talks to
→ Leads (logs)
Estimatorstheir scheduleUI+
UI · their schedule
Each estimator sees what they’re bidding, and when.
Talks to
→ Estimating slots (their week)
BPipeline
Leadsstatuses you setSERVICE+
SERVICE · statuses you set
Every bid opportunity, moving through statuses the team defines.
Talks to
← Delta’s team (logs)
→ Client accounts (for)
→ Follow-ups
→ Estimating slots (scheduled)
→ Project (won)
Follow-upscalls · emailsSERVICE+
SERVICE · calls · emails
Calls and emails due on a lead, logged when done.
Talks to
← Leads
→ Interactions (logged as)
Estimating slotswho · dates · hoursSERVICE+
SERVICE · who · dates · hours
A bid on the estimating schedule: which estimator, which dates, hours planned and hours actually spent.
Talks to
← Estimators (their week)
← Leads (scheduled)
→ Estimator profiles (assigned)
Estimator profilesspecialtiesSERVICE+
SERVICE · specialties
Each estimator and their specialties.
Talks to
← Estimating slots (assigned)
Client accountsSERVICE+
SERVICE
The companies Delta bids for, with their own statuses.
Talks to
← Leads (for)
→ Contacts
ContactsSERVICE+
SERVICE
The people at each account.
Talks to
← Client accounts
InteractionstimelineSERVICE+
SERVICE · timeline
Every call, email and meeting with an account, on one timeline.
Talks to
← Follow-ups (logged as)
→ PostgreSQL (SQL)
Projectwhen it’s wonSERVICE+
SERVICE · when it’s won
A won lead becomes a project.
Talks to
← Leads (won)
CData
PostgreSQLSTORE+
STORE
The record of leads, accounts and the schedule.
Talks to
← Interactions (SQL)
Connections
Delta’s team → Leads · logs
Estimators → Estimating slots · their week
Leads → Client accounts · for
Client accounts → Contacts
Leads → Follow-ups
Follow-ups → Interactions · logged as
Leads → Estimating slots · scheduled
Estimating slots → Estimator profiles · assigned
Leads → Project · won
Interactions → PostgreSQL · SQL
One flow
A lead gets an estimator
Step through it and the parts it runs through light up above.
Notes
N.1An estimating slot keeps the hours planned next to the hours actually spent, per estimator.
N.2The team sets its own lead statuses, so the pipeline uses their words.
I’m a systems architect in Virginia. In 2024 I co-founded Formwork, and I build the software it and its clients run on.
Since 2022 I’ve also been at CGI Federal, building AI for Medicare and Medicaid. On my own time I build a synth and AI tools that test software and run agents. I studied computer information systems at James Madison.
Formwork does sales, marketing and software for commercial construction contractors. I built all of its technology, and I decide how it fits together across the three units. It started as Sunrise Systems.
I work in the Health and Social Services unit. I built the AI prototypes that led to a contract award from the Centers for Medicare & Medicaid Services. I also built the tracking systems and the dashboards leadership uses to see the team’s work.
1“He has been integral in the development of tracking systems and dashboards, automating and displaying team function at an executive level.”