# 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:**
```bash
# 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

```yaml
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:
```yaml
- type: prompt
  prompt: "Your prompt template with {variables}"
  provider: claude
  output_var: response
```

**Code Step** - Runs Python code:
```yaml
- 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:**
```yaml
output_var: processed
```
```python
processed = input.upper()  # This gets captured
```

**Multiple variables (comma-separated):**
```yaml
output_var: processed, count, summary
```
```python
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

```bash
# 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

```bash
# 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`:

```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/`:

```bash
#!/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 (`/\|&;$`"'<>(){}[]!?*#~`)

## Tool Composition

SmartTools are designed to chain together like any Unix command.

### External Pipelines (Tool-to-Tool)

```bash
# Chain multiple SmartTools
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:

```yaml
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

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` |
