03-architecture.md
1. System overview
QPlan is a step-based workflow engine built for the βLLM writes β engine executesβ scenario. A QPlan script flows through Tokenizer β Parser β Semantic Validator β Step Resolver β Executor, and every intermediate value is stored in the ExecutionContext (ctx). The components below live in src/, and external callers access them via runQplan, registry, buildAIPlanPrompt, etc.
Script
β tokenize() (src/core/tokenizer.ts)
Tokens
β Parser.parse() (src/core/parser.ts)
ASTRoot
β validateSemantics() (src/core/semanticValidator.ts)
Validated AST + StepResolution
β Executor.run() (src/core/executor.ts)
ExecutionContext (variables, futures, step outputs)
2. Core components
| Component | Description | Key files |
|---|---|---|
| Tokenizer | Breaks scripts into tokens; recognizes strings, numbers, JSON, identifiers, keywords. | src/core/tokenizer.ts |
| Parser | Converts tokens into AST nodes (Action, If, While, Each, Parallel, Step, Jump, etc.), verifying all actions/control statements are inside steps and handling var/print syntax. | src/core/parser.ts, src/core/ast.ts |
| Semantic Validator | Pre-checks duplicate step IDs, ensures onError=βjumpβ targets and jump to targets exist, and returns issues. | src/core/semanticValidator.ts |
| Step Resolver / Controller | Computes order/path/parent relationships for the step tree and, during execution, manages onError policies (fail/continue/retry/jump) plus plan/step events (onPlanStart/End, onStepStart/End/Error/Retry/Jump). | src/step/stepResolver.ts, src/step/stepController.ts, src/step/stepEvents.ts |
| Executor | Runs the AST sequentially/parallel, handling If/While/Each/Parallel/Jump/Set/Return/Future/Join/Stop/Skip and updating the ExecutionContext. | src/core/executor.ts |
| ExecutionContext | Runtime store offering ctx.set/get/has/toJSON plus ctx.getEnv() / ctx.getMetadata() for per-run context. Supports dot-path access (stats.total) so sub-fields of step outputs can be reused. | src/core/executionContext.ts |
| QPlan wrapper | Optional object that pre-parses/validates a script, exposes step metadata via getStepList(), and runs with built-in lifecycle tracking while forwarding custom stepEvents. Useful when UIs need a plan overview before execution. | src/qplan.ts, examples/19_exam_qplan_object.js |
| ModuleRegistry | Manages ActionModule registration/lookup/metadata exposure. Each ModuleRegistry seeds the default basic modules (unless { seedBasicModules: false } is passed). | src/core/moduleRegistry.ts, src/index.ts |
| ActionModule | Function-style or { execute(inputs, ctx) {} } modules. Metadata id/description/usage/inputs powers docs and LLM prompts. | src/core/actionModule.ts |
| Prompt Builders | buildAIPlanPrompt, buildQplanSuperPrompt, buildAIGrammarSummary combine registered modules and grammar summaries into LLM prompts. | src/core/buildAIPlanPrompt.ts, src/core/buildQplanSuperPrompt.ts, src/core/buildAIGrammarSummary.ts |
3. Step system architecture
- Step definition β
step id="..." desc="..." type="..." onError="..." { ... }. The parser reads the header, validates the ID, and builds a StepNode. - Step resolution β Before execution,
resolveSteps()walks the tree to computeorder,path,parent, anderrorPolicymetadata, plus a StepID β StepNode map. - StepController β When the executor runs a step, the controller handles:
- Emitting onStepStart/End/Error/Retry/Jump events (supplied via
stepEvents). onError="continue": end the step on error and move on.onError="retry=N": retry up to N times, calling onStepRetry each attempt.onError="jump='cleanup'": raise a JumpSignal to another step.
- Emitting onStepStart/End/Error/Retry/Jump events (supplied via
- Jump handling β
jump to="stepId"statements or onError jumps throw JumpSignals; the executor updates block overrides to restart loops/blocks accordingly. - Step result β If the step block contains
return, that object becomes the result; otherwise, the final action result becomes the step result. Either way, the executor stores it underctx[runId][namespace], wherenamespacedefaults to the step ID (override withstep ... -> resultVar), and mirrors the same object under the original step ID so later steps can reference eithernamespace.fieldorstepId.field.
4. Module structure
- Default bundle β
src/modules/index.tsregisters nine modules (var/print/echo/sleep/file/math/future/join/json) into the default registry. - Extension modules β
src/modules/basic/*.tscontains optional modules (http, html, string, ai, timeout, etc.) that can be activated viaregistry.register(). - ActionModule execution β The executor fetches a module, calls it directly if itβs a function or
mod.execute()if itβs an object. When a future module returns{ __future: Promise }, only the promise is stored in ctx so join can consume it.
5. Prompt / AI integration
- buildAIPlanPrompt(requirement, { registry, language }) β Bundles registered module metadata, AI-friendly grammar summary, execution rules, and user requirements into a prompt telling the LLM to βoutput QPlan only,β using whichever registry/language you provide.
- buildQplanSuperPrompt(registry) β System-level prompt describing QPlan philosophy, architecture, modules, and grammar summary.
- buildAIGrammarSummary() β Produces a lightweight grammar synopsis versus the full
docs/02-grammar.md, reducing LLM input size.
6. ExecutionContext & data flow
- Store β Save action or step results via
ctx.set(name, value). - Read β When another action passes a string argument, it auto-binds if the ctx has a matching name.
ctx.has/ctx.getsupport dot paths, so returningstats={ total, count }lets you reusestats.total. - Dump β
ctx.toJSON()dumps the entire state for logging/debugging.
7. Tooling & validation
- validateQplanScript(script) β Returns tokenize/parse/semantic-validation results;
{ ok: true, ast }on success,{ ok: false, error, line, issues? }on failure. - CLI β
npm run validate -- <file>(backed bysrc/tools/validateScript.ts) checks files or stdin for CI/editor integrations. - Step events β
runQplan(script, { env, metadata, stepEvents })λλqplan.run({ ... })λ₯Ό μ¬μ©νλ©΄ νλ μμ/μ’ λ£μ Step μ§ν μν©μ UI/λ‘κ·Έ/λͺ¨λν°λ§μ μ λ¬νλ©΄μ μ€ν 컨ν μ€νΈ(env/metadata)λ₯Ό 곡μ ν μ μλ€.
8. Extension & integration points
- Add modules β Implement an ActionModule and call
registry.register(customModule). With metadata filled in, prompt builders automatically include usage info. - Custom executor hooks β Use
stepEventsto capture plan+step start/end/error/retry/jump events (receivingStepEventRunContext) and feed Gantt charts, progress, or audit logs. - LLM integration β Generate prompts via
buildAIPlanPrompt(optionally callingsetUserLanguage("<language>")with any string beforehand) and execute withrunQplanor theQPlanwrapper to realize βAI thinks, QPlan executes.β - Further docs β See
docs/02-grammar.md,docs/06-executor.md,docs/10-step-system.md, etc., for deeper extension strategies.
9. Summary diagram
+---------------------+
| QPlan Script |
+---------------------+
|
v tokenize()
+---------------------+
| Tokenizer |
+---------------------+
|
v Parser.parse()
+---------------------+
| AST (Action/Step/...)|
+---------------------+
|
v resolveSteps() + validateSemantics()
+---------------------+
| StepResolution |
+---------------------+
|
v Executor.run()
+---------------------+
| StepController + |
| ExecutionContext |
+---------------------+
|
v
+---------------------+
| ctx variables / |
| step events / logs |
+---------------------+
This architecture delivers concise grammar, step-based control, and module extensibility so AI and humans can co-design and run workflows.