Skip to main content

CmdForge Architecture

Module Structure

src/cmdforge/
├── cli/ # CLI commands
│ ├── __init__.py
│ ├── tool_commands.py # list, create, edit, delete
│ ├── provider_commands.py # providers management
│ ├── registry_commands.py # publish, install
│ └── collections_commands.py # collections list, info, install
├── registry/ # Registry API
│ ├── app.py # Flask API endpoints
│ ├── db.py # SQLite schema and queries
│ ├── sync.py # Git repo sync
│ └── rate_limit.py
├── web/ # Web UI (cmdforge.brrd.tech)
│ ├── app.py # Flask app factory
│ ├── routes.py # Page routes
│ ├── auth.py # User authentication
│ ├── forum/ # Forum feature
│ ├── templates/ # Jinja2 templates
│ └── static/ # CSS, JS
├── gui/ # Desktop GUI (PySide6)
│ ├── __init__.py # Entry point, run_gui()
│ ├── main_window.py # Main window with sidebar
│ ├── styles.py # QSS stylesheet
│ ├── pages/ # Application pages
│ │ ├── tools_page.py # Tool list and details
│ │ ├── tool_builder_page.py # Create/edit tools
│ │ ├── registry_page.py # Browse/install tools
│ │ └── providers_page.py # Provider management
│ └── dialogs/ # Modal dialogs
│ ├── step_dialog.py # Prompt/code step editors
│ ├── argument_dialog.py
│ ├── provider_dialog.py
│ ├── connect_dialog.py # Registry connect
│ └── publish_dialog.py
├── tool.py # Tool dataclass and loading
├── runner.py # Tool execution engine
└── providers.py # AI provider abstraction

Data Flow

CLI Tool Execution

User Input (stdin)


┌─────────────┐
│ runner.py │ ──── Loads tool from ~/.cmdforge/<name>/config.yaml
└─────────────┘


┌─────────────┐
│ Steps │
│ (prompt/ │ ──── For prompt steps, calls providers.py
│ code) │ ──── For code steps, exec() Python
└─────────────┘


Output (stdout)

Web UI Request Flow

Browser Request


┌─────────────────┐
│ Cloudflare │ ──── HTTPS termination
└─────────────────┘


┌─────────────────┐
│ Flask :5050 │ ──── web/app.py
└─────────────────┘

├──── /api/* → registry/app.py (API)
└──── /* → web/routes.py (Pages)


┌─────────────┐
│ SQLite DB │
└─────────────┘

Key Classes

Tool (tool.py)

@dataclass
class Tool:
name: str
description: str
category: str
arguments: List[ToolArgument]
steps: List[Step] # PromptStep | CodeStep | ToolStep
output: str
dependencies: List[str]
source: Optional[ToolSource] # Attribution for imports
version: str

ToolSource (tool.py)

@dataclass
class ToolSource:
type: str # "original", "imported", "forked"
license: str
url: str
author: str
original_tool: str # e.g., "fabric/patterns/extract_wisdom"

Provider (providers.py)

@dataclass
class Provider:
name: str # e.g., "opencode-pickle"
command: str # e.g., "$HOME/.opencode/bin/opencode run --model ..."
description: str

Error Handling

The runner provides detailed error messages for debugging:

Code Step Errors

When Python code fails in a code step, shows:

  • Step number and error type
  • Offending line with context (line before/after)
  • Visual pointer (>>>) to error line
  • List of available variables
Error in code step (step 2):
NameError: name 'undefined_var' is not defined

1: data = input.split('\n')
>>> 2: result = undefined_var + data
3: output = result

Available variables: ['input', 'max_size', 'step1_output']

YAML Syntax Errors

When a tool's config.yaml has syntax errors:

  • Line and column number
  • Visual pointer to exact position
  • Context line above
Error loading tool 'my-tool': YAML syntax error
Line 15, column 8

14: steps:
> 15: - type prompt # missing colon
^
Problem: expected ',' or ']'

Nested Tool Errors

When a tool calls another tool that fails, shows the full call stack:

Error in tool chain:
my-wrapper (step 2)
-> summarize (step 1)
-> Tool 'missing-tool' not found

Registry Database

SQLite schema for published tools:

CREATE TABLE tools (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
category TEXT DEFAULT 'Other',
config_yaml TEXT NOT NULL, -- Full tool YAML
source TEXT, -- Deprecated (type only)
source_url TEXT, -- Deprecated
source_json TEXT, -- Full ToolSource as JSON
published_at TIMESTAMP,
downloads INTEGER DEFAULT 0,
owner_id INTEGER REFERENCES users(id)
);

The source_json column stores the complete ToolSource object, preserving all attribution fields when tools are published.

Configuration Files

FileLocationPurpose
Tool config~/.cmdforge/<name>/config.yamlTool definition
Providers~/.cmdforge/providers.yamlAI provider commands
Main config~/.cmdforge/config.yamlRegistry URL, client ID