# Wasot CLI Vision

## Philosophy

Wasot is a filter. Like `jq` for JSON or `xmllint` for XML, `wasot` transforms structured documents. It reads from stdin or files, writes to stdout or files, and composes with pipes.

```bash
wasot < in.wasot > out.wasot
cat doc.wasot | wasot -t xml | xmllint --format -
wasot -t jsonl doc.wasot | jq -s 'group_by(.type)'
find . -name "*.wasot" | xargs wasot check
```

## Design Principles

1. **Simple over complex** — Easy things should be easy
2. **Discoverable** — `wasot --help` should teach you the tool
3. **Composable** — Works with pipes and standard Unix tools
4. **Predictable** — Same input + same options = same output

## Interface

```
wasot [OPTIONS] [FILE]...        Convert/transform (default)
wasot check [FILE]...            Validate syntax
wasot info [FILE]                Show document statistics
```

If FILE is `-` or omitted, read stdin.

### Convert (default command)

```
wasot [OPTIONS] [FILE]...

OPTIONS:
  -f, --from FORMAT    Input format  [default: auto]
  -t, --to FORMAT      Output format [default: wasot]
  -o, --output FILE    Output file   [default: stdout]
  --select SELECTOR    Filter blocks matching selector

  -q, --quiet          Suppress warnings
  -v, --verbose        Verbose output
  --color WHEN         auto, always, never [default: auto]

  -h, --help           Show help
  -V, --version        Show version
  --completions SHELL  Generate shell completions

FORMATS:
  wasot    Wasot markup (.wasot)
  xml      XML (.xml)
  jsonl    JSON Lines (.jsonl)
  binary   Protobuf binary (.wasotb)
```

### Check (subcommand)

```
wasot check [FILE]...

Validate syntax. Exit 0 if valid, 1 if invalid.
Errors printed to stderr.
```

### Info (subcommand)

```
wasot info [FILE]

Show document statistics: block counts, depth, size.
```

## Option Conventions

Following Click/POSIX conventions:

| Short | Long | Purpose |
|-------|------|---------|
| `-f` | `--from` | Input format |
| `-t` | `--to` | Output format |
| `-o` | `--output` | Output file |
| `-q` | `--quiet` | Suppress warnings |
| `-v` | `--verbose` | Verbose output |
| `-h` | `--help` | Show help |
| `-V` | `--version` | Show version |

Long-only options for less common features:
- `--select SELECTOR` — Filter blocks
- `--color WHEN` — Color control
- `--completions SHELL` — Shell completions

## Exit Codes

```
0    Success
1    Invalid input (parse error, validation failure)
2    I/O error (file not found, permission denied)
3    Invalid arguments (unknown format, bad selector)
```

## Stdout vs Stderr

```
stdout    Converted output, info output, selected blocks
stderr    Errors, warnings, verbose messages
```

## Format Auto-Detection

> **Status: NOT IMPLEMENTED** — Currently requires explicit `-f` flag for non-wasot input

When `-f` is omitted, input format is detected:

**By extension:**
```
.wasot  → wasot
.xml    → xml
.jsonl  → jsonl
.wasotb → binary
```

**By content (for stdin or unknown extension):**

1. Read first ~100 bytes
2. If not valid UTF-8 → `binary`
3. Skip whitespace (spaces, tabs, newlines)
4. Check first non-whitespace character:
   - `.` or `#` or letter → `wasot`
   - `<` → `xml`
   - `{` or `[` → `jsonl`
   - Otherwise → `binary`

**Output format detection:**

When `-t` is omitted but `-o` is given, format is detected from output file extension.

When both `-t` and `-o` are omitted, output is wasot (normalized).

## Examples

### Basic Usage

```bash
# Normalize wasot (parse and re-emit)
wasot doc.wasot

# Convert to XML
wasot doc.wasot -t xml
wasot doc.wasot -o doc.xml          # format from extension

# Convert from binary
wasot -f binary data.wasotb
cat data.wasotb | wasot             # auto-detected (once implemented)

# Roundtrip
wasot doc.wasot -t binary | wasot   # wasot → binary → wasot
```

### Validation

```bash
# Check single file
wasot check doc.wasot && echo "valid"

# Check multiple files
wasot check *.wasot

# In CI
find . -name "*.wasot" -exec wasot check {} +
```

### Filtering with --select

> **Status: NOT IMPLEMENTED** — Selectors exist in wasot-demo but not main binary

