Packages & architecture
Agent Flow is a pnpm monorepo of five packages laid out along the compilation chain:
.flow source
│
▼
@dynamic-workflow/lang Langium grammar + parsing (lex/parse → AST)
│
▼
@dynamic-workflow/compiler semantic + type checking → Flow IR → codegen (restricted JS)
│
▼
@dynamic-workflow/sandbox subprocess + isolated-vm, loads and runs the artifact
│
▼
@dynamic-workflow/runtime runtime semantics: events, AgentRuntime adapter, FakeAgentRuntime
│
▼
@dynamic-workflow/cli flow check / compile / run
Package list
| Package | Responsibility | Key files |
|---|---|---|
@dynamic-workflow/lang | grammar and parser (Langium) | src/language/agent-flow.langium |
@dynamic-workflow/compiler | checkFlow (diagnostics) and compileFlow (IR + JS codegen) | src/checker.ts, src/codegen.ts |
@dynamic-workflow/runtime | runtime semantics: FlowEventSink, the AgentRuntime interface and FakeAgentRuntime, typed errors | src/fake-agent.ts etc. |
@dynamic-workflow/sandbox | sandbox execution: subprocess → isolated-vm → trusted bootstrap ($runtime ABI) | e2e tests |
@dynamic-workflow/cli | command line: check / compile / run | src/main.ts |
Every hop of the chain
- Parse (language):
.flow→ lexing/parsing (Langium) → syntax AST - Check (compiler.checker): semantic diagnostics (scopes/resources/ dependencies) + type diagnostics (inference/assignability/expect), merged
- Compile (compiler.codegen): syntax AST → Flow IR (with metadata
like
StageIR.dependencies) → ESTree → restricted JavaScript - Sandbox (sandbox): a subprocess hosts an isolated-vm running the
trusted bootstrap; workflow glue reaches the host only through
$host.invoke(op, payload) - Runtime (runtime): deterministic structures execute inside the
bootstrap;
agentcalls forward to host-side HostOps (the budget / concurrency / resolution / narrowing / validation / repair / retry pipeline); events stream through FlowEventSink
Plugging in your own agent system
Exactly one interface stands between language and model: AgentRuntime. As a host you provide:
- resolveAgent(resourceId) — map the logical id of
use agent "my-assistant"onto a concrete implementation - resolveTeam(teamId) — return the team (
mainplus members) forteam.main/team.member(...)routing and membership validation - Invocation — receive the task descriptor (target, task, input, the post-intersection tool set, write policy, OutputContract) and return a structured output; contract validation and the repair loop belong to the Runtime
Usage from the CLI (packages/cli/src/main.ts):
const agents = new FakeAgentRuntime({
teams: {
'engineering-team': {
main: 'lead',
members: ['lead', 'implementer', 'test-engineer', 'reviewer'],
},
},
});
const result = await runFlowSandboxed(compiled, input, {
host: { agents, events, context: { project: 'cli-demo' } },
});
Swap FakeAgentRuntime for your implementation (OpenAI, Anthropic, an
internal gateway...) — the workflow doesn't change a line. That is where
"vendor-free" lands.
Build & test
pnpm build # tsc -b: all packages
pnpm test # vitest unit tests
pnpm e2e # sandbox end-to-end tests
pnpm typecheck # type check
pnpm lint # biome