smarttools/docs/DESIGN.md

12 KiB

SmartTools - Design Document

A lightweight personal tool builder for AI-powered CLI commands

Overview

SmartTools 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

~/.smarttools/
  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}"

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

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

# See what prompt gets sent
sum -i document.txt --show-prompt

# Test with mock (no API call)
sum -i document.txt --provider mock

# Read from stdin, write to stdout
cat doc.txt | sum | less

# Interactive stdin input
sum --stdin

# No input (empty string) - useful for tools using only arguments
sum --max 100

# Or via smarttools run
smarttools 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

# Launch the UI to manage tools
smarttools

# Or use CLI directly:
smarttools list              # List all tools
smarttools create sum        # Create new tool (basic)
smarttools edit sum          # Edit tool config in $EDITOR
smarttools delete sum        # Delete tool
smarttools test sum          # Test with mock provider
smarttools run sum           # Run tool for real
smarttools refresh           # Refresh all wrapper scripts
smarttools ui                # Launch interactive UI

Terminal UI

A BIOS-style terminal UI using urwid with full mouse support.

Main Menu

┌──────────────────────────────────────┐
│         SmartTools Manager           │
├──────────────────────────────────────┤
│  Tools:                              │
│  ┌────────────────────────────────┐  │
│  │  sum                           │  │
│  │  reviewer                      │  │
│  │  translator                    │  │
│  └────────────────────────────────┘  │
│                                      │
│  [Create] [Edit] [Delete] [Test]     │
│                                      │
│  Tool Info:                          │
│  Name: sum                           │
│  Description: Summarize documents    │
│  Arguments: --max                    │
│  Steps: PROMPT[claude] -> {response} │
│                                      │
│              [EXIT]                  │
└──────────────────────────────────────┘

Tool Builder

┌──────────────────────────────────────────────────────────────┐
│                        New Tool                              │
├──────────────────────────────────────────────────────────────┤
│ ┌─[ Tool Info ]──────────┐ ┌─ Arguments ─────────────────┐   │
│ │ Name: [sum__________]  │ │  --max -> {max}             │   │
│ │                        │ │                             │   │
│ │ Desc: [Summarize____]  │ └─────────────────────────────┘   │
│ │                        │ [Add] [Edit] [Delete]             │
│ │ Output: [{response}_]  │                                   │
│ └────────────────────────┘ ┌─ Execution Steps ───────────┐   │
│                            │  P:claude -> {response}     │   │
│                            │                             │   │
│                            └─────────────────────────────┘   │
│                            [Add] [Edit] [Delete]             │
│                                                              │
│                    [Save]  [Cancel]                          │
└──────────────────────────────────────────────────────────────┘

Navigation:

  • Tab - Cycle between sections (Tool Info -> Arguments -> Steps -> Buttons)
  • Arrow keys - Navigate within lists
  • Enter/Click - Select/activate
  • Escape - Cancel/back
  • Shift + mouse - Terminal-native text selection (bypasses UI mouse handling)
  • Ctrl+Shift+V - Paste

The current section's title is highlighted with brackets: [ Tool Info ]

Copy/Paste tip: Hold Shift while dragging with mouse to select text, then use your terminal's copy function (usually right-click or Ctrl+Shift+C).

Code Step Dialog

┌──────────────── Add Code Step ─────────────────┐
│ Variables: input, max, response                │
│                                                │
│ File: [processed.py______________] < Load >    │
│                                                │
│ ┌─ Code ─────────────────────────────────────┐ │
│ │processed = input.upper()                   │ │
│ │count = len(processed.split())              │ │
│ │                                            │ │
│ └────────────────────────────────────────────┘ │
│                                                │
│ Output var: [processed, count____]             │
├────────────────────────────────────────────────┤
│               < OK >   < Cancel >              │
└────────────────────────────────────────────────┘

Code Step Features:

  • Multiline editor - Write multi-line Python code
  • External file storage - Code is auto-saved to ~/.smarttools/<toolname>/<filename> on OK
  • Load button - Load code from external file (with confirmation)
  • Multiple output vars - Capture multiple variables (comma-separated)

Implementation

Directory Structure

smarttools/
  __init__.py
  cli.py           # Entry point, argument parsing
  ui.py            # UI dispatcher (chooses urwid/snack/dialog)
  ui_urwid.py      # Urwid-based BIOS-style UI
  ui_snack.py      # Snack/newt fallback UI
  tool.py          # Tool loading/saving/wrapper scripts
  runner.py        # Execute tools
  providers.py     # Provider abstraction

Provider System

Providers are defined in ~/.smarttools/providers.yaml:

providers:
  - name: claude
    command: "claude -p"
    description: "Anthropic Claude"
  - name: codex
    command: "codex -p"
    description: "OpenAI Codex"
  - name: gemini
    command: "gemini"
    description: "Google Gemini"

The provider command receives the prompt via stdin and outputs to stdout.

Wrapper Scripts

When you save a tool, SmartTools creates a wrapper script in ~/.local/bin/:

#!/bin/bash
# SmartTools wrapper for 'sum'
# Auto-generated - do not edit
exec /path/to/python -m smarttools.runner sum "$@"

The wrapper uses the full Python path to ensure the correct environment is used.

Use smarttools refresh to regenerate all wrapper scripts (e.g., after changing Python environments).

Tool Name Validation

Tool names must:

  • Start with a letter or underscore
  • Contain only letters, numbers, underscores, and dashes
  • Not contain spaces or shell-problematic characters (/\|&;$"'<>(){}[]!?*#~`)

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

  1. Run smarttools to open UI
  2. Select "Create" to create a new tool
  3. Fill in: name, description, output template
  4. Add arguments (e.g., --max with default 500)
  5. Add a prompt step with your prompt template and provider
  6. Click "Save"
  7. Exit UI
  8. Run sum -i myfile.txt -o summary.txt

Done. No containers, no signing, no certification. Just a tool that works.

Default Values

Step Type Default Output Var Default File
Prompt response n/a
Code processed processed.py