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.
 
 
 
 
 
 

26 KiB

DOX framework

  • DOX is highly performant AGENTS.md hierarchy installed here
  • Agent must follow DOX instructions across any edits

Core Contract

  • AGENTS.md files are binding work contracts for their subtrees
  • Work products, source materials, instructions, records, assets, and durable docs must stay understandable from the nearest applicable AGENTS.md plus every parent AGENTS.md above it

Read Before Editing

  1. Read the root AGENTS.md
  2. Identify every file or folder you expect to touch
  3. Walk from the repository root to each target path
  4. Read every AGENTS.md found along each route
  5. If a parent AGENTS.md lists a child AGENTS.md whose scope contains the path, read that child and continue from there
  6. Use the nearest AGENTS.md as the local contract and parent docs for repo-wide rules
  7. If docs conflict, the closer doc controls local work details, but no child doc may weaken DOX

Do not rely on memory. Re-read the applicable DOX chain in the current session before editing.

Update After Editing

Every meaningful change requires a DOX pass before the task is done.

Update the closest owning AGENTS.md when a change affects:

  • purpose, scope, ownership, or responsibilities
  • durable structure, contracts, workflows, or operating rules
  • required inputs, outputs, permissions, constraints, side effects, or artifacts
  • user preferences about behavior, communication, process, organization, or quality
  • AGENTS.md creation, deletion, move, rename, or index contents

Update parent docs when parent-level structure, ownership, workflow, or child index changes. Update child docs when parent changes alter local rules. Remove stale or contradictory text immediately. Small edits that do not change behavior or contracts may leave docs unchanged, but the DOX pass still must happen.

Hierarchy

  • Root AGENTS.md is the DOX rail: project-wide instructions, global preferences, durable workflow rules, and the top-level Child DOX Index
  • Child AGENTS.md files own domain-specific instructions and their own Child DOX Index
  • Each parent explains what its direct children cover and what stays owned by the parent
  • The closer a doc is to the work, the more specific and practical it must be

Child Doc Shape

  • Create a child AGENTS.md when a folder becomes a durable boundary with its own purpose, rules, responsibilities, workflow, materials, or quality standards
  • Work Guidance must reflect the current standards of the project or user instructions; if there are no specific standards or instructions yet, leave it empty
  • Verification must reflect an existing check; if no verification framework exists yet, leave it empty and update it when one exists

Default section order:

  • Purpose
  • Ownership
  • Local Contracts
  • Work Guidance
  • Verification
  • Child DOX Index

Style

  • Keep docs concise, current, and operational
  • Document stable contracts, not diary entries
  • Put broad rules in parent docs and concrete details in child docs
  • Prefer direct bullets with explicit names
  • Do not duplicate rules across many files unless each scope needs a local version
  • Delete stale notes instead of explaining history
  • Trim obvious statements, repeated rules, misplaced detail, and warnings for risks that no longer exist

Closeout

  1. Re-check changed paths against the DOX chain
  2. Update nearest owning docs and any affected parents or children
  3. Refresh every affected Child DOX Index
  4. Remove stale or contradictory text
  5. Run existing verification when relevant
  6. Report any docs intentionally left unchanged and why

User Preferences

When the user requests a durable behavior change, record it here or in the relevant child AGENTS.md

Child DOX Index

This project is not yet indexed. Before continuing you must scan the project, build the DOX tree and replace this message with the actual index. Go deep and scan files recursively to properly evaluate complexity and create nested DOX files where needed.

AGENTS.md

Agent handbook for the ShellSpy (Punk Shell) repository. These guidelines cover builds, linting, testing, code style, and day-to-day conventions for all contributors and agentic assistants. Always check for nested AGENTS.md files before editing subdirectories. This root spec applies repo-wide unless overridden deeper in the tree.

if conflict with CLAUDE.md, AGENTS.md wins.

Quickstart Checklist

  • Confirm Windows-friendly Tcl toolchain (8.6+ required, 9.0 supported).
  • Run tclsh src/make.tcl packages once after cloning to populate generated assets.
  • Keep edits within the scoped instructions of any nested AGENTS.md.
  • Use tclint before submitting code to align formatting and structure for any new agent-produced code, but do not use it to reformat existing code.
  • Execute at least one relevant test script (tclsh src/tests/<path>/<file>.tcl).
  • Document changes impacting build, tooling, or developer workflow.

