CmdForge Design Document
A lightweight personal tool builder for AI-powered CLI commands
Overview
CmdForge lets you create custom AI-powered terminal commands. You define a tool once (name, steps, provider), then use it like any Linux command.
Example:
# Create a summarizer tool, then use it:
sum -i text.txt -o summary.txt --max 512
Core Concepts
Tool = Directory + Config
~/.cmdforge/
sum/
config.yaml
processed.py # Optional external code file
reviewer/
config.yaml
translator/
config.yaml
config.yaml Format
name: sum
description: "Summarize documents"
arguments:
- flag: --max
variable: max
default: "500"
description: "Maximum words in summary"
steps:
- type: prompt
prompt: |
Summarize the following text in {max} words or less:
{input}
provider: claude
output_var: response
output: "{response}"
# Optional: declare dependencies for meta-tools
dependencies:
- official/summarize
- official/translate@^1.0.0 # With version constraint
Step Types
Prompt Step - Calls an AI provider:
- type: prompt
prompt: "Your prompt template with {variables}"
provider: claude
output_var: response
Code Step - Runs Python code:
- type: code
code: |
processed = input.upper()
count = len(processed.split())
output_var: processed, count
code_file: processed.py # Optional: external file storage
Tool Step - Calls another CmdForge tool (meta-tools):
- type: tool
tool: official/summarize # Tool reference (owner/name or just name for local)
input: "{input}" # Input to pass (supports variable substitution)
args: # Optional arguments
max_words: "100"
output_var: summary # Variable to store the tool's output
provider: claude # Optional: override the called tool's provider
Steps execute in order. Each step's output_var becomes available to subsequent steps.
Variables
{input}- Always available, contains stdin or input file content (empty string if no input){variable_name}- From arguments (e.g.,{max}){output_var}- From previous steps (e.g.,{response},{processed})
Output Variables
The output_var field specifies which Python variable(s) to capture from your code:
Single variable:
output_var: processed
processed = input.upper() # This gets captured
Multiple variables (comma-separated):
output_var: processed, count, summary
processed = input.upper()
count = len(processed.split())
summary = f"Processed {count} words"
# All three are captured and available as {processed}, {count}, {summary}
CLI Interface
Running Tools
# Basic usage (wrapper script in ~/.local/bin)
sum -i document.txt -o summary.txt
# With custom args
sum -i document.txt --max 200
# Preview prompt without calling AI
sum -i document.txt --dry-run
# Test with mock (no API call)
sum -i document.txt --provider mock
# Read from stdin, write to stdout
cat doc.txt | sum | less
# Or via cmdforge run
cmdforge run sum -i document.txt
Input Handling
| Scenario | Behavior |
|---|---|
| Piped stdin | Automatically read (cat file.txt | mytool) |
-i file.txt | Read from file |
--stdin | Interactive input (type then Ctrl+D) |
| No input | Empty string (useful for argument-only tools) |
Universal Flags (all tools)
| Flag | Short | Description |
|---|---|---|
--input | -i | Input file |
--output | -o | Output file (or stdout if omitted) |
--stdin | Read input interactively (type then Ctrl+D) | |
--dry-run | Show prompt, don't call AI | |
--show-prompt | Call AI but also print prompt to stderr | |
--provider | -p | Override provider (e.g., --provider mock) |
--verbose | -v | Show debug info |
--help | -h | Show help |
Managing Tools
cmdforge list # List all tools
cmdforge create sum # Create new tool (basic)
cmdforge edit sum # Edit tool config in $EDITOR
cmdforge delete sum # Delete tool
cmdforge test sum # Test with mock provider
cmdforge run sum # Run tool for real
cmdforge refresh # Refresh all wrapper scripts
cmdforge check sum # Check dependencies for meta-tools
cmdforge ui # Launch interactive UI
Tool Composition
CmdForge tools are designed to chain together like any Unix command.
External Pipelines (Tool-to-Tool)
# Chain multiple CmdForge tools
cat logs.txt | log-errors | summarize | translate --lang Japanese
# Mix with standard Unix tools
git log --oneline | head -20 | changelog | tee CHANGELOG.md
# Build complex workflows
cat *.py | review-code --focus security | json-extract --fields "issue, severity, file" | json2csv
Each tool reads stdin and writes stdout. No special integration needed.
Internal Pipelines (Multi-Step)
Within a single tool, chain steps for preprocessing/validation:
steps:
- type: code # Preprocess
code: |
filtered = '\n'.join(l for l in input.split('\n') if 'ERROR' in l)
output_var: filtered
- type: prompt # AI processes filtered input
prompt: "Explain these errors: {filtered}"
provider: claude-haiku
output_var: explanation
- type: code # Post-process
code: |
result = f"Found {len(filtered.split(chr(10)))} errors:\n\n{explanation}"
output_var: result
output: "{result}"
When to use which:
- External pipelines: Reusable tools, different providers per stage, standard Unix interop
- Internal pipelines: Tightly coupled steps, shared context, validation of AI output
What This Design Doesn't Include
Intentionally omitted (not needed for personal use):
- Trust tiers / security levels
- Cryptographic signing
- Container isolation / sandboxing
- Certification testing
- Distribution packaging
- PII redaction
- Audit logging
- Provider capability negotiation
Why? This is a personal tool builder. You write the tools, you run the tools, you accept the responsibility. Just like any bash script you write.
Dependencies
Required:
- Python 3.10+
- PyYAML
- urwid (for TUI)
Optional fallbacks:
- python3-newt/snack (simpler TUI)
- dialog/whiptail (basic TUI)
Example Workflow
- Run
cmdforgeto open UI - Select "Create" to create a new tool
- Fill in: name, description, output template
- Add arguments (e.g.,
--maxwith default500) - Add a prompt step with your prompt template and provider
- Click "Save"
- Exit UI
- Run
sum -i myfile.txt -o summary.txt
Done. No containers, no signing, no certification. Just a tool that works.