Engineering Diagram Library — v1

How KEEP Is Built

Seven diagrams for the public site: what KEEP is, how Merlin is governed and bounded, how a Hub and its Spokes fit together, how sign-in and authentication work, how technician authorization works once someone is signed in, and two concrete proofs of engineering discipline (signal intelligence and Spoke trust). Sourced from KEEP's approved architecture documentation; every Planned/Future item is labeled as such, not presented as shipped.

Source documentation/architecture/*, merlin.md, merlin-onboarding.md, KEEP_PRODUCT_STRATEGY_V1.md Date 2026-08-07 Audience keepmsp.io — evaluators & technical visitors

§0 Legend

One shared encoding across all six diagrams.

CurrentBuilt and live today
PlannedLocked architecture, not yet built
FutureNamed in docs, not scoped or committed
ExternalOutside KEEP's own trust boundary
Trust boundaryA network, org, or vendor crossing
Authority flowWho may act, and on whose behalf
Audit writeWhere an action or refusal is recorded
RefusedBlocked by governance, never executes

§1 Merlin Governance & Decision Model

AUTHORITY FLOW — MERLIN OWNS NONE OF IT KEEP governing authority Director grants / revokes Merlin's authority Acting Session the human authorizing right now Merlin borrows the session's authority only No standing authority of its own. If the acting human can't do it, Merlin can't either — regardless of what it would otherwise recommend. capability classes — live in V1 Observe gather real state — incidents, logs, scans, telemetry Analyze reason over observed state to produce a diagnosis or brief Correlate connect observations across devices, incidents, or time Recommend a conclusion, traceable to what was observed Authorization Evaluation Identity → Authority → Policy → Rule Boundary every request is sorted: Allowed · Prohibited · Never-Permitted Prohibited / Never-Permitted — refused, recorded, stops here Allowed Live Confirmation default — human explicitly approves in the moment one exception: duress PIN — immediate, automatic, no pause Standing Pre-Authorization Deterministic rule evaluation, persistence, and audit are built — the LLM is never re-invoked live at trigger time Director-facing interface to create/sign a rule: PLANNED — NOT YET AVAILABLE Execute change state outside KEEP's own logs AUTONOMOUS EXECUTE: PROHIBITED · POLICY-FIRED EXECUTE: FUTURE Audit — every approval, refusal, and ambiguity, append-only merlin.md §8 (corrected 2026-08-10): environment-changing actions require durable audit; producing information does not 2 of 3 surfaces' refusals still reach only console.warn — see note below CURRENT FOR MUTATING ACTIONS · SMALLER GAP REMAINS FOR REFUSALS
Figure 1. Authority never originates with Merlin — it is always borrowed from whichever human session is active. Execute is drawn outside the Version 1 boundary deliberately: no policy, standing or live, currently authorizes it.
Purpose
Show that Merlin operates inside deterministic governance and bounded authority — the core trust claim behind every other Merlin surface.
Major components
Authority chain (KEEP → Director → Acting Session → Merlin); capability classes (Observe, Analyze, Correlate, Recommend — live; Execute — future-only); Authorization Evaluation gate; two approval modes (Live Confirmation, Standing Pre-Authorization) plus the one named duress exception; the audit terminus.
Relationships
Authority flows one direction only and is never assumed by Merlin. The LLM is invoked only for Analyze/Correlate/Recommend — never for a standing-policy trigger. A refusal bypasses approval and execution entirely, going straight to audit. Every path, approved or refused, ends at the same audit terminus.
Why the site
Turns "advisor by default, executor only when authorized" from a claim into a checkable mechanism — the first thing a technically skeptical evaluator should see.
Partially resolved 2026-08-15 — narrowed, not a remaining "no exception" gap

Audit coverage: the rule was corrected, a smaller gap remains, honestly tracked

A direct code-inspection pass (2026-08-04, documentation/merlin-architecture-diagrams.html) found that of Merlin's three live surfaces, only the Incident Coordinator durably persisted both successful responses and ordinary refusals (into incident_log). Rather than requiring the other two surfaces to match that bar, a 2026-08-10 Director decision corrected merlin.md §8 itself: durable audit is now required only for actions that change the environment — Device Diagnosis and Onboarding Scan Analysis are analysis-only (never able to reach a mutating action, verified in merlin-rule-boundary.ts), so they were never actually required to carry that treatment. What remains, honestly tracked rather than closed by the rule change: their ordinary refusals still only reach console.warn, not a durable record — recorded as MERLIN-AUDIT-COVERAGE-PARTIAL in the project's roadmap. Standing-policy ambiguity events (§18) are, and always were, durably audited for all three routes (migration 068).

§2 Hub / Spoke System Architecture

CUSTOMER NETWORK Client Devices switches, servers, UPS, workstations, printers SNMP / WinRM / SSH / LDAP read-only, no configuration changes SPOKE discover.js · poll.js same codebase as the Hub CURRENT — Spoke initiates, Hub waits SOLO variant Hub with no Spokes — scans its own network directly Tailscale / self-hosted Headscale tunnel (or direct HTTPS — cloud-hosted Hub) HUB — MSP-OPERATED, ON-PREM OR CLOUD Hub App (Next.js) operational authority — device data, incidents, credentials CURRENT Undercroft (Postgres) the Hub's own system of record bind-mounted on the host, outside the container devices, incidents, vulnerabilities, UPS readings Self-contained services Uptime Kuma · Guacamole · ntopng · Greenbone/OpenVAS · self-hosted Headscale no third-party accounts required to run a Hub KEEPMSP.io Control Plane business authority — licensing, entitlement, billing, updates its own database — never customer operational data (devices, incidents, credentials — those never leave the Hub) CURRENT — separate app, separate DB registration (one-way, one-time) heartbeat — entitlement / revocation status Hub operational secrets never transit the Control Plane — the Hub mints Spoke credentials locally Spoke's own direct heartbeat — entitlement / revocation status, not relayed through the Hub (registration eligibility capped by the Hub's own license — license_grants.max_spokes)
Figure 2. One boundary carries device/customer data (Spoke↔Hub); a second, entirely separate boundary carries only business-relationship data — and both the Hub and the Spoke cross it independently, each with their own direct heartbeat to KEEPMSP.io. The two boundaries are never merged.
Purpose
Establish what KEEP physically is — one product, deployed twice, in two roles, with a clean data-ownership split.
Major components
Client Devices, Spoke, the Hub App, Undercroft (Hub-local Postgres), the Hub's self-contained service stack, and the external KEEPMSP.io Control Plane.
Relationships
Spoke always initiates its tunnel to the Hub; the Hub waits and admits. The Hub is the sole operational authority — device data, incidents, and credentials never leave it. KEEPMSP.io is the business authority only — licensing, entitlement, billing — and structurally never stores customer operational data. Separately, both the Hub and the Spoke talk directly to KEEPMSP.io: the Hub does a one-time registration plus an ongoing two-way heartbeat; the Spoke does its own direct two-way heartbeat, not relayed through the Hub. A Spoke's eligibility to register at all is capped by the Hub's own account-level license grant, but its ongoing heartbeat/entitlement status is then checked individually. A Solo deployment is simply a Hub with zero Spokes.
Why the site
The single fact every visitor needs first: vendor-agnostic, one codebase, and data sovereignty by architecture, not by promise.
Corrected 2026-08-15 — real gap found while fixing a layout bug

The Spoke's own direct Control Plane connection was missing from this diagram entirely

This diagram originally showed only Hub↔Control Plane, with a line labeled "license grant / deployment token" that turned out, on direct code inspection, not to represent anything that actually happens on that connection — the deployment token is delivered out-of-band, before the Hub's first registration call, not pushed back over it. Two real, separate things were missing: the Hub's ongoing heartbeat (distinct from its one-time registration, verified against control-plane/app/api/v1/heartbeat/route.ts), and the Spoke's own independent heartbeat directly to KEEPMSP.io (verified against spoke/heartbeat.js and control-plane/app/api/spoke/heartbeat/route.ts — not relayed through the Hub, contrary to how this diagram, and hub-spoke.md's own "What's Not Yet Built" list, previously implied). Both are now drawn.

§3 Merlin Architecture

KEEP → Merlin Governance → Merlin Narrative Layer → Future Merlin. Each layer sits strictly on top of the one below without replacing it. Verified against KEEP_PRODUCT_STRATEGY_V1.md §4 (layers 1–3, exact terms "KEEP," "Merlin Governance," "Merlin Narrative Layer") and merlin.md §13/§14/§17 (Future Merlin — a synthesis of three separate future-only sections, not a single named layer in the source).

KEEP — the deterministic platform monitoring, detection, incidents, compliance, reporting — fully functional with zero AI dependency ships complete; this is what the product actually sells CURRENT Merlin Governance — governance, audit & policy layer Rule Boundary, Authorization Evaluation, Standing Policy, audit — see Figure 1 ships free with every install — foundational plumbing, not a paid feature CURRENT Merlin Narrative Layer — optional AI layer V1 scope: Device Diagnosis · Incident Coordination · Onboarding Scan Analysis KEEP-managed provider by default — BYOL available at the same price CURRENT — removable without breaking governance Future Merlin cinematic installer theme (§13) behavioral risk & silent escalation (§14) multi-provider / offline model support (§17) FUTURE — explicitly not V1 extends the layer below — never bypasses Core's governance boundary
Figure 3. KEEP works completely with Merlin Governance alone — no AI required. Merlin Narrative Layer can be removed without touching governance. Future Merlin is drawn separately because none of it is committed for Version 1.
Purpose
Establish what Merlin is — a layered extension of a complete, standalone platform, not an AI feature bolted onto a shell.
Major components
KEEP (deterministic platform), Merlin Governance (governance/audit/policy, free), Merlin Narrative Layer (optional AI layer, KEEP-managed default / BYOL), Future Merlin (cinematic install, behavioral risk research, multi-provider/offline).
Relationships
Each layer sits strictly on top of the one below without replacing it — KEEP functions with Core alone; Intelligence is removable; Future Merlin extends Core's governance rather than bypassing it.
Why the site
Directly supports the locked product-philosophy line "Merlin enhances KEEP, it isn't a separate product" — shows a prospect they're buying a complete deterministic platform first, AI second.

§4 Incident & Signal Intelligence

Condition Detected on a specific device two independent classifications — neither implies the other Severity → Color single source of truth: severity.ts never assigned directly elsewhere CURRENT Condition Type → Flash DEVICE_UNREACHABLE · UPS_ON_BATTERY · UPS_BATTERY TEMPERATURE · ROGUE_DEVICE_DETECTED · ZERO_DAY_THREAT TEMPERATURE_ANOMALY · MASS_DATA_INACCESSIBILITY · ENVIRONMENT_MISMATCH — only these nine flash CURRENT — HIGH_RISK vulns: solid, no flash SLA Category Operational Emergency — minutes (device down, UPS, temperature) clock starts on first response (double-click) SLA Category Security / Compliance — hours to weeks (vulnerability, AV, patch) per-client, signed at onboarding Compound Risk 2+ open incidents, distinct condition types, same device elevated above either condition alone — not additive, qualitative e.g. PATCH_MISSING + AV_STALE → "unpatched and blind" CURRENT — +12pt health-score penalty per compound device
Figure 4. Color and flash are deliberately decoupled — a HIGH_RISK vulnerability is just as severe as an unreachable device, but only the unreachable device demands the technician's eyes right now.
Purpose
Show KEEP's "evidence, not assertions" philosophy operating on ordinary day-to-day monitoring data.
Major components
Condition detection; Severity (color); Flash (urgency, condition-type driven); the two SLA categories (Operational Emergency vs. Security/Compliance); Compound Risk.
Relationships
Severity and flash are independent axes — one never implies the other. SLA category determines the response-time contract, signed per client. Two or more distinct conditions on one device escalate qualitatively, not by simple addition.
Why the site
The plainest demonstration of the product's daily value — a rules-driven, explainable signal model, not a black box.

§5 Root of Trust / Enrollment

KEEP Trust the joining device is genuine KEEP hardware/software embedded manufacturer identity — certificate or equivalent root of trust FUTURE — not built, no mechanism exists yet Network Trust the Director's own authenticated access to the customer's LAN independent of KEEP's control plane — a statement about the customer's network CURRENT — already how this works Enrollment Authorization the Director deliberately opens the admission window today: issuing a deployment token is itself the authorization act CURRENT, in substance all three independently required — none substitutes for another Hub admits the Spoke issues operational credentials — Headscale key, ingest token, mesh credentials, mTLS client cert CURRENT — bundled in one signed token today Today, one token issuance action satisfies Network Trust + Enrollment Authorization together. KEEP Trust remains unbuilt — an impostor device is not yet cryptographically excluded. Named honestly, not implied solved.
Figure 5. Three independently-answered questions, not one. Naming KEEP Trust as unbuilt is deliberate — the honesty is more credible than implying a finished mechanism.
Purpose
Make KEEP's Spoke-enrollment security posture legible and checkable, not just asserted.
Major components
KEEP Trust (device authenticity — Future, unbuilt), Network Trust (Director's own LAN access — Current), Enrollment Authorization (Director deliberately opens the window — Current); the Hub's credential-issuance step they all gate.
Relationships
All three are independently required before the Hub issues Spoke operational credentials — none substitutes for another. Today, one action (token issuance) happens to satisfy two of the three at once; the third has no mechanism yet.
Why the site
Answers "how do I know an impostor device can't join my network" with an actual decision model — and naming what's still unbuilt is more convincing than a blanket security assurance would be.

§6 Authentication & Sign-In

KEEP supports three deployment authentication methods — a KEEP-native local account, Active Directory/LDAP, and generic OIDC/SSO — plus exactly where multi-factor authentication does and doesn't apply. A fourth, non-customer-facing development fallback exists in the code and is shown here for completeness, clearly separated from the three real options.

Tech Attempts Sign-In evaluated per tech, not per deployment the three supported deployment methods — OIDC/SSO is a separate, parallel path, reached only via its own sign-in button Local Account bcrypt against msp_techs.password_hash ① checked first for this tech CURRENT — Session 95 Active Directory / LDAP bind via ldapts — any LDAP-speaking directory ② checked next, if a directory server is set CURRENT — Session 95 Development/Test Only no password hash set, no directory configured not a deployment authentication option OIDC / SSO Entra ID, Google Workspace, Okta, JumpCloud, and similar separate NextAuth provider CURRENT — Sessions 94-95 Unrecognized/Inactive → Pending authentication alone never activates the account Director/Senior Technician approval required CURRENT — Session 94 MFA Gate TOTP + recovery codes local accounts only CURRENT — T18 Hit 2 known, active account the three supported paths, plus the dev-only fallback, reach the same session — MFA is the only difference between them Session Established authentication only — see Figure 7 for authorization continues to Figure 7 — a session alone grants no KEEP authority
Figure 6. Three supported deployment methods, plus the OIDC/SSO pending-approval gate — and multi-factor authentication applies to exactly one of the three. The dashed, visually separated fourth box is a development-only fallback, not a deployment authentication option. Ends at session establishment; what a signed-in session can actually do is a separate question, answered in Figure 7.
Purpose
Make KEEP's own sign-in mechanics legible — which of the three supported methods a tech actually authenticates through, exactly where MFA does and doesn't apply, and where OIDC/SSO's pending-approval gate sits in that flow.
Major components
Local Account (bcrypt), Active Directory/LDAP (via ldapts), OIDC/SSO (a separate NextAuth provider) with its own pending/inactive gate for an unrecognized or not-yet-approved email; the MFA Gate hung only off the Local Account path. A development-only fallback also exists in the code (accepts any password when neither Local nor AD/LDAP applies) — drawn small, dashed, and visually separated from the three supported methods, never presented as a customer-facing deployment option.
Relationships
Local and LDAP are evaluated in that priority order for a given tech — the first that applies wins; the development-only fallback is what happens if neither does, shown here only because an existing finding on this page (below) depends on it being visible, not as a fourth peer choice. OIDC sits outside this chain entirely, reached only via its own sign-in button, and is the only path with its own denial branch (an unrecognized or inactive email is refused, not signed in). Every successful path converges on the same session; MFA is the only structural difference among the three supported methods, and it applies to Local accounts alone. Session establishment is authentication only — it says nothing about what that session can do. That's authorization, a separate mechanism covered in Figure 7.
Why the site
Answers a security-evaluating reader's actual question — "what happens when I sign in, and is MFA actually enforced" — with the real branching logic, not just a feature-list mention.

Backend selection is per tech, not per deployment

A Director can hand one contractor a local password inside an otherwise AD-integrated MSP — password_hash is checked per msp_techs row, not as a single deployment-wide switch. (Source: DECISIONS.md, "Auth Provider Abstraction.")

The installer doesn't offer Local as an install-time choice yet

chooser.js and install-pyx.sh's network-type question still only offers ldap, oidc, or skip — skip maps to the insecure development-only fallback shown above (dashed, not one of the three supported methods), meaning a real deployment can end up on it by installer choice, not just by leaving env vars unset in dev. Wiring Local into the installer scripts is separate, unbuilt work.

§7 Authorization: Roles & Permissions

What a signed-in session can actually do inside KEEP — a separate question from Figure 6's "how did this session get established," answered by an additive, union-based role model rather than a single rank.

Signed-In Technician already authenticated — see Figure 6 AD / LDAP Group Mapping AD/LDAP group membership → KEEP roles re-evaluated on every sign-in CURRENT — Additive RBAC Manually Assigned by a Director or Senior Technician unaffected by AD/LDAP-driven changes CURRENT — Additive RBAC both sources can apply to the same technician at once generic OIDC/SSO authenticates identity only — no OIDC group or claim maps to a KEEP role This Technician's Assigned Roles (example) a technician may hold any number of roles from either group, at once Senior Technician predefined Onboarding Coordinator composable Effective Permissions the union of everything every assigned role grants no deny-list, no conflicting-role restriction in this version PREDEFINED ROLES each is its own role, like any other — not a ranked ladder Technician Senior Technician Director COMPOSABLE ROLES assignable standalone or alongside any other role Remote-Access Specialist Onboarding Coordinator Compliance Reviewer Security Administrator
Figure 7. Effective access is the union of every role a technician holds, from either source — never a single rank, never a deny-list.
Purpose
Make KEEP's authorization model legible once a session already exists — which roles a technician can hold, where those roles come from, and how they combine into what that technician can actually do.
Major components
Two independent role-assignment sources (AD/LDAP group mapping, manual assignment); three predefined roles (Technician, Senior Technician, Director); four composable roles (Remote-Access Specialist, Onboarding Coordinator, Compliance Reviewer, Security Administrator); the union operation that turns an assigned-role set into effective permissions.
Relationships
A technician's assigned roles are the combination of whatever AD/LDAP groups currently map to them and whatever a Director or Senior Technician assigned by hand — both can apply at once, independently, and neither source erases the other. Generic OIDC/SSO is deliberately absent from this pair: it authenticates identity only, and no OIDC group or claim currently maps to a KEEP role. Effective permissions are the union of everything every assigned role grants; there is no deny-list and no conflicting-role restriction in this version, so holding an additional role only ever adds access. The predefined and composable roles are drawn as equal, independent options specifically to avoid implying a ranked ladder is how the system decides access — permissions are the actual primitive.
Why the site
Answers the natural follow-on to Figure 6 — "OK, I'm signed in, so what can I actually do, and who decides that" — with the real model, not just "roles exist."

Live-verified end-to-end, not just designed

Confirmed against a disposable KEEP deployment, not only reviewed in source: role assignment through the real administrative screen, the permission union it produces, AD/LDAP-group-driven role mapping and revocation on re-sign-in, and coexistence between a manually assigned role and a directory-derived one all behaved exactly as described above.