```bash
# Extract code blocks as wasot
wasot --select "code-block" doc.wasot

# Extract as JSONL (--select works with -t)
wasot --select "code-block" doc.wasot -t jsonl

# Extract with attribute selector
wasot --select "code-block[lang=rust]" doc.wasot

# Count matches
wasot --select "paragraph" doc.wasot | grep -c "^\\."
```

### Information

> **Status: NOT IMPLEMENTED**

```bash
$ wasot info doc.wasot
blocks: 1234
  document: 1
  section: 45
  paragraph: 892
  code-block: 156
depth: 6
lines: 8456
bytes: 239821
```

### Pipelines

```bash
# Stream to jq
wasot doc.wasot -t jsonl | jq 'select(.type == "code-block")'

# Transform with XSLT
wasot doc.wasot -t xml | xsltproc transform.xsl - > out.html

# Batch conversion
find . -name "*.wasot" | parallel wasot {} -o {.}.xml
```

## Current State vs Vision

### Current (implemented)

```
wasot <COMMAND>

Commands:
  pretty       Normalize wasot
  to-binary    Convert to binary
  to-jsonl     Convert to JSONL
  to-xml       Convert to XML
  to-wasot     Convert to wasot (from markdown/binary)
  completions  Shell completions
```

### Vision (proposed)

```
wasot [FILE]              Normalize/convert (default)
wasot check [FILE]        Validate
wasot info [FILE]         Statistics
```

### Migration

| Current | Proposed |
|---------|----------|
| `wasot pretty doc.wasot` | `wasot doc.wasot` |
| `wasot to-xml doc.wasot` | `wasot doc.wasot -t xml` |
| `wasot to-jsonl doc.wasot` | `wasot doc.wasot -t jsonl` |
| `wasot to-binary doc.wasot` | `wasot doc.wasot -t binary` |
| `wasot to-wasot doc.md` | `wasot doc.md` (auto-detect) |
| `wasot-demo select -s "foo"` | `wasot --select "foo"` |
| (none) | `wasot check` |
| (none) | `wasot info` |

## Implementation Status

| Feature | Status |
|---------|--------|
| Basic conversion (`-t`, `-o`) | ✅ Implemented (as subcommands) |
| Auto-detect from extension | ⚠️ Partial |
| Auto-detect from content | ❌ Not implemented |
| `wasot check` | ❌ Not implemented |
| `wasot info` | ❌ Not implemented |
| `--select` in main binary | ❌ Not implemented (in wasot-demo) |
| `--select` + `-t` combination | ❌ Not implemented |
| Exit codes | ⚠️ Partial |
| SIGPIPE handling | ❌ Not implemented |
| `--color` flag | ❌ Not implemented |

## Non-Goals

- **Watch mode** — Use external tools (entr, watchexec)
- **In-place editing** — Use shell: `wasot f > tmp && mv tmp f`
- **Recursive directory processing** — Use find/xargs/parallel
- **Config files** — Behavior determined entirely by arguments
- **Plugins** — Use pipes to external tools

## Implementation Notes

### SIGPIPE Handling

```rust
// In main.rs, before any output
#[cfg(unix)]
unsafe {
    libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
```

### Color Detection

```rust
fn should_color(choice: ColorChoice, stream: &impl IsTerminal) -> bool {
    match choice {
        ColorChoice::Always => true,
        ColorChoice::Never => false,
        ColorChoice::Auto => {
            stream.is_terminal()
                && std::env::var_os("NO_COLOR").is_none()
                && std::env::var("TERM").map(|t| t != "dumb").unwrap_or(true)
        }
    }
}
```

### Content Sniffing

```rust
fn detect_format(data: &[u8]) -> Option<Format> {
    // Check UTF-8 validity
    let text = std::str::from_utf8(data).ok()?;

    // Skip whitespace to find first meaningful character
    let first_char = text.chars().find(|c| !c.is_whitespace())?;

    match first_char {
        '.' | '#' => Some(Format::Wasot),
        '<' => Some(Format::Xml),
        '{' | '[' => Some(Format::Jsonl),
        c if c.is_alphabetic() => Some(Format::Wasot),
        _ => None, // Fall back to binary
    }
}
```

## Summary

The `wasot` CLI should be:

1. **Simple** — `wasot file.wasot` just works
2. **Discoverable** — Subcommands for distinct modes (check, info)
3. **Composable** — Flags for modifiers (`-t`, `-f`, `-o`, `--select`)
4. **Predictable** — Clear exit codes, stdout/stderr separation

It should feel intuitive to newcomers while remaining powerful for Unix users.
