Skip to main content

Architecture

Workloom is a TypeScript monorepo built with pnpm workspaces and Turborepo. The architecture enforces strict package boundaries with no dependency cycles.

System Overview​

┌───────────────────────────────────────────────────────────────┐
│ Workloom Registry │
│ │
│ Organizations → Packages → Versions → Assets │
│ ↓ │
│ Workspaces → Targets → Provider assignments │
│ ↓ │
│ Revisions → Audit trail → Approval workflows │
└───────────────────────────┬───────────────────────────────────┘
│ HTTPS / Object Sync
▼
┌───────────────────────────────────────────────────────────────┐
│ wl CLI │
│ │
│ pull → resolve → render plan → provider adapters → write │
│ sync --check → drift detection → exit codes │
│ push → draft → review → publish │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ Local Workspace │
│ │
│ .claude/settings.json AGENTS.md .github/copilot-*.md │
│ CLAUDE.md .codex/ .loom/state.json │
│ .claude/skills/** config.toml .loom/lock.json │
└───────────────────────────────────────────────────────────────┘

Monorepo Structure​

workloom/
apps/
cli/ # `wl` CLI — Commander.js
web/ # Next.js 15 — Registry UI & API
docs/ # Docusaurus — This documentation

packages/
core/ # Domain IDs, errors, policy enums
manifest/ # Zod schemas for all manifest types
renderer/ # Deterministic render engine
provider-claude/ # Claude adapter
provider-codex/ # Codex adapter
provider-copilot/ # Copilot adapter
provider-gemini/ # Gemini adapter (fixtures only)
drift/ # Drift detection and classification
telemetry/ # Privacy-safe event builder
config/ # TOML parsing, platform paths
db/ # PostgreSQL schema (Drizzle ORM)
sdk/ # Typed HTTP API client

fixtures/ # Test fixtures for all scenarios

Package Dependency Graph​

Dependencies flow strictly downward. No cycles are permitted.

core ← no dependencies
↑
├── manifest
│ ↑
│ ├── renderer
│ │ ↑
│ │ ├── provider-claude
│ │ ├── provider-codex
│ │ ├── provider-copilot
│ │ ├── provider-gemini
│ │ └── drift
│ │
│ ├── telemetry
│ ├── sdk
│ └── db
│
└── config

Key Architectural Invariants​

1. Registry-First Desired State​

Canonical assets, versions, workspace assignments, and approvals live in the registry. Local files are generated artifacts — not the source of truth.

2. Provider-Aware Core​

Provider asymmetry is modeled explicitly via a capability matrix. The core understands that Claude, Codex, Gemini, and Copilot have fundamentally different file locations, scoping rules, and trust behaviors.

3. Immutable Packages, Revisioned Workspaces​

Package versions are append-only. You can't silently change a published version. Workspace state changes are tracked through numbered revisions with full audit trails.

4. Deterministic Rendering​

Same input (package + workspace revision) → same output files. Always. The CLI and web UI use the exact same @workloom/renderer package to guarantee parity.

5. HTTPS Object Sync Only​

No rsync, SSH, shell remoting, or bidirectional folder sync. Whole-object transfer for text assets: normalize → validate → SHA-256 hash → upload if missing → reference by hash.

6. Desired-State Apply, Not File Mirroring​

wl pull fetches desired state. wl sync applies it through a render plan. This is Terraform-style plan/apply — not Dropbox-style mirroring.

Tech Stack​

LayerTechnologyRationale
Monorepopnpm + TurborepoWorkspace isolation + build caching
LanguageTypeScript (strict)Shared types across all packages
WebNext.js 15 (App Router)Full-stack React + API routes
DatabasePostgreSQL + Drizzle ORMRelational model + type-safe queries
Object StorageS3-compatibleContent-addressed blobs via presigned URLs
AuthAuth.js v5 + Device FlowWeb sessions + CLI device grant
SchemaZodRuntime validation shared everywhere
CLICommander.jsLightweight subcommand support
ConfigTOML (human) + JSON (machine)Right format for each use case
TestingVitest + PlaywrightUnit/integration + E2E
CIGitHub ActionsStandard ecosystem

Render Pipeline Deep Dive​

The render pipeline is the core of Workloom. Here's how a wl pull works internally:

1. Fetch workspace revision from registry
└→ Returns: packages[], targets[], overrides[]

2. Resolve version constraints
└→ Returns: resolved package versions with content hashes

3. Download missing objects (content-addressed)
└→ SHA-256 verified on download

4. Build render plan
└→ For each target × provider:
- Select packages assigned to this target
- Apply workspace overrides
- Determine output file paths
- Calculate merge ordering for shared files

5. Execute render plan
└→ Each provider adapter transforms canonical assets
into provider-specific file content

6. Apply ownership model
└→ Check existing file state (managed/modified/override/user_local)
└→ Apply conflict policy
└→ Write files + update .loom/state.json

Security Architecture​

Workloom's trust model is built around the principle of explicit approval for anything that expands authority:

  • Passive text (instructions, prompts): auto-applied
  • Configuration (settings): manual review
  • Tool permissions (sandbox, grants): approval required
  • Executable hooks (shell commands): approval required
  • Networked MCP (server configs): approval required

See Trust & Security for the full trust classification matrix.