---
FrontmatterVersion: 1
DocumentType: Guide
Title: Fathym Command-Line Interface
Summary: CLI for managing Fathym runtimes, scaffolding projects, and operating local workloads.
Created: 2025-11-20
Updated: 2025-11-20
Owners:
- fathym
References:
- Label: Projects: Ref-Arch README
Path: ../README.md
- Label: Projects: Ref-Arch AGENTS
Path: ../AGENTS.md
- Label: Projects: Ref-Arch Guide
Path: ../GUIDE.md
- Label: Root README
Path: ../../../README.md
- Label: Root Agents Guide
Path: ../../../AGENTS.md
- Label: Root Workspace Guide
Path: ../../../WORKSPACE_GUIDE.md
- Label: Project Agents Guide
Path: ./AGENTS.md
- Label: Project Guide
Path: ./GUIDE.md
---
CLI for working with Fathym runtimes and micro-frameworks—covering scaffolding, project management, local development workflows, and operational utilities.
- Goal: deliver a reliable CLI that automates common platform tasks (project setup, environment bootstrap, build/test/deploy flows).
- Outputs: design notes, command reference, release packaging, and sample scripts showing usage across projects.
- Code location:
projects/ref-arch/command-line-interface/(CLI runtime, commands/templates, tests, and runtime scripts).
- CLI runtime, commands, and tests moved here from
@fathym/common; schema emission and runtime scripts live in./scripts. - Depends on
@fathym/commonfor core utilities and@fathym/dfsfor file system abstractions. - Packaging tasks and compile/run helpers defined in
deno.jsonc; adjust for release targets as needed.
- Intent: Productionalize the CLI docs for launch readiness across guides, concepts, and API reference with explicit gap analysis, example QA, and an executable plan.
- Outcome: Added a companion Documentation Production Plan that details remediation tracks, ownership, CI automation, compliance checks, and validation matrices; linked it from the readiness guide and docs index.
- Next Steps: Implement
doc:lint/doc:verifytasks, retrofit troubleshooting and security callouts, publish stability and compatibility matrices, and enforce doc impact summaries inCHANGELOG.mdfor releases.
- Intent: Move beyond planning with a concrete audit of every doc/example to determine accuracy, usability, and compliance for launch.
- Outcome: Published a Documentation Audit Report that inventories each doc area, flags verification gaps, and lists execution-ready fixes (install matrix, compatibility policy, troubleshooting/rollback, runnable snippets, compliance callouts).
- Next Steps: Assign owners per area, capture expected outputs for
prioritized snippets, wire
doc:lint/doc:verifyinto CI, and update guides/API docs with stability and compatibility matrices.
- Intent: Translate the readiness, production plan, and audit into a concrete, file-level execution playbook that can drive the remediation pass.
- Outcome: Added a Documentation Implementation Runbook with sequenced tasks, validation criteria, and ownership to perform the comprehensive docs implementation pass.
- Next Steps: Start at the top of the runbook task board
(install/compatibility), capture real outputs for runnable snippets, and wire
doc:lint/doc:verifyinto CI to gate merges.
- Review the root and portfolio Instruction Documents plus this project’s
AGENTSandGUIDE. - Declare intent before editing; summarize outcomes and open questions in a short log or in this README.
- Capture upstream provenance, release channels, and packaging details in
UPSTREAM.mdonce known. - Keep links relative; reference implementation repos/branches when selected.
- Record prompts or scripts used when designing commands or automations.
The CLI framework includes built-in runtime validation:
- Schema Validation: Args and flags are validated against Zod schemas at runtime (not just help text)
- Complex Type Resolution:
ZodObject/ZodArrayflags automatically resolve from file paths or inline JSON - fileCheck Meta: Control resolution with
.meta({ fileCheck: true/false }) .Validate()Hook: Add custom validation with access toRootValidate()callback
// Complex types auto-resolve from files or inline JSON
const FlagsSchema = z.object({
config: z.object({ host: z.string(), port: z.number() }), // --config ./config.json OR --config '{"host":"x"}'
name: z.string(),
});
Command("deploy", "Deploy application")
.Flags(FlagsSchema)
.Validate(async ({ Params, RootValidate }) => {
const result = await RootValidate();
if (!result.success) return result;
// Custom validation after schema validation
return { success: true };
})
.Run(async ({ Params }) => {
const config = Params.Flag("config"); // Already parsed object!
})
.Build();See docs/api/validation.md for complete documentation.
The CLI framework supports Next.js-style file-based routing with dynamic
segments. This enables commands like cli projects @pkg/name ref where
@pkg/name is captured as a dynamic parameter.
Segment Types:
[param]- Required segment (captures any non-empty value)[[param]]- Optional segment (may be omitted)[...rest]- Rest/catch-all segment (captures one or more values as array)
Directory Structure:
commands/
├── projects/
│ ├── list.ts # cli projects list
│ └── [projectRef]/ # Dynamic segment folder
│ ├── .group.ts # Group metadata for dynamic commands
│ ├── ref.ts # cli projects <projectRef> ref
│ ├── build.ts # cli projects <projectRef> build
│ └── deps/
│ └── update.ts # cli projects <projectRef> deps update
Defining Commands with Segments:
import { z } from "zod";
import { Command, CommandParams } from "@fathym/cli";
// Define segment schema
const SegmentsSchema = z.object({
projectRef: z.string().describe("Project reference (@scope/name or path)"),
});
// Custom params class for typed access
class RefCommandParams
extends CommandParams<[], {}, z.infer<typeof SegmentsSchema>> {
get ProjectRef(): string {
return this.Segment("projectRef") as string;
}
}
export default Command("projects:[projectRef]:ref", "Display project details")
.Segments(SegmentsSchema) // Define expected segments
.Params(RefCommandParams)
.Run(async ({ Params, Segments }) => {
// Access via Params or directly via Segments
console.log(`Project: ${Params.ProjectRef}`);
console.log(`Project: ${Segments.projectRef}`);
return 0;
});Accessing Segments in Commands:
Segments are available in two ways:
- Via
ctx.Segments- Direct access to all extracted values - Via
ctx.Params.Segment('name')- Type-safe access through CommandParams
.Run(async ({ Segments, Params }) => {
// Direct access
const ref = Segments.projectRef;
// Type-safe access (with custom Params class)
const ref2 = Params.Segment('projectRef');
// Rest segments are arrays
const paths = Segments.path; // string[] for [...path]
})Testing Dynamic Commands:
import { CommandIntent, CommandIntentSuite } from "@fathym/cli";
import refCommand from "./[projectRef]/ref.ts";
// Single test with segments
await CommandIntent("resolves project by name", refCommand, import.meta.url)
.Segments({ projectRef: "@fathym/cli" }) // Mock segment value
.ExpectSuccess()
.Run();
// Multiple tests with shared segments
await CommandIntentSuite("ref command", refCommand, import.meta.url)
.Segments({ projectRef: "@fathym/cli" }) // Applied to all tests
.Add("shows project info")
.ExpectSuccess()
.Add("handles missing project")
.Segments({ projectRef: "@nonexistent/pkg" }) // Override for this test
.ExpectFailure()
.Run();Help Output:
Dynamic commands display segments in help output:
📘 Display project details
Usage:
cli projects <projectRef> ref [options]
Segments:
<projectRef> - Project reference (@scope/name or path)
Flags:
--json - Output as JSON
--describe and --plan Output:
Both --describe and --plan flags include segment information:
{
"name": "ref",
"segments": [
{ "name": "projectRef", "type": "required", "description": "Project reference" }
],
"args": [],
"flags": [...]
}See the test-cli examples in test-cli/commands/dynamic/ for working
implementations.
The CLI framework uses a Command Stack pattern with nested middleware execution for runtime orchestration. The stack defines participants (CLIRuntime, GroupRuntime, FlagCommands), but execution follows a middleware pattern where each layer wraps the next.
Key Concepts:
- Runtimes implement CommandStackItem - GroupRuntime and CLIRuntime provide
KeyandWrap()directly - Nested middleware execution - Each
Wrap()returns a CommandModule with$Commandinjected - Builder-first approach - FlagCommands and intent system accept builders, not built modules
- IoC flows from executor - No parent IoC parameter needed in Wrap()
How it works:
// Stack is built from runtimes
const stack = CommandStackBuilder.Build(
cliRuntime,
groupRuntimes,
flagCommands,
);
// Each item wraps the next, creating middleware layers
// CLI → Group → FlagCommand → Command
const executor = new CommandStackExecutor(stack);
await executor.Execute(inputCommand);FlagCommand integration:
FlagCommands remain as builders until wrap time, allowing $Command and
$FlagCommand injection:
// FlagCommands are builders, not built modules
export const HelpFlagCommand = FlagCommand("help", "Show help")
.Run(async ({ Command, FlagCommand }) => {
// $Command and $FlagCommand injected at wrap time
console.log(Command.description);
});
// Note: No .Build() call - stays as builderUnknownCommand handling:
When no command matches, an UnknownCommand executes through the same stack
pattern, ensuring consistent lifecycle hooks and middleware execution.
- Fathym CLI (open-source):
projects/open-source/fathym-clinow hosts theftmcommands/templates/docs. Use@fathym/cliruntime from this repo as the dependency.