You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Julian Noble 0032478e46 G-082 increment 1: activate goal; characterize 0.12.x optional-rejection overflow errors 19 hours ago
.claude agent guardrails: tclsh has no -e one-liner flag - AGENTS.md pitfall entry + claude PreToolUse deny hook 2 days ago
.fossil-custom update .gitignore, .fossil-custom, .fossil-settings 3 years ago
.fossil-settings DOX: ignore-rule changes in one VCS must be mirrored in the other 2 days ago
bin doc: restore 'dev doc.validate' - wrap tcllib dtplite as bin/dtplite.cmd 1 day ago
callbacks Explain callbacks is experimental for shellspy 2 weeks ago
goals G-082 increment 1: activate goal; characterize 0.12.x optional-rejection overflow errors 19 hours ago
scriptlib goals: G-062 achieved archival + archive-loss prevention (sweep rules, backlink markers, goals_lint) 3 days ago
src G-082 increment 1: activate goal; characterize 0.12.x optional-rejection overflow errors 19 hours ago
.gitignore agent guardrails: tclsh has no -e one-liner flag - AGENTS.md pitfall entry + claude PreToolUse deny hook 2 days ago
AGENTS.md DOX: ignore-rule changes in one VCS must be mirrored in the other 2 days ago
CHANGELOG.md CHANGELOG: fill the 0.12.23 gap retrospectively 1 day ago
CLAUDE.md commit conventions VCS-neutral; template DOX/goals ownership design input 1 week ago
GOALS-archive.md G-030 achieved: make.tcl dogfoods punk::args - tabled usage, declared subcommands, -confirm prompt policy 1 day ago
GOALS.md G-082 increment 1: activate goal; characterize 0.12.x optional-rejection overflow errors 19 hours ago
LICENSE.txt goals: G-062 achieved archival + archive-loss prevention (sweep rules, backlink markers, goals_lint) 3 days ago
README.md goals: G-062 achieved archival + archive-loss prevention (sweep rules, backlink markers, goals_lint) 3 days ago
compositing_ansi.png compositing_ansi.png for README.md 2 years ago
getpunk.cmd update multishell scriptsapps 10 months ago
getpunk.cmd.lastrun scriptwrap unix shell fixes 10 months ago
getpunk.ps1 misc scriptapps and file/folder organisation 10 months ago
hype_roysac.png README.md update - + ansi art image with copyleft license courtesy of roysac.com 2 years ago
punk1.ico change project icon 3 years ago
punk1.png change project icon 3 years ago
punk1_transparent.png change project icon 3 years ago
punkproject.toml make.tcl shell under punk exes: recompute tcl_interactive, restore accelerator-forgotten packages 1 day ago
tclint.toml convert tclint.toml to lf lineendings 9 months ago

README.md

punkshell - an alternative Tcl Shell

BSD-2-Clause license (see LICENSE.txt)

Version 0.11.0 (2026-07) — this is alpha level software and still highly experimental. See CHANGELOG.md for recent changes.

Supported Platforms

  • Tcl 8.6+ required; Tcl 9.0 and 9.1 supported.
  • Primary target: Windows (win32-x86_64). Linux, macOS, and FreeBSD are secondary targets.

Getting Started

The project uses a Tcl-based build system (src/make.tcl). From the project root:

# Fetch a suitable Tcl runtime (cross-platform polyglot wrapper — runs from bash, powershell, or cmd.exe)
./bin/runtime.cmd fetch

# Build modules and libraries into the project root
tclsh src/make.tcl packages

# Full build (modules + libraries + VFS + binaries)
tclsh src/make.tcl project

See src/README.md for detailed build instructions and bin/AGENTS.md for the runtime manager.

For evaluating uncommitted source without a full build, a built executable can run directly against the source tree:

<punkexe> src shell

