Clara-CLI.hub Reference
Clara-CLI.hub is a static Next.js application that renders interactive command builders for CLI harnesses. All data lives in data/registry.json — a single JSON file that describes every supported CLI, its commands, and their parameters. No runtime API calls. No backend. No authentication layer.
The playground simulates terminal output locally — no CLI binary is invoked at any point. Output strings are defined per-command in the registry and rendered through a typed colorizer pipeline in components/playground/Terminal.tsx.
Key invariants
Every slug in the registry is globally unique. Command names within a single entry are unique. Parameter flags follow POSIX long-form convention (--flag-name) and must be globally unique within a command. The registry is imported at build time via TypeScript's resolveJsonModule — changes require a rebuild.
Registry Schema
data/registry.json is an array of CLIEntry objects. The file is the single source of truth for all catalog and playground data. Schema follows the TypeScript types defined in lib/types.ts.
Minimal valid entry
{
"slug": "gimp",
"name": "GIMP",
"emoji": "🎨",
"domain": "Image Editing",
"category": "creative",
"command": "cli-anything-gimp",
"testCount": 107,
"commandCount": 38,
"commands": [
{
"name": "project new",
"description": "Create a new GIMP project",
"params": [
{
"flag": "--width",
"label": "Width",
"type": "number",
"required": true,
"defaultValue": "1920",
"placeholder": "e.g. 1920"
}
],
"simulatedOutput": "✓ Created project: poster.json\n size: 1920 × 1080 px"
}
]
}Validation rules
The Vitest suite in __tests__/registry.test.ts enforces these constraints at CI time. Any entry that violates them will cause tests to fail.
✓ slug — kebab-case, globally unique, no spaces
✓ name — human-readable, title-case preferred
✓ emoji — single Unicode emoji (rendered in catalog card)
✓ domain — short descriptor, ≤ 28 chars
✓ category — must be one of the Category union (see Type Reference)
✓ command — the base CLI-Anything binary name, no args
✓ testCount — integer ≥ 0
✓ commandCount — integer ≥ 1 (must have at least one command)
✓ commands — non-empty array; each command has ≥ 0 params
✓ param.flag — POSIX --long-form; unique within parent command
✓ param.type — "string" | "number" | "boolean"
✓ simulatedOutput — newline-separated string; supports colorizer tokensType Reference
All types are defined in lib/types.ts and imported by consumers.
CLIEntry
CLICommand
CLIParam
Category
type Category =
| 'creative' // GIMP, Blender, Inkscape, Audacity
| 'productivity' // LibreOffice, OBS Studio
| 'ai-ml' // Ollama, ComfyUI
| 'data'
| 'network'
| 'communication'
| 'diagramming'Simulation Protocol
The terminal panel renders output through a two-stage pipeline: a timing sequencer inhooks/usePlayground.ts and a line colorizer in components/playground/Terminal.tsx.
Timing sequencer
When the user clicks Run, the hook constructs a synthetic preamble of init lines followed by a hard freeze, then streams the simulatedOutput lines. Total runtime is enforced to a minimum of 7 seconds.
Phase 1 — Command display ~50ms
Phase 2 — Init lines ~420–740ms per line
→ initializing <harness>...
→ runtime loaded · awaiting execution
→ running: <command name>
Phase 3 — FREEZE 2400ms (silent, cursor blinks)
Phase 4 — Output lines ~70–220ms per line
Phase 5 — Completion hold max(0, 7000 - elapsed) msLine colorizer rules
Each line of simulatedOutput is classified by its prefix and rendered in a distinct color. The rules are applied in order — first match wins.
Prefix / pattern CSS class Color
─────────────────────────────────────────────────
Starts with "$" .term-cmd #93c5fd (blue)
Starts with "✓" .term-ok #4ade80 (terminal green)
Starts with " " (2sp) .term-muted #64748b (muted gray)
Starts with "{" .term-json #fbbf24 (amber)
All other lines .term-text #e2e8f0 (off-white)Command assembly
The preview string and the echoed $ command line are assembled by buildCommand() in the hook:
function buildCommand(cli, cmd, params): string {
const parts = [cli.command, cmd.name]
cmd.params.forEach(p => {
const val = params[p.flag] ?? p.defaultValue ?? ''
if (val) parts.push(`${p.flag} "${val}"`)
})
return parts.join(' ')
}
// Example output:
// cli-anything-gimp project new --width "1920" --height "1080" --output "poster.json"Harness Spec
Clara-CLI.hub does not execute any binary. A "harness" in this context is purely a data entry: a structured description of what a real CLI tool can do, enough to assemble valid command strings and display plausible output.
What makes a good harness entry
✓ Cover the most-used 4–8 commands, not all edge cases
✓ Use real flag names from the tool's actual --help output
✓ simulatedOutput should mirror real terminal output format exactly
✓ Required params should have sensible defaultValues
✓ testCount / commandCount should reflect the real harness if known
✗ Do not invent flags that don't exist in the real tool
✗ Do not use abbreviations for flags (--w instead of --width)
✗ Do not include runtime paths or machine-specific valuessimulatedOutput conventions
# Success output (starts with ✓)
✓ Created project: poster.json
size: 1920 × 1080 px
color-mode: RGB
# JSON output (starts with {)
{"status":"ok","file":"poster.json","width":1920}
# Progress lines (leading spaces → muted)
→ loading assets...
→ processing 3 layersExtending the Registry
Add a new CLI
Edit data/registry.json directly. Add a new object to the root array following the schema above. The catalog, filter pills, and playground sidebar update automatically at next build.
# 1. Add your entry to data/registry.json
# 2. Run the test suite — it validates schema integrity
pnpm test
# 3. Start dev server to visually verify
pnpm dev
# 4. Build to confirm no TypeScript errors
pnpm buildAdd a command to an existing CLI
Locate the entry by slug and append to its commands array. The command selector dropdown in the playground populates directly from this array in order — place frequently-used commands first.
Updating testCount / commandCount
These fields are informational badges. They are not derived from the registry itself and must be set manually. If you add commands, increment commandCount.testCount reflects the real upstream harness test suite count if known; otherwise use 0.
Architecture
Data flow
data/registry.json
↓ (static import, resolveJsonModule)
lib/registry.ts → getRegistry(): CLIEntry[]
→ getCLIBySlug(slug): CLIEntry | undefined
↓
app/page.tsx (Server Component — passes clis to CLIGrid)
app/catalog/page.tsx (Server Component — passes clis to CLIGrid)
app/playground/page.tsx (Server Component — passes clis to PlaygroundClient)Component boundaries
Server Components (no 'use client'):
app/layout.tsx Root layout, fonts, metadata
app/page.tsx Landing page shell
app/catalog/page.tsx Catalog page shell
app/playground/page.tsx Suspense wrapper
app/docs/page.tsx Docs shell
Client Components ('use client'):
components/nav/Navbar.tsx Scroll state, active link
components/catalog/CLIGrid.tsx Filter + search state
components/catalog/FilterBar.tsx Category pill state
components/playground/
PlaygroundClient.tsx ?cli= param, layout
SoftwareSidebar.tsx CLI selection
CommandBuilder.tsx Command + param inputs
Terminal.tsx Line colorizer, cursor
hooks/usePlayground.ts All playground state
components/InteractiveBg.tsx rAF mouse + orb parallax
components/TerminalParticles.tsx Canvas scroll particlesRendering strategy
All routes → static export (○)
/ pre-rendered at build time
/catalog pre-rendered at build time
/playground pre-rendered (Suspense boundary for client)
/docs pre-rendered at build time
No dynamic routes. No API routes. No server-side rendering.
ISR is available but unused in Phase 1 (all data is bundled).File size targets
Page First Load JS
─────────────────────────────
/ ~100 kB shared
/catalog +catalog chunk
/playground +playground chunk
/docs +docs chunk
Shared chunk includes: React, Next router, fonts, globals