Architecture — AtelierBID
How the package is structured and how data flows through it.
AtelierBID has a deliberately simple shape: skills orchestrate, subagents do the reasoning, Node scripts do the deterministic work, and file-first artefacts are the output. Nothing runs outside the Claude Code session.
1 · The runtime model#
The plugin has zero backend and zero marginal cost. Every capability is a Claude Code primitive:
| Role | Implementation |
|---|---|
| User-facing entry point | a skill in skills/ |
| AI reasoning unit | a subagent in agents/ |
| Deterministic computation | Node scripts in scripts/ (+ scripts/lib/ libraries) |
| Design constants | data/design-system.json |
| Per-run state | a per-run output/<run-id>/ folder |
Top-level layout#
| Path | Responsibility |
|---|---|
skills/ | User-facing entry points (/AtelierBID:<skill>). Each SKILL.md defines the workflow steps. |
agents/ | Single-purpose reasoning subagents dispatched by skills (21 in total). |
scripts/ | 32 deterministic Node CLIs across all lifecycle phases — foundation, discovery, model, calculation, design, AI, and documentation. |
scripts/lib/ | Pure libraries: grounding/lifecycle helpers; design libs colorMath / themeBuilder / designSystem; pipeline libs mockupIr / composeLayout / chooseVisualType / irToPbir / applyTokens. |
data/design-system.json | Machine-readable constants: audience archetypes, layout patterns, colour roles, canvas sizes, theme defaults. data/canonical-sample.schema.json is the grounding fallback sample. |
.claude-plugin/ | plugin.json + marketplace.json manifests. |
output/<run-id>/ | Generated artefacts and step checkpoints (gitignored). |
The core design principle — deterministic vs. AI split#
Two subagents serve the calculation and metadata phases. measure-author turns a batch of requested measures into DAX bound strictly to the columns present in the supplied model, factoring shared base measures across the batch and marking anything off-schema as a proposal rather than inventing a column. metadata-enricher writes descriptions and synonyms that beat the deterministic fallback — ai-readiness.js can only template ("Amount on the Sales table."), which restates the column name and helps nobody. Neither agent writes files: both return JSON, and the skills and CLIs perform all I/O, so the write path stays byte-reproducible.
Structure is computed; taste is delegated. Scripts are deterministic and AI-free — they consume no tokens and produce reproducible output: building/validating theme JSON, colour distances, sanitising SVG/HTML, rendering DDL/Mermaid, scaffolding a PBIP, capturing a requirements spec, emitting review-only SQL/M/DAX, composing a report layout, and converting a mockup IR into PBIR. Subagents are stateless reasoning units that handle the judgment calls (brand → palette, layout composition, schema design). The skill is the only coordinator; agents never call each other. No deterministic script uses the clock, randomness, or the network.
Data flow (a design-pipeline run)#
flowchart TD
U[User brief] --> S[Skill: design-report]
S --> R["new-run.js → output/<run-id>/"]
R --> A1[orchestrator agent]
A1 --> A2[brand → data-model → dummy-data agents]
A2 --> A3[composer → visual-fill agents]
A3 --> SC["deterministic compose / token / IR checks"]
SC --> A4[validator → narrative agents]
A4 --> O[mockup HTML + IR in run folder]
A1 -. checkpoint .-> R
A3 -. checkpoint .-> REach step checkpoints into the run folder before the next begins, so an interrupted run resumes from the last completed step.
The mockup → PBIR bridge (Phase E)#
The design phase's headline structure is a single shared mockup IR read by both the human previews and the PBIR converter, so an approved mockup becomes a report page without re-authoring:
flowchart LR
CMP["design-report.js --compose<br/>(composeLayout + chooseVisualType)"] --> IR["mockup IR<br/>(mockupIr.js — schemaVersion 1.0)"]
IR --> TOK["--apply-tokens (applyTokens.js)<br/>resolve tokens + background zones"]
TOK --> MH["--emit-mockup → HTML mockup"]
TOK --> PRO["prototype-report.js --ir<br/>interactive Chart.js prototype"]
PRO --> EIR["--emit-ir → approved IR (byte-identical)"]
EIR --> PBIR["design-report.js --from-ir --pbip<br/>(irToPbir.js → PBIR-enhanced page)"]
TOK --> PBIRThe IR is a self-describing JSON contract (kind atelierbid/mockup-ir, additive-only — ADR-0033) carrying the grid, KPI strip, and per-visual type + rationale on a floor+remainder grid tiling that guarantees no overlap. Conversion (irToPbir.js) targets the PBIR-enhanced format, maps visual types through a fixed VISUAL_TYPE_MAP (unmapped → warn-and-skip), emits deterministic GUIDs, and guards existing files behind a _atelierBidGeneratedBy ownership sentinel (ADR-0034).
The foundation & data-acquisition CLIs (Phases A + B)#
The grounding/lifecycle spine plus discovery, SQL and Power Query/M authoring compose into one coherent starting flow:
flowchart LR
NP["new-project.js"] --> PBIP["scaffold-pbip.js / validate-pbip.js"]
NP --> BP["best-practice.js (seed _00-Best-Practice/)"]
GC["ground-schema.js (load gate · propose-don't-invent · re-ground)"] --> GEN[generation]
LC["lifecycle.js (offline floor · Tier-1 opt-in · bind-gate · manual publish)"] -. wraps .-> GEN
DR["discover-requirements.js"] --> AS["author-sql.js (emit-only)"]
AS --> AM["author-m.js (emit-only)"]2 · The full-package architecture#
The package covers seven lifecycle phases, all writing into one PBIP project, all standing on the shared cross-cutting spine (Phase A).
flowchart TB
subgraph SPINE["Cross-cutting spine — always on"]
GC[Schema-grounding contract]
BP[Best-practice rule library]
LC[Hybrid lifecycle + conformance harness]
end
A[A · Start project + PBIP shell] --> B[B · Discovery + SQL/M text]
B --> C[C · Model — star schema → TMDL]
C --> D[D · Calculation — DAX]
D --> E[E · Design — tokens → theme → IR → PBIR]
E --> F[F · AI — readiness + Fabric data agent]
F --> G[G · Documentation]
SPINE -. grounds / guards / cites .-> A
SPINE -. grounds / guards / cites .-> C
SPINE -. grounds / guards / cites .-> D
SPINE -. grounds / guards / cites .-> EKey components and responsibilities#
| Component | Responsibility | Where |
|---|---|---|
| New Project + PBIP scaffold | Create the project folder + conventions, and an openable PBIP container every downstream skill writes into; structural validator as a Desktop proxy. | Phase A |
| Schema-grounding contract | Single authoritative schema-of-record; a load gate; propose-don't-invent (off-schema = a proposal); re-ground on change. | Phase A |
| Best-practice rule library | Per-project _00-Best-Practice/ rules + BPA JSON; the single source the model/DAX/settings skills cite by stable id. | Phase A |
| Hybrid lifecycle + conformance harness | Offline floor + optional Tier-1; "bind live data?" gate; drift guard over canonical PBIR/TMDL fidelity; manual publish. | Phase A |
| Discovery + source text | Deterministic requirements spec with trace ids + gap detection; emit-only SQL and folding-aware Power Query/M. | Phase B |
| Model engine | Emit star-schema TMDL: tables, inferred safe relationships including role-playing, settings, partitions, incremental refresh, and a ranked read-only optimisation pass with safe auto-fix. | Phase C |
| Calculation engine | Idiomatic DAX + calc groups in a _Measures host; a time-intelligence family on a contiguous marked date table; equivalence-preserving rewrites with a write-back gate; EVALUATE validation queries. | Phase D |
| Design pipeline | Token contract, accessible theme with RAG separation, zoned PBIP-wired background, a shared mockup IR that converts into valid PBIR, and an interactive prototype. | Phase E |
| AI layer | Model AI-readiness (audit, descriptions+synonyms, linguistic schema, surface hygiene, verified answers) via one offline CLI; plus a Fabric data-agent generator emitting a grounded agent-config.json with scope + guardrails and an ordered provisioning runbook. | Phase F |
| Documentation generator | Deterministic, regenerable data dictionary parsed straight from the TMDL. | Phase G |
The artefact model — one project that accretes#
All phases write into a single PBIP container, which grows but always stays Desktop-openable:
flowchart LR
P0[Empty PBIP shell] --> P1[+ TMDL model]
P1 --> P2[+ DAX measures]
P2 --> P3[+ theme.json + PBIR report]
P3 --> P4[+ AI-ready metadata]
P4 --> P5[Openable, documented project]Data-flow / grounding tier model#
stateDiagram-v2
[*] --> Offline
Offline --> Offline: generate / validate (file-first, zero network)
Offline --> Tier1: user opts in — "bind live data?"
Tier1 --> Offline: read live schema · validate · drop back
Tier1 --> Manual: publish / refresh
Manual --> [*]: runs in the Power BI Service — instructions only, never via APIOffline is the default and floor; live read/validate is opt-in Tier-1; publish/refresh are always a deliberate manual step (ADR-0002, ADR-0008).
External dependencies#
By design, there are almost none:
- Runtime: Node.js (stdlib only — no npm dependencies).
- Claude Code: provides the skill/subagent execution environment.
- Chart.js (CDN): loaded only by the interactive prototype's output HTML, at view time — the one optional, preview-only network dependency. The IR → PBIR generation path is fully offline.
- Power BI Desktop (optional): for the "opens without error" verification and the optional Tier-1 live read/validate. Never required for the offline floor.
- No backend, database, auth, API key, or cloud service — the zero-backend stance is the defining constraint.
Decisions that shape the architecture#
- ADR-0002 — optional live connectivity as Tier-1 above an offline floor; publish stays manual.
- ADR-0004 — PBIP structural baseline + offline determinism; the validator is a Desktop proxy.
- ADR-0012 / 0013 — SQL and Power Query/M authoring are emit-only with offline static validation.
- ADR-0014–0021 — the model engine: emit-only TMDL, inferred star-safe relationships, settings, partitions, incremental refresh, and a read-only optimiser with a result-preservation gate.
- ADR-0022–0029 — the calculation engine: TMDL measure shape, marked-date binding, contiguous date table, time-intelligence semantics, equivalence-preserving rewrites, and EVALUATE queries.
- ADR-0030–0032 — the design token contract, RAG separation rule, and background wiring.
- ADR-0033 — the shared mockup-IR schema + floor/remainder grid tiling.
- ADR-0034 — IR → PBIR conversion to the PBIR-enhanced format with offline structural fidelity.
- ADR-0035–0039 — the AI-readiness layer: model-as-TMDL-directory + exit-0-findings-in-content; additive enrich; linguistic-schema shape; hygiene via
displayNamewithout renaming; measure-grounded verified answers. - ADR-0040–0042 — the Fabric data agent: a single deterministic
agent-config.json; an offline-floor CLI shape; a grounding-input contract accepting JSON model or TMDL directory.
See Decisions for the full digest.