ADR 0000 Federated Design Infrastructure & Storage Architecture
Originally
ADR 0000--Federated Design Infrastructure & Storage Architecture (v1) · Source on Confluence ↗Our current monolithic Figma workflow has led to divergent component copies across product teams, inconsistent token usage, and an inability for AI agents to resolve a single source of truth. Design-to-code handoff is unreliable because there is no enforceable contract between design artifacts and React implementations.
Design team routinely copy-pasted components and tweak them locally, creating invisible drift that only surfaces during visual QA - often too late to address without significant rework. AI agents operating in this environment cannot determine which variant of a component is canonical, leading to non-deterministic code generation.
Decision Drivers
- AI agents require deterministic, machine-readable sources; Figma files are opaque.
- Component drift across products creates visual inconsistency and duplicated engineering effort.
- Token-level governance is impossible without a version-controlled, CI-enforced pipeline.
- The design-to-code pipeline must support fully automated code generation with predictable outputs.
Alternatives Considered
| Option | Rejected Because |
|---|---|
| Single monorepo for all design + product code | Couples release cycles; product teams can’t ship independently. Blast radius of a bad merge affects all products. |
| Figma + plugin-based sync (e.g., Tokens Studio) | No CI enforcement; drift detection is manual and advisory-only. AI agents cannot reliably parse plugin output. |
| Package-registry-only model (npm-style distribution) | Adds indirection; .pen files need direct Git-resolvable imports for AI context. Loses the ability to do cross-file AST analysis at CI time. |
1. The Core Principle: “Centralize System, Localize Composition”
We are moving away from a monolithic Figma file. We are adopting a federated model where the Shared Repo owns the Language and the Product Repo owns the Usage.
2. Storage & Ownership Distribution
To ensure AI agents have the correct context, files must be stored according to these strict boundaries:
A. Shared Design-System Repo (ds-core)
Role: The Library. Defines the “Atomic” building blocks.
| Artifact | Description |
|---|---|
| Tokens | All primitive and semantic JSON definitions. |
Shared .lib.pen Libraries | The source of truth for all base components. |
| Primitives | Base shapes and low-level UI elements. |
| Variants & States | Comprehensive definitions of all component permutations. |
| React Contracts | TypeScript interfaces that the AI must satisfy. |
| AI Prompts | The “System Instructions” for how agents should interpret these components. |
| Governance Docs | Rules for when to promote a local component to a shared one. |
Versioning: ds-core follows semver. Product repos pin to a minor range (e.g., ~2.3.0) in a pen.lock or equivalent manifest. Major bumps require explicit opt-in. The Guardian Agent blocks builds if a product repo references a deprecated or yanked component version.
Dependency Resolution: .pen imports resolve via a Git submodule or package reference. The chosen mechanism must support offline resolution and deterministic builds. While a registry URL may be used as a fallback resolution path, the primary import mechanism must remain Git-resolvable so AI agents can perform cross-file AST analysis.
B. Product Repos (app-dashboard, app-mobile, etc.)
Role: The Implementation. Defines the “Molecular” and “Organism” layouts.
| Artifact | Description |
|---|---|
| Screens | Full-page layouts constructed from shared primitives. |
| Flows | Multi-screen logic and navigation paths. |
| Feature Compositions | High-level UI patterns unique to that product (e.g., a specific “Analytics Widget”). |
| Product-Specific Exceptions | Deliberate, reviewed deviations from the system. |
| Generated React Code | The output of the AI Codegen agent. |
| Stories & Tests | Automated UI tests (Storybook) for the product-specific compositions. |
Generated Code Ownership: Files in /components/generated are machine-owned. Manual edits are overwritten on regeneration. If a developer needs to customize generated output, they must wrap it in a handwritten component under /components/composed and never modify the generated file directly.
3. Ownership Boundary: Definition vs. Composition (“The Usage Rule”)
- The Shared Repo owns the “What”: What is a Button? What color is Primary?
- The Product Repo owns the “Where”: Where does the Button go on the Login screen?
Non-Negotiable: A product repo can create a DashboardHeader.pen (composition), but it cannot redefine Button.pen (primitive). If a product team needs a new “type” of button, they must submit a PR to the ds-core repo.
Token Resolution Order
Product repos may define theme-level overrides (e.g., dark mode mappings) but must not redefine primitive token values.
ds-core/tokens/primitive → Base values (color-blue-500: #3B82F6)
ds-core/tokens/semantic → Mapped meanings (color-primary: {primitive.color-blue-500})
product-repo/tokens/theme → Scoped overrides (color-primary: {primitive.color-indigo-500})
↑ Only semantic-tier remapping allowed.
Primitive-tier keys must never be shadowed.The Guardian Agent validates that no product-level token shadows a primitive-tier key.
4. Technical Rule: “No Silent Local Forks”
One of the primary failure points in our current Figma workflow is “copy-pasting a component and tweaking it locally.”
Pencil.dev Enforcement: Product-level .pen files should only reference the .lib.pen from the shared repo.
CI Detection Mechanism
The Guardian Agent runs a pen lint --no-local-shadows check during CI. It compares the AST of every .pen file in the product repo against the ds-core component registry. A match on component name + category (not content hash) triggers a hard failure with an auto-generated message:
❌ LOCAL_FORK_DETECTED: `Button.pen` in /design/components/
shadows `ds-core/primitives/Button.lib.pen`.
→ Import: `@use "ds-core/primitives/Button.lib.pen"`
→ Or submit an extension PR:
https://github.com/org/ds-core/issues/new?template=primitive-extension5. Revised AI Pipeline for Storage Logic
The AI Agents are now “Repo-Aware”:
- The Architect Agent sits in the Product Repo. It looks at the local
Flow.penand the importedds-corelibrary to generate the layout code. - The Reviewer Agent checks if a Product-Specific Exception is actually a new “Primitive” in disguise. If it detects a recurring pattern, it triggers an “Extraction Ticket” to move that pattern into the Shared Repo.
Extraction Threshold & Process
The Reviewer Agent uses a 3-screen / 2-product threshold:
- A composition qualifies for extraction when it appears in ≥3 screens within one product, OR
- it appears in ≥1 screen in each of ≥2 different product repos.
The agent opens an Extraction Ticket in ds-core containing:
- Usage locations (file paths + screenshots)
- Proposed prop interface
- Diff from nearest existing primitive
SLA: DesignOps must triage extraction tickets within 5 business days. Until promoted, the composition remains product-owned.
6. Definition of Done (Storage Focus)
A feature is not “Done” until:
- All primitives used are imported from
ds-core. - The screen composition lives in the Product Repo’s
/designfolder as a.penfile. - The generated React code lives in the Product Repo’s
/components/generatedfolder. - No raw values (hex/px) exist in the local product files.
- Storybook stories exist for all product-specific compositions.
- The Guardian Agent CI check passes with zero warnings.
7. Breaking Change & Deprecation Policy
When a shared primitive changes its prop contract or visual output:
- The old version is marked
@deprecatedin the.lib.penmetadata with a migration note. - A compatibility window of 2 minor releases is maintained (both old and new coexist).
- The Guardian Agent emits warnings during the window; after expiry, it fails builds.
- The AI Architect Agent is updated to generate code against the new contract only after the compatibility window opens.
Consequences
Positive
- Single source of truth for AI agents enables deterministic code generation.
- CI-enforced consistency eliminates silent component drift.
- Product teams retain full composition autonomy within clear guardrails.
- Clear ownership boundaries reduce cross-team ambiguity and design review overhead.
Negative
- Higher onboarding cost for product teams unfamiliar with the federated model.
- PR friction for new primitive requests against
ds-coremay slow teams initially. - Requires Guardian Agent infrastructure investment before enforcement is possible.
- Cross-repo dependency chain introduces versioning complexity that must be actively managed.
Neutral
- Extraction Ticket workflow creates a new process that needs cultural adoption.
- Theme-override scoping rules require documentation and team education.
Appendix: Open Questions
- Submodule vs. package reference: Which resolution mechanism should be the default? Needs a spike with the DevEx team.
- Multi-brand theming: If a product repo serves multiple brands, does the token override cascade need an additional tier?