The Build Pipeline
The fixed phase sequence that turns a project into a ColdBox application.
On this page
The Build Pipeline
bxAgents build runs a fixed sequence of phases, once, producing a plain ColdBox application. Nothing here runs again at request time - that's the whole point of build-time assembly. This page walks the phases in the exact order BuildPipeline.bx runs them.
flowchart TD
A["1 Β· Resolve config<br/><small>AgentConfigResolver</small>"] --> B["2 Β· Discover<br/><small>ProjectDiscoverer</small>"]
B --> C{"3 Β· Validate<br/><small>ProjectValidator</small>"}
C -->|"any error"| X["Build throws.<br/>.build/app is never written or touched"]
C -->|"clean<br/><small>warnings never block</small>"| D["4 Β· Generate"]
D --> D1["1 Interceptors"] --> D2["2 Gateways"] --> D3["3 MCP"] --> D4["4 Router"]
D4 --> D5["5 Web UI"] --> D6["6 Core app skeleton"] --> D7["7 Tools/skills copy"] --> D8["8 Scheduler"]
D8 --> E["5 Β· Normalize + write<br/><small>ManifestNormalizer</small>"]
E --> F[".build/manifest.json<br/>+ .build/app - a plain ColdBox application"]
style C fill:#fff3cd,stroke:#856404
style X fill:#f8d7da,stroke:#721c24
style F fill:#d4edda,stroke:#155724
Validation is the gate: it collects every error rather than failing fast, and nothing is generated until it comes back clean.
(Packaging into a .bxa is a deliberately separate step - see Deployment & Secrets - so a fast build β inspect β build again loop never pays a packaging cost it doesn't need.)
1. Resolve config
AgentConfigResolver loads Agent.bx, invokes configure() and the active environment's override method, then deep-merges in boxlang.json/boxlang-{env}.json/miniserver.json/miniserver-{env}.json if present. Produces the single resolved config struct every later phase reads from.
2. Discover
ProjectDiscoverer walks the project root and enumerates every convention folder (models/, tools/, skills/, subagents/, gateways/, mcp/, interceptors/, modules/) into raw { name, path, type } entries. schedules/ is the one exception - it's not a list of entries, just a single hasScheduler/schedulerPath pair, since it holds one real ColdBox scheduler file rather than a set of BX Agents-defined config entries. Pure discovery - no interpretation of file contents happens yet.
3. Validate
ProjectValidator runs every validator and collects every error (never fail-fast) plus any warnings: duplicate tool/skill/model/subagent names, duplicate agent names across the whole subagent tree (see subagents/), circular subagent/module references, the two gateway entry shapes, remote MCP config completeness, and model/provider validity. If any errors were collected, the build throws immediately here - no .build/app is written or touched. Warnings (e.g. a schedules/ folder with no Scheduler.bx in it) never block the build.
4. Generate
Only reached once validation is clean. In order:
- Interceptors -
InterceptorSplittercopiesagent-scope interceptors into.build/app/interceptors,runtime-scope ones into a separate.build/runtime-interceptorsdirectory. - Gateways -
GatewayGeneratoremitsaiGatewayRegistry().register(...)statements for channel-adapter entries, and (if any aretype: "http") writes.build/app/handlers/Gateway.bx. If any entry is a push-style gateway (e.g.type: "telegram"), it also writes.build/app/interceptors/GatewaySessionBootstrap.bx, wiring a single bx-aiGatewaySession(bundling every push-style gateway) to the project's root agent. - MCP -
McpGeneratorcopies localmcp/*servers into.build/app/mcpand emits theirmcpServer(...).registerTool(...)registration statements. - Router -
RouterGeneratorwrites.build/app/config/Router.bx: oneroute(path).toAi(...)/toMCP(...)per exposure entry, plus the 3 fixed gateway webhook routes if ahttp-type channel gateway exists. - Web UI -
WebUiGeneratorruns for anyexposes: "webui"entry, writing the static<path>/index.html,handlers/ChatUi.bx(the twenty-action API),models/ChatDb.bx(the SQLite store and its forward-only migrations),interceptors/WebUiSchema.bx(migrates at boot rather than on whichever request touches the database first), and - only whenapiKeyEnvVaris set -interceptors/WebUiAuthGate.bx. It returns the resolved database config, which the next step needs. - Core app skeleton -
ColdBoxAppGeneratorwritesApplication.bx,config/ColdBox.bx,config/WireBox.bx,agent/GeneratedAgentFactory.bx, andindex.bxm, threading in every statement gathered above (gateway registrations, MCP registrations, and - iftools/has any files - a bareaiToolRegistry().scan("tools")call) intoApplication.bx'sonApplicationStart(), and (Phase 1'sGatewaySessionBootstrap.bx, if generated) into theinterceptorslistconfig/ColdBox.bxreferences. Every generated agent also now always receives a checkpointer (withCheckpointer(...), defaulting to acache-backedaiMemory()if the project declares nocheckpointerconfig and the class set none of its own) - without one, human-in-the-loop approval flows through any gateway other thanclifail outright.config/WireBox.bxmaps every agent in the tree (root + every subagent) under its own declaredname, not just the fixed root"GeneratedAgent"alias - see schedules/. For a project with awebuiexposure it also turns session management on, registers the SQLite datasource (naming it as the app default viathis.datasource), creates the database's parent directory inonApplicationStart()- SQLite creates the file but never the folder holding it - and pins qb's grammar inconfig/ColdBox.bx. - Tools/skills copy -
ToolsSkillsCopierwipes and rewrites.build/app/toolsand.build/app/skillsverbatim from your project's own folders. - Scheduler -
SchedulerGeneratorcopiesschedules/Scheduler.bxthrough to.build/app/config/Scheduler.bxuntouched, if present - no generation, it's real ColdBox code you wrote yourself.
5. Normalize + write the manifest
ManifestNormalizer produces the canonical, hash-stamped internal manifest from the discovery + resolved-config data, and the pipeline writes it to .build/manifest.json.
Idempotency
Rebuilding an unchanged project produces byte-identical output, down to the manifest's per-file content hashes - the entire point of paying the assembly cost once, at build time, rather than deferring any of this work into request handling.