[go: up one dir, main page]

JBR Vibe Coding with Claude

These are JBR centric, YMMV

Claude Code SKILL.md for Tcl. This is a Markdown doc so we'll just call it code for now

---
name: tcl-scripting
description: Develop Tcl scripts, Tk desktop GUIs, and critcl C extensions. Use when working on .tcl files, writing procs, creating Tk interfaces, binding events, building C extensions, or debugging Tcl errors. Triggers on tcl, tclsh, wish, tk, proc, namespace, critcl, widget, grid, pack, bind, expr, lmap, dict.
allowed-tools:
  - Read
  - Edit
  - Write
  - Grep
  - Glob
  - Bash
---

# Tcl Development

## Core Philosophy

Tcl's power comes from "everything is a string" - but this requires defensive coding:

1. **Security first**: Unbraced `expr` and unquoted command building are injection vectors
2. **Explicit over implicit**: Brace expressions, use `[list]` for commands, namespace your code
3. **Data as code**: Tcl's metaprogramming enables DSLs and introspection - embrace it thoughtfully

## Decision Frameworks

### Quoting: When to Use What
- `{braces}` - Literal text, no substitution, defer evaluation (proc bodies, expr)
- `"quotes"` - Substitution needed but preserve as single word
- `bare` - Simple values only, avoid for user input or complex strings

### Geometry Manager: grid vs pack
- **grid** - Multi-column layouts, forms, tables, alignment matters
- **pack** - Simple stacking, toolbars, single-direction flow

### Pure Tcl vs Critcl Extension
- **Pure Tcl** - Business logic, GUIs, scripting, prototyping
- **Critcl** - System bindings (X11, hardware), performance-critical loops, existing C libraries

### Collection Operations: foreach vs lmap
- **lmap** - Transforming lists (returns new list)
- **foreach** - Side effects, early exit, multiple lists

## Anti-Patterns

- **Unbraced expr**: `expr $x + $y` is slow and dangerous. Attacker-controlled `$x` can execute code. Always `expr {$x + $y}`.

- **String-built commands**: `eval "cmd $arg"` breaks on spaces/special chars. Use `cmd $arg` directly or `{*}[list cmd $arg]`.

- **Global state**: Variables in global namespace collide across packages. Use `namespace eval` with `variable` declarations.

- **Inline bind logic**: `bind .b <1> { complex; multi; line; code }` is unmaintainable. Extract to named procs.

- **Silent catch**: `catch {cmd}` swallows errors invisibly. Always check result: `if {[catch {cmd} err]} { handle $err }`.

- **pack forget/grid forget loops**: Repeatedly hiding/showing widgets is slow. Use `grid remove` to preserve config, or redesign with frames.

## Integration Points

- **Testing**: Structure tests as procs returning boolean. Use tcltest package for larger suites.
- **C extensions**: critcl compiles inline C. Separate concerns: C for computation, Tcl for glue.
- **Shell integration**: Tcl excels at process coordination via `exec`, `open |pipe`, `fileevent`.

## References

- Tcl Manual: https://www.tcl-lang.org/man/
- Tcl Wiki: https://wiki.tcl-lang.org
- critcl: https://andreas-kupries.github.io/critcl/
- Style guide: https://wiki.tcl-lang.org/page/Tcl+Style+Guide

Claude Code tcl-pro SKILL for more depth

---
name: tcl-pro
description: Master Tcl philosophy and advanced idioms. Use when writing idiomatic Tcl, metaprogramming, functional patterns, or optimizing data structure choices. Triggers on EIAS, everything is a string, homoiconic, uplevel, upvar, lmap, fold, K combinator, ensemble, coroutine, functional Tcl, list vs dict vs array.
allowed-tools:
  - Read
  - Edit
  - Write
  - Grep
  - Glob
  - Bash
---

# Tcl Pro: Philosophy and Advanced Idioms

## Core Philosophy

### Everything is a String (EIAS)

Tcl's defining principle: **values have no inherent type**. Interpretation is extrinsic—determined by commands, not the value itself.

```tcl
set x 42
expr {$x + 1}      ;# Interpreted as integer
string length $x   ;# Interpreted as 2-character string
lindex $x 0        ;# Interpreted as single-element list
```

**Key insight**: "8" and the number 8 are the same value. Type is what you *do* with data, not what it *is*.

Internally, Tcl maintains dual representations (string + typed cache) for performance. This is invisible—two identical strings are always equal regardless of internal state.

### Code is Data is Code (Homoiconicity)

Tcl scripts are strings. Strings are data. Therefore code is data, manipulable like any other value.

```tcl
set cmd [list puts "Hello"]
eval $cmd                     ;# Execute string as code
set body [info body myproc]   ;# Introspect procedure body
```

This enables:
- DSL creation via new control structures
- Runtime code generation and modification
- Transparent procedure wrapping (memoization, tracing)

**Anti-pattern**: String concatenation for command building. Use `[list]` to prevent injection and preserve word boundaries.

## Decision Framework: Data Structures

| Need | Use | Why |
|------|-----|-----|
| Sequential data, transformations | **List** | First-class, composable, `lmap`/`foreach` friendly |
| Key-value, pass to procs | **Dict** | First-class value, nestable, preserves order |
| Mutable shared state | **Array** | Never copied, pass by name (`upvar`) |
| Set operations | **List + array index** | `array set` for O(1) membership |

### Lists as Primary Workhorse

Lists handle 80% of collection needs. Prefer flat structures:

```tcl
# Good: flat list, simple operations
set points {10 20 30 40 50 60}
foreach {x y} $points { ... }

# Avoid: premature nesting
set points {{10 20} {30 40} {50 60}}
```