Features

  • default ansi color output - toggle with 'colour on' and 'colour off' (or set NO_COLOR environment variable)
  • convenient and comprehensive in-terminal display of tk, web and terminal ANSI colour names and codes.
  • rendering of old-school Ansi art (cp437) in the terminal Ansi art courtesy of roy-sac.com
  • Relatively easy compositing of text blocks containing Ansi colour codes - (or rendered versions of ansi containing movement and other controls)
    proc welcome_test {} {
        package require textblock
        package require punk::ansi
        package require overtype
        set ansi        [textblock::join -- " " [punk::ansi::ansicat src/testansi/publicdomain/roysac/roy-welc.ans 80x8]]
        # Ansi art courtesy of Carsten Cumbrowski aka Roy/SAC - roysac.com
        set table       [[textblock::spantest] print]
        set punks       [a+ web-lawngreen][>punk . lhs][a]\n\n[a+ rgb#FFFF00][>punk . rhs][a]
        set ipunks      [overtype::renderspace -width [textblock::width $punks] [punk::ansi::enable_inverse]$punks]
        set testblock   [textblock::testblock -size 15 rainbow]
        set contents    $ansi\n[textblock::join -- "  " $table "  " $punks " " $testblock " " $ipunks " " $punks] 
        set framed      [textblock::frame -type arc -title [a+ cyan]Compositing[a] -subtitle [a+ red]ANSI[a] -ansiborder [a+ web-orange] $contents]
    } 

textblock composition of Ansi strings

  • experimental functional/pattern-matching language features. (will not be performant until more work is done on script compilation)
    e.g.1 basic pipeline with 2 segments
    var_pipe_output.= var_list.= list a b c |> string toupper
    e.g.2 basic pattern-match multi-assignment to variables x y & z
    x@0,y@1,z@2.= list a b c equivalently: x@,y@,z@.= list a b c or even x@,y@,z@= {a b c}
    x/0,y/1,z/2,zz/3.= list a b c is similar - but the use of forward-slash instead of @ will not produce a mismatch if an index is out of range.
    where .= indicates following arguments form a command, and a plain = accepts only a single argument as a value
    The diminutive case of this is x= "something" as equivalent to set x "something"
    Assignment operations and pattern-matches are slightly optimised to bytecompile, but are unlikely to compete with raw Tcl commands performance-wise.
    e.g.3 destructuring pattern-match. Get value of key 'k1' from last item in a list of dicts.
    x@end/@@k1.= list {k1 aaa} {k1 bb} returns bbb

    There are many more pattern-matching features yet to be documented.

  • easy execution of externals commands with return of stdout, stderr and the exitcode of the process
    The run... commands use a very basic repl-telemetry system to output more information to the console than just the return value,
    but in a way which makes the return value clear. The telemetry only outputs if the command is the first word on the commandline.

    • run <comand> ...
      (return exitcode of process - and allows process writes to stderr/stdout to appear in console as they occur)
    • runout [-n] <command> ...
      (return stdout of process - no output until completion)
    • runerr [-n] <command> ...
      (return stderr of process - no output until completion)
    • runx [-n] <command> ... (return a dict of stdout stderr exitcode - no output until completion)

    The run... commands attempt to make it clear if a called process outputs a trailing newline by displaying a trailing blank line.
    The optional -n argument can be used to suppress a trailing newline. runout -n pwd is thus similar to Tcl's exec pwd
    For simple cases exec <command> is fine - but the equivalent runout -n <command> when used in the shell will display exitcode and stderr separately (whilst returning only stdout) exec will return stdout and stderr together.
    If you are on a unix-like platform, or a windows platform which has something like msys2 to provide commands like 'which' and 'grep' in the path:
    Try runx -n which grep nonexistant vs exec which grep nonexistant to see the difference in terms of easy access to what was written to stderr vs stdout.
    The run... commands are intended as a supplement for rather than a replacement for Tcl's exec/open.

  • namespace browser (contextual - allowing running of commands within the active namespace - analogous to 'cd' for directories)

    • n/ - display child namespaces of current namespace (alias :/)
      also n/ <globpattern> to restrict output
    • n/ <childns> - if the argument doesn't contain glob chars '*' or '?' - attempt to switch to a child namespace of that name. Analogous to cd <dir>
      list any sub namespaces of the namespace we just switched to.
    • n// - display child namespaces and commands (alias ://)
      with colourised indication of type such as proc,alias,ensemble,oo object,oo class,imported,exported where possible.
      (renamed aliases and builtins and commands loaded from binaries will appear unmarked)
    • nn/ - move up one namespace towards root namespace '::' analogous to cd .. (alias ::/)
    • newns <somename> - create a child namespace called 'somename' and switch to it in one operation. (alias :/new)
  • cross-platform alternative to cd & ls/dir without invoking child processes. Display colourised listing of dirs and folders - with vfs indication.

    • d/ - list current directory (alias ./)
      also d/ <globpattern> to restrict output
    • d/ <subdir> - switch to subdir and list contents in one operation
    • dd/ - move up one directory and output listing. Roughly equivalent to cd .. followed by dir or ls (alias ../)
    • newdir <folder> - create a child directory and switch to it in one operation.
  • <punkexe> script subcommand for reliable non-interactive script execution:

    • punkexe script <file.tcl> ?args? — runs a script file with conventional ::argv0/::argv
    • commands | punkexe script — runs piped stdin commands and exits at EOF (no trailing exit needed)
    • Honest exit codes (0 success, 1 error with errorInfo on stderr); no shellfilter transforms or logging side effects.
    • lib:<name> resolution for scriptlib scripts: punkexe script lib:hello or bare punkexe lib:hello
  • pluggable console backends: the REPL can run against non-detectable terminal-like devices via ::opunk::Console subclasses (ssh-channel, tk-widget, test-double), with size, eof, and capability answered by subclass overrides.

  • cross-platform runtime manager (bin/runtime.cmd): fetch, list, use, and run Tcl runtimes — works from bash, powershell, or cmd.exe. list -remote compares local vs server runtimes with sha1 verification.

  • Ability to create zipfs wrapped applications with all required libraries built in.

  • Additional libraries

    • improved fork of tcllib's imap4 (punk::imap4)
    • netbox client library (punk::netbox)
    • telnet client with support for cp437 e.g can render mapscii.me with mouse support, and can view the ANSI max-headroom movie at 1984.ws
    • A feature-rich argument processor (punk::args) that can be used purely to generate function documentation, or also to process and validate flags and values (punk::args) The argument processor/documentor can display command synopses, grids of applicable argument choices, and indications of when short-forms (prefixes for flags/arguments/values) are applicable. Commands documented with punk::args carry inline usage tables accessible via i <command> at the repl.
    • In-shell help system: i <command> shows documented usage tables; i help lists registered help topics (tcl, env, console, etc.) with per-topic documented usage.

missing

  • raw mode REPL (read-eval-print-loop) to allow commandline completion etc (undergoing development).
  • documentation is incomplete, though the punk::args (PUNKARGS) system now provides inline usage tables and command documentation for many commands via i <command> at the repl.
  • tests coverage is growing but not yet comprehensive — characterization suites exist for punk::args, punk::ns, punk::lib, punk::libunknown, punk::mix, shellthread, shellfilter, and console, among others.
  • signal handling on unix-like platforms (ctrl-c implemented on windows only).

very unripe parts:

  • shellfilter - api is clumsy
  • scriptlib - will likely be reorganised/pruned significantly
  • theming

Documentation

  • src/README.md — detailed build instructions
  • CHANGELOG.md — version history and recent changes
  • AGENTS.md (root) + child AGENTS.md files — contributor guidance and project structure (DOX hierarchy)
  • GOALS.md — technical goal index with per-goal detail files under goals/