Build & Bootstrap Commands

  • Primary build: tclsh make.tcl project (Windows default) or punk902z make.tcl project inside Punk shell.
  • Clean/resync: Remove _build/ artifacts then rerun tclsh make.tcl project; avoid partial cleans that break boot modules. Cleaning _build is generally not required.
  • Binary images: Use punk make.tcl project to produce punk binaries. There are no platform-specific flags for cross-platform building - it must currently be done on each specific platform. The Tcl modules and libs are mostly cross-platform by nature, but the built binaries rely on platform specific runtimes and some binary packages from whichever src/vfs/*.vfs folder was used to build.

Testing Strategy

  • Test location: src/tests/ holds all Tcl test scripts; keep new tests there, named with the .test file extension.
  • Run entire suite: Run base src/tests/runtests.tcl or Iterate with something like for /r src\tests %f in (*.tcl) do tclsh %f (Windows) or a similar shell loop on POSIX.
  • Run single test: tclsh src/tests/<path>/<script>.tcl (e.g., tclsh src/tests/modules/opunk/str/tests/all.tcl).
  • Focused verification: Mirror production pipelines inside tests using Punk pipeline syntax for parity.
  • Test dependencies: Every test must package require punk; declare extra packages explicitly to avoid hidden dependencies.
  • Failure triage: Capture stderr logs; prefer try/on error blocks inside tests for clearer diagnostics.

Linting & Formatting

  • Command: N/A - tclint is currently only available as a plugin in vscode (configured via tclint.toml in repo root).
  • Files covered: .tcl, .tm extend config if new extensions appear.
  • Line length: Hard cap at 400 characters; wrap pipelines thoughtfully instead of exceeding.
  • Blank lines: No more than 10 consecutive blanks.
  • Indentation: 4 spaces; tabs are disallowed in Tcl sources except inside string literals.

Toolchain & Dependencies

  • Prefer the provided vendor modules under src/vendor* before fetching new dependencies.
  • Use tcl::tm::path add <dir> to surface project modules when writing new tooling.
  • Keep compatibility with Tcl 8.6+; gate 9.0-specific features behind version checks, or use existing punk::lib::compat functions.
  • When optional compiled extensions (e.g., twapi, tdom) are necessary, guard package require calls with fallback messaging.

Repository Layout Primer

modules/                    # Target module folder for when `tclsh src/make.tcl modules` is run. Agents should not directly modify.
lib/                        # Target library folder for when `tclsh src/make.tcl libs` is run. Agents should not directly modify.
src/
  bootsupport/modules/      # Early-load modules with minimal deps. These are analogous to npm devDependencies. Agents should not directly modify.
  modules/                  # Main Punk modules (.tm) - most development for punkshell is in this section.
  modules/test              # Hierarchy for unit tests that have been bundled into .tm module-based test packages with module name portion beginning with 'test' namespace/folder matching the namespace/folder of the module to be tested. Agents should generally not update this area aside from updating versions as necessary in <modulename>-buildversion.txt files, as it is generated from src/tests or manually updated by the user. Running these tests, tests the installed module/library state (that acheived after running `tclsh src/make.tcl packages|modules|lib`)
  modules_tcl8/             # Tcl8 specific modules (.tm)
  modules_tcl9/             # Tcl9 specific modules (.tm)
  lib/                      # Tcl version-independent pkgIndex.tcl-based libraries
  lib_tcl8/                 # Tcl8 specific pgkIndex.tcl-based libraries
  lib_tcl9/                 # Tcl9 specific pgkIndex.tcl-based libraries
  runtime/                  # Location of mapvfs.config which determines which src/vfs/*.vfs folders are mapped with which runtime executable.
  scriptapps/               # Entry-point scripts for Punk apps
  testansi/                 # sample files for punk::ansi features. Agents should not modify.
  vendormodules/            # Third-party modules bundled with repo. .tm files are either manually placed here or refreshed based on include_modules.config using `tclsh src/make.tcl vendorupdate`. 
  tests/                    # Unit tests (using the tcltest package) - these are designed to run against the modules in the src hierarchy. ie prior to installation.
  vfs/                      # Virtual file system images for builds - *.vfs folders are currently manually updated by the user, not Agent modified.
  vfs/_config/              # Entry point .tcl files for executables built from the *.vfs folders.
  vfs/_vfscommon.vfs        # Common libraries to be integrated into vfs during executable building. These are completley refreshed by running `tclsh src/make.tcl vfscommonupdate` - not modified directly by user or agents.
scriptlib/                  # Shared utilities + manual tests. Updated by user only unless explicit request made for agent to modify.
bin/                        # Helper binaries/scripts. Target for built punk binaries made from bin/runtime/<platform>/*.exe files and associated src/vfs/*.vfs folders. Agents should not modify.
bin/runtime/*               # Immediate subfolders are named for the target platform. These are where specific pre-built runtimes are installed by the bin/runtime.cmd helper script (or manually). Agents should not modify.
callbacks/                  # Experimental features for when punkshell is launched with the "shellspy" parameter. Agents should not modify.

Treat VFS directories as generated artifacts; edit them only when updating runtime payloads.

File Resolution Policy

Use the strongest available anchor first and do not broaden scope until that anchor is checked.

Anchor Order

  1. Exact path named by the user.
  2. Active editor file, when the environment provides one.
  3. Exact proc, symbol, or identifier named by the user.
  4. Repository naming and source-precedence rules.

Do not skip a stronger anchor for a weaker one.

Source Priority

  • For editable Punk module source, prefer src/modules/.
  • Source module filenames use the literal suffix -999999.0a1.0.tm.
  • Do not shorten or normalize that suffix.
  • For editable Tcl library source, prefer src/lib/.
  • Treat src/modules_tcl<major>/ and src/lib_tcl<major>/ as Tcl-major-version-specific source trees.
  • Prefer generic source in src/modules/ or src/lib/ unless the package, proc, or surrounding package mapping is specific to a Tcl major version or exists only in a version-specific tree.
  • Treat pkgIndex.tcl as a loader map unless the task is about package loading or registration.
  • If the best hit is pkgIndex.tcl, resolve the implementation file and continue there.
  • Prefer editable source over bootstrap, VFS, built, installed, project layout, or generated copies unless the user explicitly targets one of those.

Proc Inspection Order

  1. Read the exact file named by the user, if provided.
  2. Otherwise read the active editor file, if provided and relevant.
  3. Otherwise search once for the exact proc name.
  4. Prefer editable source under src/modules/, src/modules_tcl<major>/, src/lib/, or src/lib_tcl<major>/.
  5. If multiple matches exist, prefer the generic source tree unless version-specific behavior is relevant or only a version-specific definition exists.
  6. If the best hit is pkgIndex.tcl, use it to resolve the implementation file.
  7. Once the owning source file is identified, continue locally from that file.

Recovery After Wrong Path Guess

  • Re-check user-provided path.
  • Re-check active editor file, if available.
  • Re-check repo naming conventions.
  • Use one exact symbol search instead of probing more filename variants.

Imports & Package Management

  • Always declare dependencies explicitly using package require <name> near file tops.
  • Prefer fully-qualified namespaces when referencing external packages (package require tcl::zlib, package require TclOO).
  • Organize custom modules as namespace eval punk::<modulename> with filenames like src/modules/punk/<modulename>-<magicversionnumber>.tm.
  • Custom modules can have deeper hierarchies such as punk::lib::util::<somename> with a corresponding directory structure.
  • Use semantic versions that package vcompare can interpret; strip leading zeros.
  • For optional features, probe with if {[catch {package require foo}]} { ... } and degrade gracefully.

Formatting & Layout Rules

  • Opening braces stay on the same line for procs; multiline control structures may span lines for readability if Tcl syntax allows without using line-continuation-backslash. e.g braced expr contents (or if expressions)
  • Line continuation backslashes should only be used in documentation blocks for use with punk::args (ie in 'punk::args::define' arguments or in 'lappend PUNKARGS' elements)
  • proc contents should not use line continuation backslashes as it can make debug line-number matching harder. use Tcl expand operator with an opening brace instead. e.g dict create {}{ a A b B c C } This works in a single block for literals, but for values that need substitution, additional expand with brace pairs may be needed. e.g dict create {}{ } a A
    b B c C {}{ } d $DVAL {}{ }
  • Keep pipelines readable by aligning % var = ... and pipecase segments vertically when possible.
  • Document non-trivial procedures and exports with the standard header template (see below).

Naming Conventions

  • Procedures: lowercase_with_underscores for internals, camelCase allowed for public APIs where existing patterns fit.
  • Variables: lowercase_with_underscores; avoid single-letter names except for loop indices.
  • Namespaces: Mirror directory structure; nested modules should reflect filesystem hierarchy.
  • Private helpers: Prefix with _ (e.g., _resolve_stream); do not export them.
  • Constants: UPPER_CASE_WITH_UNDERSCORES declared via namespace eval { variable CONSTANT value } when practical.

Procedure Documentation Template Guide

    #- comments such as this with a leading dash are descriptions for the agent of how-to/what-to to implement
    #- whereas comments without the dash are either literal comments, or if angle-bracketed, descriptions of what to put in the comment.
    namespace eval argdoc {
        lappend PUNKARGS [list {
            @id     -id     ::full::namespace::path::procedure_name
            @cmd    -name   "full::namespace::path::procedure_name"\
                -summary\
                    "Short single line procedure description"\
                -help\
                    "Procedure summary without too much overlap with documented
                    arguments below.

                    Existing 
                    - include description of return value"
            @leaders
                arg1        -type any -optional 0 -multiple 0 -help\
                    "description of mandatory leading argument arg1"
            @opts
                -force      -type boolean
                -flag1      -type none -help\
                    "description of non-argument accepting flag -flag1"
                --          -type none -help\
                    "End of opts marker"
            @values -min 1 -max -1
                arg2        -type list      -optional 0 -help\
                    {Description of mandatory arg arg2
                      possibly spanning multiple lines, but each line should
                      generally be wrapped manually to keep sensibly short
                      for terminal display.
                      Help blocks may be wrapped in curly braces or double quotes.
                      See the punk::args module for details of acceptable structure.
                      } 
                glob        -type string    -optional 1 -multiple 1 -help\
                    "Description of optional argument glob which can be repeated.
                      Indenting of argument -help contents should follow this example.
                      Note that we indent subsequent lines by 2 additional spaces,
                      whereas the @cmd -help does no such indenting. This provides
                      a more presentable display when calling `i procedure_name`."
        }]
    }
    proc procedure_name {args} {
        # <optional summary line to aid debug during viewing of proc body using tools like `cmdtrace` or `corp procedure_name`>
        #- agent: these comments are not literal contents of the proc - they are to be read as a guide.
        #- argument parsing implementation:
        #-  If not highly performance sensitive use punk::args to parse,
        #-    make use of `punk::args::parse $args withid ::full::namespace::path::procedurename`
        #-  namespace eval ::punk::args::register {
        #-      #use fully qualified so 8.6 doesn't find existing var in global namespace
        #-      lappend ::punk::args::register::NAMESPACES ::punk::ansi ::punk::ansi::ansistring ::punk::ansi::colour ::punk::ansi::argdoc 
        #-  }
        #-  If performance sensitive or not part of a broad-concept of 'API' for the module and useful utilities,
        #-    use fast `switch` based code to parse the arguments.

        #- procedure functionality implementation
    }

Update the template with concrete details whenever functions are user-facing or complex.

Error Handling & Logging

  • Prefer try { ... } on error {result options} { ... } (Tcl 8.6+) for structured handling.
  • Fallback pattern:
    if {[catch {some_command} result]} {
        puts stderr "Error: $result"
        return -code error $result
    }
    
  • For Punk pipelines, wrap risky commands inside pipecase blocks and emit descriptive messages via puts stderr or Punk logging helpers.
  • Never swallow errors silently; propagate with context so shell users see actionable details.

Pipeline & Functional Style Notes

  • Punk Pipeline functionality is somewhat experimental/in-flux and should usually be avoided for AI generated code unless the user specifically requests it.
  • Use % var = ... bindings to capture intermediate values; keep names meaningful.
  • pipecase should list specific patterns before catch-alls to avoid hidden matches.
  • fun name pattern { ... } definitions should remain side-effect light; treat them as pure functions unless otherwise documented.
  • Keep pipelines short and composable; extract into helper procs or fun definitions when they exceed ~10 logical steps.

Module Structure Expectations

# <Module description>
package require <dependencies>
#- comments such as this with a leading dash are descriptions for the agent of how-to/what-to to implement
#- whereas comments without the dash are either literal comments, or if angle-bracketed, descriptions of what to put in the comment.

namespace eval <module_namespace> {
    variable version <semver>
    namespace export public_proc1 public_proc2

    namespace eval argdoc {
        lappend PUNKARGS [list {
            @id     -id     <module_namespace>::public_proc1
            ... elided ...
            #- punk::args textblock similar to example given in Procedure Documentation Template
            #- This should exist immediately prior to each proc (or at least very close),
            #- even if it is only being used for documentation and not for parsing.
            #- If the public_proc1 proc does not use the PUNKARGS definition for parsing; then the parsing within the proc
            #- and the punk::args definitions of proc args and behaviour; must be kept synchronized.
        }]
    }
    proc public_proc1 {args} {
        #- argument parsing code, using `punk::args::parse` if part of API and not performance critical
        #- if argument parsing is done in code here - the behaviour must match the arguments as defined in the PUNKARGS list created above.

        #- Implementation
    }

    namespace eval argdoc {
        lappend PUNKARGS [list {
            @id     -id     <module_namespace>::some_other_public_proc
            ... elided ...
        }]
    }
    proc some_other_public_proc {args} {
        ... elided ... 
    }

    namespace eval private {
        # <basic description of namespace - optional but recommended>
        #- use of same PUNKARGS mechanism within a further nested argdoc namespace is recommended for clarity
        #- even within private namespaces.
        #- Generally privately namespaced procs will use the PUNKARGS for documentation only,
        #- unless there is no concern about the (usually slight) overhead of punk::args::parse.

        proc private_helper {arg1 arg2} {
            #- Private implementation
        }

        proc private_helper2 {args} {
            #- argument parsing code - using `switch`, `regexp` etc if needed.

            #- Private implementation
        }
    }

    namespace eval utils {
        # <basic description of namespace - optional but recommended>
        #- other appropriately named sub namespaces such as 'utils' 'lib' can be used to structure the codebase.
        #- If these form part of what can reasonably be considered the API of the module - they should
        #- be documented using the punk::args mechanism described above.

        #- more procs
    }
}

namespace eval ::punk::args::register {
    #use fully qualified so 8.6 doesn't find existing var in global namespace
    lappend ::punk::args::register::NAMESPACES <module_namespace> <module_namespace>::utils
}

##  Ready
package provide <module_namespace> [tcl::namespace::eval <module_namespace> {
    variable version
    #- this version number, exactly 999999.0a1.0 is a literal that should be used in all src/module folders
    #- we refer to this sometimes as the 'magic version number'
    set version 999999.0a1.0
}]
return

Ensure module filenames include the magic version (punk/<subpath>/<modulename>-999999.0a1.tm), and keep namespace export lists alphabetized for clarity.

Type & Data Handling

  • Tcl is dynamically typed; emulate structural typing via argument validation at proc boundaries.
  • Validate user inputs with punk::args::parse or switch -exact, regexp, or Punk pipeline predicates before mutation.
  • Use dictionaries for structured data, or parallel lists if it is likely to be a performance win.
  • Tcl arrays can also be used, but limit to simple flat structures, or cases where it is specifically warranted.
  • When bridging to binary data (e.g., ANSI/xbin parsing), document expected encodings and conversions.

Versioning & Releases

  • Stick to semantic versioning (major.minor.patch).
  • Use the magic version 999999.0a1.0 for src/modules src/modules_tcl9 etc and add/update the actual version number in the associated -buildversion.txt file.
  • Update the -buildversion.txt file when API changes are made
  • There may be occasional exceptions such as punk::libunknown-0.1.tm which is deliberately manually versioned, but new modules should use the magic version mechanism.
  • vendormodules and modules in .vfs folders or src/bootsupport/modules should not use the magic version mechanism, nor should modules with the magic version number appear in the output paths such as /modules
  • When referencing ranges, use bounded specs (e.g., 1.2.3-2.0.0).
  • Convert loose versions to bounded form in module metadata; helper utilities exist in boot modules for this purpose.
  • Update punk::libunknown registries whenever adding/removing modules to keep discovery accurate.

Platform & Performance Notes

  • Primary target: Windows (win32-x86_64). Validate code paths that rely on Windows-only packages.
  • Secondary targets: Linux/macOS/FreeBSD; guard platform-specific calls with if {$tcl_platform(os) eq "Windows"} {...}.
  • Favor compiled extensions (tcllibc, twapi) when available, but provide scripted fallbacks whenever possible.
  • Be mindful of long-running pipelines; chunk work and avoid blocking the Punk shell UI thread.

Documentation & Comments

  • Keep inline comments concise; describe intent, not mechanics.
  • Primary documentation for procs should use the punk::args system, preferably within an argdoc sub namespace using: lappend PUNKARGS
  • Update any relevant docs or usage notes when behavior changes.
  • Mention environment variables or flags required to run new features.

Agent Workflow Tips

  • No .cursor/rules/, .cursorrules, or .github/copilot-instructions.md files exist as of this update. If they appear later, integrate their instructions here.
  • Always re-run tclint and the most specific test affected by your changes before committing.
  • When touching VFS payloads, describe regeneration steps inside commit messages and this guide if persistent.
  • Favor incremental commits tied to logical units of work; avoid monolithic diffs mixing tooling and feature changes.

Final Submission Checklist

  • Nested AGENTS.md files checked for scope-specific rules.
  • tcllint (and tcllint --fix if needed) executed with clean results.
  • Relevant tests (tclsh src/tests/runtests.tcl) executed and passing, or more specific tclsh src/tests/modules/<modulehierarchypath>/tests/all.tcl passing
  • Build step (tclsh make.tcl packages) verified when touching build-critical code.
  • Documentation/comments updated for new behavior or flags.
  • Diffs reviewed to ensure no stray whitespace or debugging output remains.

Adhering to these conventions keeps the ShellSpy/Punk Shell ecosystem consistent, portable, and friendly for future agentic collaborators. Happy hacking!