### When Arrays Beat Dicts

Arrays excel for large mutable datasets:

```tcl
# Array: no copy on modification
proc update {arrName key val} {
    upvar $arrName arr
    set arr($key) $val    ;# In-place mutation
}

# Dict: copies on write when shared
proc update {dictVar key val} {
    upvar $dictVar d
    dict set d $key $val  ;# May copy entire dict
}
```

**Rule of thumb**: Dicts for data exchange, arrays for stateful engines.

## Key Patterns

### The K Combinator

Return first argument, discard second. Enables single-expression state changes:

```tcl
proc K {x y} { set x }

# Shift: remove and return first element
proc shift {listVar} {
    upvar $listVar lst
    K [lindex $lst 0] [set lst [lrange [K $lst [unset lst]] 1 end]]
}
```

### Functional Idioms

```tcl
# Fold (reduce)
proc foldl {func acc lst} {
    foreach item $lst { set acc [{*}$func $acc $item] }
    set acc
}

# Filter
proc pick {func lst} {
    set ret {}
    foreach item $lst {
        if {[{*}$func $item]} { lappend ret $item }
    }
    set ret
}

# Use lmap for transforms (Tcl 8.6+)
lmap x $nums { expr {$x * 2} }
```

### Memoization via Proc Wrapping

```tcl
proc memo {procName} {
    rename $procName _$procName
    proc $procName args [subst -nocommands {
        variable _cache_${procName}
        if {[info exists _cache_${procName}(\$args)]} {
            return [set _cache_${procName}(\$args)]
        }
        set _cache_${procName}(\$args) [_${procName} {*}\$args]
    }]
}
```

### Ensemble Extension

Add subcommands to existing ensembles:

```tcl
proc ::tcl::dict::get? {args} {
    try { dict get {*}$args } on error {} { return {} }
}
namespace ensemble configure dict -map \
    [dict merge [namespace ensemble configure dict -map] \
        {get? ::tcl::dict::get?}]

# Now: dict get? $d key  ;# Returns {} on missing key
```

### The Filter Idiom (Suchenwirth)

Unix-style composable scripts:

```tcl
proc filter {chan} {
    while {[gets $chan line] >= 0} {
        # Process line, puts to stdout
    }
}

if {$argc == 0} {
    filter stdin
} else {
    foreach file $argv {
        set f [open $file]
        filter $f
        close $f
    }
}
```

### Iterator Pattern with Coroutines

```tcl
proc iterator {name args body} {
    proc $name $args [subst {
        yield
        $body
        return -code break
    }]
}

iterator iota {n} {
    for {set i 0} {$i < $n} {incr i} { yield $i }
}

coroutine gen iota 5
while {[set v [gen]] ne ""} { puts $v }
```

## Metaprogramming Techniques

### uplevel and upvar

- `upvar`: Create local alias to caller's variable
- `uplevel`: Execute code in caller's scope

```tcl
proc with {varName value body} {
    upvar $varName v
    set old $v
    set v $value
    try {
        uplevel 1 $body
    } finally {
        set v $old
    }
}
```

### Code Generation

Build commands safely with `list`, execute with `{*}`:

```tcl
# Safe: list preserves word boundaries
set cmd [list exec grep $pattern $file]
{*}$cmd

# Dangerous: string interpolation
eval "exec grep $pattern $file"  ;# Injection risk
```

## Anti-Patterns

- **Unbraced expr**: `expr $x + $y` parses at runtime, allows injection. Always `expr {$x + $y}`.

  **Exception — Expression-as-String APIs**: Intentionally unbraced `expr` enables flexible APIs where callers pass string expressions:

  ```tcl
  proc iota {fr {to {}}} {
      set fr [expr $fr]  ;# Unbraced: allows "iota 0 $n+1"
      set to [expr $to]  ;# Caller's "$n+1" evaluated here
      for {set r {}} {$fr < $to} {incr fr} {lappend r $fr}
      set r
  }
  iota 0 $count+1  ;# Works because expr evaluates the string
  ```

  Use this pattern deliberately in utility APIs where flexibility outweighs the (minimal) performance cost. Keep internal arithmetic braced.

- **eval with string building**: Use `{*}[list ...]` or direct invocation instead.

- **Overusing dict/array**: Simple lists suffice for most sequential data. "Even O(N²) may be ok, for sufficiently small N." —RS

- **Deep nesting**: Flat structures are more Tcl-idiomatic. Two lists often beat one nested list.

- **Ignoring dual-porting**: Switching between string and list interpretations causes "shimmering". Keep values in consistent interpretation when performance matters.

## Suchenwirth's Wisdom

- "A good proc fits between thumb and middle finger" — keep procedures concise
- "My spirit is: if a wheel is easier reinvented than reading its documentation, don't use that wheel"
- Tcl's "Play-Doh-like flexibility" permits infix, prefix, and circumfix notations

## References

- [Everything is a String](https://wiki.tcl-lang.org/page/everything+is+a+string)
- [Homoiconic](https://wiki.tcl-lang.org/page/homoiconic)
- [Meta Programming](https://wiki.tcl-lang.org/page/Meta+Programming)
- [Richard Suchenwirth](https://wiki.tcl-lang.org/page/Richard+Suchenwirth)
- [Dict VS Array Speed](https://wiki.tcl-lang.org/page/Dict+VS+Array+Speed)
- [The filter idiom](https://wiki.tcl-lang.org/page/The+filter+idiom)

gold 01/20/2026. Added categories, so can find message in Wiki.