ADR-0017: V6 enterprise governance model¶
- Status: Accepted
- Date: 2026-09-06
- Deciders: Jian (product owner)
Context¶
V6 (KAN-1122–1126) requires SSO/SCIM, RBAC roles (Creator/Operator/Auditor/Tool Manager), PII
scrubbing/egress policy rules, SIEM-exportable audit logs, and per-run cost circuit breakers — five
one-line [ROADMAP] cards today, none scoped in depth. PLAN.md's own sequencing rationale is that
none of this is meaningful "in a single-user local tool" — V6 exists to satisfy IT/security review
of a shared system, which only exists once V5 ships. The operator has confirmed strict
sequencing (V5 fully before V6 begins), so this ADR builds entirely on V5's now-decided
foundations: Postgres + Drizzle + RLS multi-tenancy (ADR-0014) and Better Auth's session/
organization/SSO-plugin account model (ADR-0015). This ADR is a scoping decision, in the same
"firm recommendation plus explicitly flagged open questions" style as ADR-0011/0012, not an
implementation plan.
Decision¶
1. SSO/SCIM: activate Better Auth's already-adopted sso plugin; SCIM is a separate, unscoped gap.¶
Firm recommendation. ADR-0015 adopted Better Auth specifically so its sso plugin (OIDC/SAML
as a relying party) would be available, dormant, until V6. V6 turns it on: a workspace admin
configures their own identity provider (Okta, Azure AD, Google Workspace, etc.) as that workspace's
sign-in source, scoped per-workspace rather than globally — a workspace that hasn't configured SSO
keeps using V5's email+password/GitHub OAuth unchanged.
Open question, not resolved here: SCIM (automated user provisioning/deprovisioning driven by the customer's IdP) is a distinct protocol Better Auth does not implement out of the box as of today. This is a real, unscoped gap — V6 implementation work needs its own research pass on SCIM specifically (a community plugin, a hand-rolled SCIM endpoint, or descoping automated provisioning from a first V6 cut in favor of manual admin-driven user management) rather than assuming the SSO plugin choice already covers it.
2. RBAC: four roles as a permission matrix over existing routes, built on Better Auth's organization/access-control primitive — not a new authorization engine.¶
Firm recommendation. Better Auth's organization plugin (adopted in ADR-0015 for workspace/
member modeling) ships an access-control primitive that roles attach to. V6 defines Creator/
Operator/Auditor/Tool Manager as a fixed permission matrix over the API routes packages/server
already exposes (spec read/write, run start/approve, tool config read/write) rather than inventing
a general-purpose policy language. Concretely: a Compliance Auditor role denies every mutating
route at the same auth middleware layer ADR-0015 already established for resolving the current
user and workspace, while allowing read-only routes (spec read, run history, audit log read) —
this is the acceptance criterion SLICES.md already names for this feature ("that user can view an
audit log entry for a real run but cannot edit or run agents").
Open question: whether four fixed roles remain sufficient once real customers use this, or whether demand emerges for custom/composable roles — deferred until there's evidence of the need, consistent with this project's general anti-premature-infrastructure stance.
3. PII scrubbing/egress: policy middleware around the existing tool-call path, reusing the existing guardrail pause mechanism — not a new blocking protocol.¶
Firm recommendation. Implemented as middleware wrapping the existing HTTP tool-call path
(packages/engine/src/http-tool.ts, also vendored per ADR-0010 into every exported project) — a
workspace-configurable policy (rule-based: block a disallowed HTTP verb, block a destination domain
not on an allowlist, redact a PII-shaped pattern from a request/response) evaluated before a tool
call is dispatched. A rule violation reuses the existing requires_approval/fallback_action
pause mechanism from ADR-0009 (the same yield/resume seam AgentRun.start/resume already
provides) rather than inventing a second, parallel blocking protocol — exactly the kind of reuse
ADR-0011 already validated this seam for when it extended it to sub-agent delegation.
Open question: whether policy rules are configured via a UI builder or as YAML/JSON policy
files (mirroring AgentSpec's own YAML-first, hand-authorable ethos) — a real implementation
choice not resolved here, though the YAML-first option is the more consistent-with-this-project's-
conventions starting point.
4. Audit logs: a new audit_events table, populated as a side effect of RBAC/PII enforcement points already being built — not a separately instrumented pass.¶
Firm recommendation. A new audit_events table (workspace_id, actor, action, resource,
timestamp, structured JSON detail), following ADR-0014's shared-schema-plus-RLS pattern like
every other tenant-scoped table. Entries are written at the exact points RBAC's middleware (item 2)
and the PII/egress tool-call gate (item 3) already intercept requests — audit logging falls out of
enforcement work V6 is already doing, rather than requiring a separate instrumentation pass across
the whole codebase. "SIEM-exportable" means the JSON shape is documented, versioned, and stable,
plus a simple export endpoint or webhook — not a commitment to any specific SIEM vendor's
integration format.
Open question: exact retention and immutability guarantee — genuine WORM (write-once-read-many)
storage, or an application-level append-only convention enforced by Postgres permissions (e.g. no
UPDATE/DELETE grant on the table for the application role) — not decided here.
5. Cost circuit breakers: protect the operator's compute, not just the customer's BYOK spend.¶
Firm recommendation. Because V5 is BYOK, a workspace's own dollar cost is already the
workspace's own concern, not the operator's — the framing SLICES.md's original one-line sketch
implies ("per-run cost/token circuit breakers... department-level cost attribution") is only half
the picture on a self-hosted homelab deployment. The other half is protecting the operator's own
compute (a homelab k3s cluster, not elastically-scaling cloud infrastructure, per ADR-0013) from
abusive or runaway workspace usage — run frequency/duration limits matter here regardless of whose
API key is being billed. Token/cost estimation per run (from whatever usage metadata the Vercel AI
SDK response already exposes) is recorded in runs (ADR-0014), with a configurable per-workspace
threshold that halts further runs once crossed — surfaced via the same fail-visibly convention
(ADR-0004) as any other guardrail, not a silent throttle.
Open question: the exact threshold model (hard stop vs. rate-limited degradation) and whether department-level attribution (implying sub-workspace grouping) is real V6-launch scope or a later refinement — SLICES.md's original phrasing names it, but the data model for "department" within a workspace is not designed here.
Alternatives considered¶
| Option | Why not |
|---|---|
| Self-host Keycloak or Authentik as this app's own IdP for V6 SSO | Conflates being an IdP with accepting SSO from a customer's IdP — the same distinction ADR-0015 already drew; this app remains the relying party, not the identity provider, for the customer's own users. |
| A generic policy engine (OPA/Rego) for RBAC and PII/egress instead of hand-rolled middleware | Disproportionate infrastructure for four fixed roles and a modest rule set; revisit only if the rule surface grows past what a readable middleware chain can express, which nothing today indicates. |
| A dedicated eval/audit-log service instead of a Postgres table | No identified scale or query pattern justifies a separate system yet; a well-modeled table with RLS already gives per-workspace isolation and fits the existing data layer without new infrastructure. |
| Building SCIM support as part of this ADR's firm recommendations | No existing library coverage (unlike SSO's OIDC/SAML, which Better Auth already implements) and no concrete design has been done — honestly flagging it as an open gap is more useful than a confident-sounding but ungrounded proposal. |
Consequences¶
- V6 introduces almost no new infrastructure of its own — it is new middleware and new tables layered entirely on V5's Postgres/Better Auth foundation (ADR-0014, ADR-0015), which is precisely the "nothing to review until a shared system exists" sequencing logic PLAN.md already gave for putting V6 after V5, now made concrete rather than asserted.
- SCIM remains a real, unscoped implementation gap that V6 work must budget explicit research time for, not assume is solved by the SSO plugin choice.
- RBAC, PII/egress, and audit logging share one enforcement point (the auth middleware and the tool-call gate) rather than three independent subsystems — a deliberate design choice that keeps V6 additive to V5's existing request-handling path rather than a parallel structure bolted alongside it.
Open questions for V6 implementation to revisit¶
- SCIM protocol implementation approach (library, hand-rolled, or descoped from a first cut).
- Whether four fixed RBAC roles are sufficient at launch or need to become composable.
- PII/egress policy authoring surface (UI builder vs. YAML/JSON policy files).
- Audit log retention/immutability mechanism.
- The cost-circuit-breaker threshold model and whether department-level attribution is in scope for V6's first cut or a later refinement.