Context
Following a review of the AI automation surface (Claude Code skills/agents, theeos-spec navigator) and the in-product AI runtime, the question was raised: should
Encore OS adopt LangChain, LangGraph, LangSmith, or Agent OS?
The review found that the problems these tools solve are already solved in our
stack, and that adopting them would duplicate working infrastructure while widening a
HIPAA-regulated dependency surface.
What already exists (the reason most of this is redundant)
ADR-023
already dispositioned the broader agent-harness and eval-tooling question (deferring
Mastra and any product-agent harness; recording that Promptfoo + self-hosted Langfuse
already shipped). It did not name the LangChain family or Agent OS. This ADR closes
that gap with an explicit, durable disposition so the question does not recur.
Options Considered
Option A: Adopt LangChain / LangGraph as the orchestration framework
- How it works: wrap LLM calls and agent loops in LangChain abstractions; use LangGraph for stateful graph orchestration.
- Pros: large ecosystem; off-the-shelf agent/graph primitives.
- Cons: duplicates the
AIProviderseam; heavy, fast-churning abstraction; Python-first with JS as the second-class citizen (our edge runtime is Deno, see ADR-011); adds a large new dependency inside the HIPAA boundary. - Why not chosen: negative ROI — it replaces a small abstraction we fully control with a large one we do not.
Option B: Adopt LangSmith for observability/evals
- How it works: route traces, datasets, and scores to LangSmith.
- Pros: integrated eval tooling.
- Cons: redundant with the self-hosted Langfuse stack already shipped (PR #815); hosted-by-default, which is the wrong posture for PHI/residency.
- Why not chosen: Langfuse already covers tracing/datasets/experiments/scores, and self-hosting keeps trace storage on our box.
Option C: Adopt Agent OS
- How it works: either (a) LangChain’s hosted agent-deployment runtime, or (b) buildermethods’ spec-driven dev-workflow system for coding agents.
- Pros: turnkey agent deployment (a); ready-made spec workflow (b).
- Cons: (a) is a Python-centric hosted runtime that mismatches our
Supabase/Deno/Vercel stack and has no product agent to host; (b) duplicates
eos-spec+ skills/commands and lacks our regulated-core gates (compliance-reviewer, RLS, PHI lanes). - Why not chosen: architectural mismatch or duplication in both readings.
Option D: Keep extending the provider-agnostic seam ✓ (Chosen)
- How it works: treat the
AIProviderseam (PF-111) as the platform AI substrate; add new AI capability by extending the seam and the existing eval/observability layers, not by adopting an orchestration framework. - Pros: no new HIPAA dependency surface; full control of the abstraction; preserves per-module/per-lane model routing and BAA boundaries; consistent with ADR-023/ADR-024.
- Cons: we own the orchestration code (e.g. the agentic tool-loop) rather than outsourcing it.
- Why chosen: lowest risk, no duplication, and the “cons” are small and already mitigated by keeping that code small and tested.
Decision
We do not adopt LangChain, LangGraph, LangSmith, or Agent OS.- LangChain — not adopted. Redundant with the
AIProviderseam (PF-111); heavy, fast-churning abstraction; Python-first / Deno-second; widens the HIPAA dependency surface. - LangGraph — not adopted as a framework. Durable / branching orchestration is
already served by pgmq (
workflow-executor-worker) plus the ADR-024 execution seam. If a concrete, funded product agent ever needs in-process stateful orchestration, prefer a lightweight in-stack TS state machine over the framework — seeded by the now-extracted, unit-tested agentic tool-loop atsupabase/functions/_shared/ai/agentic-loop.ts. - LangSmith — not adopted. Redundant with self-hosted Langfuse (L2, PR #815); self-hosting is a PHI/residency advantage.
- Agent OS — not adopted (both meanings). (a) LangChain’s hosted agent-deployment
runtime: architectural mismatch and no product agent to host (ties to the ADR-023
harness deferral); (b) buildermethods’ spec-driven dev workflow: duplicates
eos-spec- skills/commands and lacks the regulated-core gates.
Principle enshrined
The provider-agnosticAIProvider seam is the platform’s AI substrate. New AI
capabilities extend the seam (and the existing L1/L2/L3 eval-observability layers)
rather than adopt an orchestration framework. Prompts stay in the DB-driven system
(pf_ai_skills), not in a third-party prompt-management product, to keep the seam — and
the BAA/PHI boundary — authoritative.
Revisit trigger: a concrete, funded product-agent feature (the same gate ADR-023
sets for Mastra/Claude Agent SDK). At that point, re-evaluate LangGraph specifically
against a hand-rolled state machine; the rest of this disposition stands regardless.
Consequences
Positive
- No new always-on dependency inside the HIPAA boundary; the model/gateway/streaming and eval/observability layers already in place keep their single owner.
- The decision is durable and discoverable, so the “should we use LangChain?” question stops recurring.
- The agentic tool-loop is now isolated and tested, making any future state-machine evolution cheap without a framework.
Negative
- We own the orchestration code (the agentic loop) rather than outsourcing it to a framework.
Mitigations
- The orchestration surface is deliberately small and now unit-tested
(
agentic-loop.test.ts). - The revisit trigger above keeps the door open if a real product agent ever justifies reopening LangGraph specifically.
Revision 2026-06-24 — Orchestration backbone for the Agentic Workspace (revisit trigger fired)
Status of this revision: Recommendation (directional), pending a time-boxed PF-125 Phase-0 prototype — see “Prototype gate” below. Date: 2026-06-24 Decision Makers: Jeremy Bloom (project owner), PF Supersedes: nothing — this section is additive. The original disposition above (LangChain / LangSmith / Agent OS — not adopted) stands unchanged.Context — the revisit trigger fired
The original ADR-026 set a single revisit trigger: “a concrete, funded product-agent feature” (line 115-117), at which point LangGraph specifically would be re-evaluated against a hand-rolled state machine. That trigger has now fired: the Encore Agentic Workspace program (docs/superpowers/specs/2026-06-24-encore-agentic-workspace-roadmap-design.md) is the concrete, funded product-agent feature, and its Phase-0 spike (roadmap §4) requires a revised ADR-026 that scores the orchestration build-vs-adopt question against a five-criterion rubric: (a) PHI-lane enforceability, (b) checkpoint/resume fidelity for long runs, (c) BAA posture / data-residency of any adopted dependency, (d) maintenance surface & team familiarity, (e) subagent fan-out support.
This revision re-scores the question honestly under that trigger. Scoring an option is not adopting it. The capability the external options sell — durable, branching, checkpointed orchestration — already exists in-perimeter and was verified on disk during this review:
supabase/functions/workflow-executor-worker/index.ts(1311 lines) consumesworkflow_execution_queueviapgmq_read, runs batches under a per-orgworker_runningoptimistic-lock semaphore, classifies errors, writes pre/post/failure/waiting checkpoints, routes permanent failures toworkflow_dlq, and resumes via the cron-drivenfw_claim_queued_executionsfallback when the worker is down.supabase/functions/_shared/checkpointHelpers.tsprovideswritePreStepCheckpoint/writePostStepCheckpoint/writeFailureCheckpoint/writeWaitingCheckpoint/writeSkippedCheckpoint(for nodes bypassed during resume) +classifyError(transient/permanent/timeout).- 24 migrations already wire
pgmq/cron.schedule. - The ADR-024
@/platform/workflowseam is more built than previously assumed.enqueueWorkflowExecutionandgetThrottleStatus(src/platform/workflow/execution.ts), thefw-enqueue-executionedge function, anduseWorkflowEnqueue.tsall exist on disk and route throughpf_has_org_accesswith idempotency. Only ADR-024’s frontmatter still readsStatus: Proposed— that is documentation drift to reconcile, not a missing seam. - The reasoning spine is in-house and unit-tested:
supabase/functions/_shared/ai/agentic-loop.ts(MAX_LOOP_ITERATIONS = 5) already routes every call through the fail-closed PF-111 PHI lane (PHI_MODELS= cl+pm, BAA/ZDR) and already neutralizes tool results (neutralizeToolResultFn) and guards tool names (assertToolCallIsAllowedFn) before re-prompting.
max_cascade_depth, not aggregate it). Both sit on the existing seams — this is additive, not a rewrite.
Options considered (re-scored under the fired trigger)
- Option 1 — Extend in-house, bespoke: evolve
agentic-loop.tsinto a persisted run-state machine on a new, parallel pgmq + pg_cron queue/worker/checkpoint table — the literal “lightweight in-stack TS state machine” of the original disposition, taken to a fully bespoke extent off the ADR-024 seam. - Option 2 — Build on the in-perimeter backbone (chosen, gated): reuse the ADR-024
@/platform/workflowseam +workflow-executor-worker+ FW-48 checkpoints for durable run-state / checkpoint / resume / scheduling, withagentic-loop.tsas the in-house reasoning/tool layer on top. PF-125 serializes agentRun/Taskstate into the FW-48 checkpoint model — net-new schema on a proven substrate, no new external dependency in the HIPAA boundary. - Option 3 — Adopt external: a durable-execution vendor (Temporal / Inngest, self-hosted in-perimeter) and/or LangGraph (TS) as the PF-125 backbone.
Rubric scores (all three options; 1-5 per criterion, /25 total)
Reading the table. Options 1 and 2 are both fully in-perimeter and tie on the two axes that dominate this regulated context (a, c). They diverge on (d): Option 1 hand-builds a second durable executor + checkpoint table + DLQ/retry/cascade stack parallel to
workflow-executor-worker / fw_execution_steps, off the sanctioned ADR-024 seam — the largest owned maintenance surface and widest regression frontier of the set, and a direct contradiction of this ADR’s Decision D (“extend the seam”). Option 2 extends the seam, inheriting the worker’s already-tested retry/DLQ/checkpoint/cascade machinery, so it dominates Option 1 on (d) at equal (a)/(c). Option 3’s two real wins (b, e) are each ~70% already covered in-perimeter, while its costs are structural — BAA/residency (hosted egresses PHI run-state; self-hosted adds a heavy always-on stateful PHI datastore inside the HIPAA boundary — the exact dependency-surface widening this ADR rejects at lines 25/52/92), a Deno-runtime mismatch (ADR-011; Temporal/Inngest SDKs are Node-centric, LangGraph Python-first; today there is zero temporal/inngest/langgraph dependency in package.json or supabase/), and PHI-chokepoint erosion (LangGraph owns the model-call layer, duplicating/bypassing the AIProvider seam — Option A’s named harm).
Decision
The orchestration backbone for PF-125 is built on the existing in-perimeter backbone (Option 2): extend the ADR-024@/platform/workflow execution seam + the pgmq workflow-executor-worker + FW-48 checkpoints for durable run-state / checkpoint / resume / scheduling, with agentic-loop.ts as the in-house reasoning/tool layer. This is a recommendation pending the PF-125 Phase-0 prototype below.
- LangGraph / LangChain / external durable-execution vendors — not adopted as the backbone. The original disposition (lines 89-105) stands, reaffirmed under the now-fired trigger. Option 3’s marginal, partially-redundant gains do not justify a second run-state owner or a new always-on stateful dependency inside the HIPAA boundary.
- Option 2 over Option 1 because the durable substrate already exists and is tested: extending the seam beats hand-rolling a parallel executor on (d) at equal perimeter posture. Option 1 is the documented fallback — adopt it only if the prototype proves agent run-state genuinely cannot fit the FW execution/checkpoint model.
- Narrowed revisit trigger (replaces the broad “any product agent” door for orchestration): re-open Temporal (self-hosted, model-agnostic) specifically only if proven, multi-day human-in-the-loop runs with complex durable-join semantics become a measured bottleneck that pgmq +
checkpointHelpersdemonstrably cannot carry. LangGraph remains rejected regardless (it owns the model call and erodes the PHI chokepoint).
Consequences
Positive- Zero new dependency inside the HIPAA / 42-CFR-Part-2 boundary; the PF-111
AIProvider/PHI-lane and the pgmq durable executor keep their single owner. - Reuses genuinely mature durable infra (per-org semaphore, FW-48 step checkpoints, retry-policy merge, circuit breakers, DLQ,
fw_claim_queued_executionscron resume) that a framework would otherwise re-implement. - Boundary-clean: the ADR-024 seam lets CE/PM/HR enqueue durable agent runs without core-to-core imports (Constitution §1 / ADR-010).
- The §6.1 two-path PHI rule, tool-result neutralization, and fail-closed routing already live in
agentic-loop.tsand do not have to be ported into a foreign runtime.
- We own the orchestration code (PF-125 run-state, fan-out/join, resume) rather than outsourcing it.
- Agent-loop iteration/message state is in-memory today — durable resume requires net-new PF-125
Run/Taskserialization into the FW-48 model. - Subagent fan-out is greenfield:
handleCascadeBlock/max_cascade_depthare built to block deep fan-out, so governed parallel fan-out + join/aggregation must be built, and the cascade guard re-configured to permit (not DLQ) governed fan-out. - The FW queue is workflow-rule-shaped (
fw_workflow_executions,rule_id,trigger_condition); mapping free-form agent runs onto it needs a deliberate schema bridge (or a PF-125 sibling table), not a drop-in. - Ordering constraint (load-bearing): per roadmap §6, this orchestration layer (Layer 3) must land behind the Phase-1 guardrail spine (PF-27-EN-01 unified redaction, runtime injection screening, PF-30-EN-01 scoped principals off
service_role, PF-126 governance-in-the-loop, fail-closed budgets). Building durable run-state ahead of the spine would strip protective friction (roadmap §2 #1 risk: indirect injection via tool-result / inter-agent re-prompts is unaddressed today).
Status: Proposed is stale relative to the shipped enqueueWorkflowExecution / fw-enqueue-execution seam — reconcile alongside the PF-111/PF-27 frontmatter fixes.
Prototype gate (this decision is provisional until PF-125 proves it)
This is a recommendation, not a final commit, because three rubric criteria are unproven on the agent path: (b) is “high once adapted, not free,” (e) is greenfield against a guard that actively blocks fan-out, and the schema bridge is undemonstrated. Per roadmap §4 the Phase-0 spike is time-boxed to ~5 engineer-days and must clear the checklist below before the backbone is committed. If the spike fails the run-state-fit or fan-out items, fall back to Option 1 (bespoke in-house) and record that result; under no outcome does this revision adopt an external framework. Prototype checklist (all must pass):- Run-state serialization fidelity — agent
Run/Taskmessage + tool-call state round-trips through the FW-48 checkpoint model and resumes after worker crash without re-executing committed steps. - Governed subagent fan-out — re-configure the cascade guard to permit (not DLQ) governed parallel fan-out; child tasks inherit ≤ parent scope and draw budget from the parent run.
- FW-queue schema bridge — free-form agent runs map cleanly onto
fw_workflow_executions/ PF-125 sibling tables without breaking idempotency or org scoping. - Claim-check payload offloading — large PHI message/tool blobs are stored out-of-line (object store or dedicated table); checkpoints reference by id only — workflow history does not saturate on LLM payloads.
- Run/version pinning — in-flight runs pin the skill prompt version, tool registry snapshot, and risk-rule set at run start; mid-run deploys cannot alter behavior for active runs.
Revision 2026-06-25 — PF-125 Phase-1 foundation: prototype gate resolved (extend-in-house, PF-125-owned run-state on the in-perimeter pgmq/pg_cron substrate)
Status of this revision: Accepted (for the PF-125 Phase-1 flag-OFF foundation). Resolves the Revision-2 “Prototype gate” for Phase 1. Date: 2026-06-25 Decision Makers: Jeremy Bloom (project owner), PF Supersedes: nothing — additive. The original disposition (LangChain / LangSmith / Agent OS — not adopted) and Revision 2’s rejection of an external durable-execution backbone both stand, reaffirmed. This revision only resolves which in-perimeter shape PF-125 takes.What the Phase-1 build determined
Revision 2 recommended Option 2 (build on the in-perimeter backbone) but flagged it provisional behind a five-item prototype checklist, naming Option 1 (extend in-house) as “the documented fallback — adopt it only if the prototype proves agent run-state genuinely cannot fit the FW execution/checkpoint model.” Authoring PF-125 against the FW model answered exactly that question:- Run/Task state does not fit
fw_workflow_executions. That table is workflow-rule-shaped (rule_id,trigger_condition) — built for declarative FW rules, not free-form, message/tool-call-bearing agent runs. Revision 2 itself listed this as a load-bearing Negative (“mapping free-form agent runs onto it needs a deliberate schema bridge or a PF-125 sibling table”). PF-125’s spec landscape scan confirmedpf_agent_runs/pf_agent_tasks/pf_agent_run_checkpoints/pf_agent_run_eventsare net-new with no table collision. So PF-125 owns its run-state schema (the sibling-table mechanism of Option 1) rather than bending agent runs onto the FW execution rows. - But the durable substrate is reused, not re-invented. This is not Option 1’s “second bespoke durable executor parallel to
workflow-executor-worker.” The Phase 3-4 background/scheduled-run worker (spec FR-17) runs on the same proven pgmq +pg_cronpattern and thecheckpointHelpersdiscipline;agentic-loop.tsremains the in-house reasoning/tool layer (PF-72), wrapped — not replaced — by the run-state machine. Zero new dependency enters the HIPAA boundary.
Decision
The PF-125 orchestration backbone is built in-house: PF-125 owns theRun/Task run-state, checkpoint, and event tables and three governed SECURITY DEFINER transition RPCs (pf_agent_run_advance / pf_agent_run_checkpoint / pf_agent_run_resume); it wraps runAgenticLoop as a durable, resumable, checkpointed run-state machine; and the Phase 3-4 background worker reuses the existing pgmq + pg_cron substrate. No external orchestration framework or durable-execution vendor is adopted.
- Scope of this acceptance = the PF-125 Phase-1 flag-OFF foundation. Everything ships additive and behind
pf.agents.interactive_tools_enabled(PF-45, defaultfalse) with the spine check unconditional. The write/PHI/budget seams (PF-30-EN-01 / PF-27-EN-01 / PF-111-EN-01) are integrated via documented fail-closed shims until those specs land; the production flag-flip is a separate human gate (PF-125 compliance signoff C-01..C-08). - Prototype-checklist disposition (Rev-2 items 1–5): item 1 (run-state serialization round-trip) and item 5 (run/version pinning) are delivered by the Phase-1 checkpoint model + run-pinned snapshot; items 2 (governed subagent fan-out), 3 (FW-queue bridge — now moot: PF-125 owns sibling tables), and 4 (claim-check payload offloading) are Phase 3-4 work behind the production gate, not the flag-OFF foundation.
- Narrowed revisit trigger stands unchanged: re-open Temporal (self-hosted, model-agnostic) only if proven multi-day human-in-the-loop runs with complex durable-join semantics become a measured bottleneck pgmq +
checkpointHelpersdemonstrably cannot carry. LangGraph remains rejected regardless (it owns the model call and erodes the PF-111 PHI chokepoint).
Consequences
- Positive: zero new HIPAA-boundary dependency (reaffirms the whole ADR); the run-state schema fits agent runs natively instead of straining the FW rule model; the proven pgmq/
pg_cron/checkpointHelperssubstrate is reused for Phase 3-4;agentic-loop.tsPHI-lane/neutralizer/allowlist guards are preserved, not ported into a foreign runtime. - Negative (named honestly): PF-125 owns its run-state machine, fan-out/join, and resume code (the original Option-D con). Run-state, fan-out, and the background worker are net-new owned surface — mitigated by reusing the substrate and keeping the reasoning layer unchanged.
Related Documents
- ADR-023 Agent Harness, Skills & Eval-Tooling Direction — broader harness/eval disposition
- ADR-024
@/platform/workflowExecution Seam — durable cross-core execution - ADR-010 Core–PF Dependency Boundary
- ADR-011 Edge Functions on Deno
- Eval & Observability
src/platform/ai/README.md— PF-111 AI integration layer & model routing