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
| Layer | Technology | Rationale |
|---|---|---|
| Monorepo | pnpm + Turborepo | Workspace isolation + build caching |
| Language | TypeScript (strict) | Shared types across all packages |
| Web | Next.js 15 (App Router) | Full-stack React + API routes |
| Database | PostgreSQL + Drizzle ORM | Relational model + type-safe queries |
| Object Storage | S3-compatible | Content-addressed blobs via presigned URLs |
| Auth | Auth.js v5 + Device Flow | Web sessions + CLI device grant |
| Schema | Zod | Runtime validation shared everywhere |
| CLI | Commander.js | Lightweight subcommand support |
| Config | TOML (human) + JSON (machine) | Right format for each use case |
| Testing | Vitest + Playwright | Unit/integration + E2E |
| CI | GitHub Actions | Standard 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.