Flow Diagrams
Four maps. How a fragmented CLI stack became a unified instrument. The outcome map defines success. The architecture shows the target. The capability map reveals what to extract. The build order sequences the work.
What does success look like?
Three outcomes. Each proves a different layer of consolidation.
OUTCOME MAP — CLI Platform
═════════════════════════
┌─────────────────────────────────────────────────┐
│ drmg ROUTES ALL COMMANDS │
│ (One binary, 9 namespaces, 60+ commands. │
│ Every CLI operation through one entry point.) │
└────────────────────────┬────────────────────────┘
│
┌──────────────┴──────────────┐
│ │
┌──────────▼──────────┐ ┌──────────▼──────────┐
│ ZERO DIRECT DB │ │ AGENTS DISCOVER │
│ IMPORTS │ │ COMMANDS AT │
│ │ │ RUNTIME │
│ ESLint blocks │ │ │
│ import { db } in │ │ drmg describe │
│ tools/scripts/ │ │ returns JSON schema │
│ CI enforces. │ │ for any namespace │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
└──────────────┬──────────────┘
│
┌────────────────────────▼────────────────────────┐
│ SHARED PLATFORM LIB │
│ 8 concerns extracted: arg-parser, output, │
│ env-loader, db-context, dry-run, introspect, │
│ cli-context, types. One implementation each. │
└─────────────────────────────────────────────────┘Outcomes defined. What does the target architecture look like?
Where does effort die?
Current state vs target state. Every "Custom" cell is wasted effort.
VALUE STREAM — Current State (5 independent CLIs) ═════════════════════════════════════════════════ NEW SCRIPT PICK CLI WIRE DEPS FORMAT OUTPUT SHIP ────────── ──────── ───────── ───────────── ──── ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ Which entry │ │ Copy arg │ │ Import DB │ │ Custom │ No │ point? │ │ parser │ │ directly │ │ formatter │ introspection │ │ │ from │ │ (no lint │ │ (JSON? │ for agents │ 5 choices │ │ nearest │ │ blocks) │ │ table??) │ │ no guidance │ │ CLI │ │ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ WASTE: 30-60 min duplicating infrastructure per new command LEAK: Direct DB access drifts from repository layer GAP: Agents can't discover or compose commands VALUE STREAM — Target State (drmg unified binary) ═════════════════════════════════════════════════ NEW COMMAND IMPORT PLATFORM DEFINE SCHEMA REGISTER SHIP ─────────── ─────────────── ───────────── ──────── ──── ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ One entry │ │ Import │ │ Zod schema │ │ Add to │ drmg describe │ point: │ │ CliContext │ │ for args + │ │ router │ auto-discovers │ drmg │ │ from │ │ return │ │ namespace │ new command │ namespace │ │ platform │ │ type │ │ │ │ command │ │ lib │ │ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ RECOVERED: 30-60 min per new command (zero duplication) GAINED: Repository-only DB access, introspection, dry-run, typed output
Value stream mapped. What shared concerns can we extract?
What can we extract?
8 shared concerns across 5 CLIs. Every "Custom" or "Direct" cell is duplication cost. Every "No" is a missing capability.
CAPABILITY MAP — 8 Concerns × 5 CLIs
═════════════════════════════════════
Plan CLI ETL CLI Comms CLI Data CLI Measure CLI
──────── ─────── ───────── ──────── ───────────
Arg parser Custom ✗ Custom ✗ Custom ✗ Custom ✗ Custom ✗
Output Mixed ✗ JSON JSON Table ✗ JSON
Env loader dotenv dotenv dotenv dotenv dotenv
DB context Direct ✗ Direct ✗ Convex ⚠ Direct ✗ Direct ✗
Dry-run No ✗ No ✗ No ✗ No ✗ No ✗
Introspect No ✗ No ✗ No ✗ No ✗ No ✗
CLI context Partial No ✗ No ✗ No ✗ No ✗
Types/schema Partial Zod Zod Drizzle Zod
✗ = duplication cost or missing capability
⚠ = different backend (Convex vs Postgres) — platform lib must handle both
EXTRACTION PRIORITY (highest dividend first)
════════════════════════════════════════════
1. Arg parser — 5 custom implementations → 1 Zod-based parser
2. DB context — 4 direct SQL → 1 repository-only DI container
3. Introspection — 0 of 5 → drmg describe for all commands
4. Dry-run — 0 of 5 → --dry-run flag on mutations
5. Output — 3 inconsistent → 1 format switcher (JSON/table/md)
6. CLI context — 1 partial → 1 typed context for all commands
7. Types — 3 different → 1 shared type system
8. Env loader — already consistent, just extractCapabilities identified. What gets built in what order?
What gets built in what order?
Foundation first, enforcement last. You need somewhere to migrate TO before blocking the old path.
PHASE 1 PHASE 2 PHASE 3 PHASE 4 PHASE 5
Platform Lib Monolith Split CLI Absorption Unified Router Enforcement
──────────── ────────────── ────────────── ────────────── ───────────
#1 Arg parser #9 Lifecycle #14 ETL #18 Router #21 ESLint rule
#2 Output #10 Audit #15 Comms #19 Describe #22 Nx constraints
#3 Env loader #11 Tasks #16 Data #20 Version
#4 DB context #12 Sessions #17 Measure
#5 Dry-run #13 Data/query
#6 CLI context
#7 Introspect
#8 Types
8 rows 5 rows 4 rows 3 rows 2 rows
PROVES: PROVES: PROVES: PROVES: PROVES:
Shared infra works 40+ commands All CLIs share One binary, Boundary
preserved platform lib runtime violations
introspection impossibleQuestions
What does the duplication table tell you about where extraction pays the highest dividend?
- Which shared concern, if extracted first, unblocks the most downstream work?
- Where does the Convex vs Postgres split create a boundary the platform lib must respect?
- If all 22 rows are at Live, what's the next extraction target?