4.4 KiB
Memind Workflow Orchestrator Boundary
Decision
The Orchestrator starts in the Memind repository but is designed as an independently deployable bounded context. Source colocation does not authorize in-process execution inside Portal.
The stable boundary is:
Memind Control Plane
-> versioned Orchestrator API / events
Workflow Orchestrator
-> versioned Executor Gateway
Executor adapters
-> Goosed / Aider / OpenHands
LangGraph remains an internal workflow engine implementation. Memind must not depend on LangGraph graph, checkpoint, command, or interrupt types.
Ownership
| Data | Owner |
|---|---|
| User, authorization, billing, product run | Memind |
| Workflow node state, checkpoint, interrupt | Orchestrator |
| Goosed session | Goosed plus Session Broker mapping |
| Executor job | Executor Gateway / executor adapter |
| Workspace and deliverable | Workspace / Artifact / MindSpace services |
| User-visible progress and audit | Memind run-event projection |
The Orchestrator must not read or write Memind user, billing, capability, or provider-key tables. A shared PostgreSQL instance is acceptable during the single-host phase, but the Orchestrator must use its own database and database credentials.
Runtime modes
memindadm owns the versioned routing configuration:
| Mode | Behavior |
|---|---|
off |
Native Agent Run only |
shadow |
Native executes; LangGraph observes and compares decisions |
canary |
Explicit users and deterministic percentage may use LangGraph |
active |
Workflow-allowlisted tasks use the primary engine |
All modes support an explicit Native fallback. The environment kill switch
MEMIND_ORCHESTRATOR_KILL_SWITCH=1 overrides admin configuration and forces
Native selection.
The initial workflow allowlist contains only code-run-v1. Ordinary chat and
existing Goosed session traffic remain outside the Orchestrator path.
Phase 2 implements only the off and shadow execution semantics. Although
Canary and Active can be configured and evaluated by the control plane, the
Portal does not hand execution ownership to LangGraph yet. This prevents an
administrative configuration mistake from creating two task executors.
Protocol
The framework-neutral contracts are:
orchestrator-run-v1orchestrator-event-v1
The implemented internal API is:
POST /v1/runs
GET /v1/runs/:id
POST /v1/runs/:id/resume
POST /v1/runs/:id/cancel
GET /v1/runs/:id/events?after=<cursor>
External state changes must use an idempotency key derived from run, graph version, node, and attempt. Graph state stores resource references and decisions, not API keys, large logs, binary artifacts, or absolute production paths.
The Phase 2 graph has three deterministic nodes:
validate_run -> build_plan -> finalize_run
It requires policy.executionMode=observe-only and
policy.sideEffectsAllowed=false. It projects the Native executor boundary but
cannot call Goosed, Aider, OpenHands, Tool Gateway, or the filesystem.
Failure isolation
Portal invokes Shadow only after the product run and its queued event have
been committed. The observation is scheduled without awaiting it. A timeout or
failure:
- cannot reject or delay
createRun; - cannot mutate the Native run status;
- is projected as
workflow_shadow_failed; - remains removable by deleting the observer wiring and changing only the service URL boundary.
Successful observations are projected as workflow_shadow_completed; graph
checkpoints stay in the Orchestrator-owned PostgreSQL database.
Both terminal projection events contain bounded observation latency. The Memind-owned observability service aggregates those events and may join them to the product run status. Only per-run detail calls cross the service boundary to read LangGraph checkpoint state and node events.
Deployment evolution
- Local native Orchestrator process with an explicit MemorySaver for debugging.
- Colima Compose with an isolated PostgreSQL checkpoint database.
- Approved server-side shadow service; no production task claim.
- User-allowlisted code-run canary with Native rollback.
- Isolated Aider/OpenHands executor workers.
- Move the same service contract to Linux or Kubernetes when horizontal scaling or independent ownership becomes necessary.
The Orchestrator must not share the Goosed Compose lifecycle or mount the Docker socket. It calls MindSpace through its service API and calls Goosed through the existing proxy boundary.