28 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
- Read the root AGENTS.md
- Identify every file or folder you expect to touch
- Walk from the repository root to each target path
- Read every AGENTS.md found along each route
- If a parent AGENTS.md lists a child AGENTS.md whose scope contains the path, read that child and continue from there
- Use the nearest AGENTS.md as the local contract and parent docs for repo-wide rules
- 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
- Re-check changed paths against the DOX chain
- Update nearest owning docs and any affected parents or children
- Refresh every affected Child DOX Index
- Remove stale or contradictory text
- Run existing verification when relevant
- 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
src/— Source tree root; editable source code, build scripts, tests, VFS payloads, vendor deps, docs (see src/AGENTS.md)src/modules/— Main editable module source (see src/modules/AGENTS.md)src/modules/punk/— Core punk namespace modules (see src/modules/punk/AGENTS.md)src/modules/test/— Installed-module test packages (see src/modules/test/AGENTS.md)src/modules/opunk/— Alternative punk namespacesrc/modules/punkcheck/— Build/check system
src/modules_tcl8/— Tcl 8 specific modules (see src/modules_tcl8/AGENTS.md)src/modules_tcl9/— Tcl 9 specific modules (see src/modules_tcl9/AGENTS.md)src/lib/— Editable library source (see src/lib/AGENTS.md)src/lib_tcl8/— Tcl 8 specific librariessrc/lib_tcl9/— Tcl 9 specific librariessrc/bootsupport/— Early-load bootstrap modules (see src/bootsupport/AGENTS.md)src/tests/— Unit tests for src-hierarchy modules (see src/tests/AGENTS.md)src/vfs/— Virtual file system images for builds (see src/vfs/AGENTS.md)src/scriptapps/— Entry-point scripts for Punk apps (see src/scriptapps/AGENTS.md)src/vendormodules/— Third-party bundled modules (see src/vendormodules/AGENTS.md)src/vendorlib/— Third-party bundled libraries (see src/vendorlib/AGENTS.md)src/vendorlib_tcl8/— Tcl 8 specific vendor librariessrc/vendorlib_tcl9/— Tcl 9 specific vendor librariessrc/runtime/— Build runtimes and VFS config (see src/runtime/AGENTS.md)src/doc/— Generated documentation (see src/doc/AGENTS.md)src/testansi/— Sample ANSI art files (do not modify)
- Directories agents should not directly modify (no child DOX needed):
callbacks/— Experimental shellspy features, user-onlyscriptlib/— Shared utilities + manual tests, user-onlybin/— Built binaries and helpers, build output targetmodules/(root) — Build output target fortclsh src/make.tcl moduleslib/(root) — Build output target fortclsh src/make.tcl libsmodules_tcl8/,modules_tcl9/— Tcl version-specific build output targetslib_tcl8/,lib_tcl9/— Tcl version-specific build output targets
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 packagesonce after cloning to populate generated assets. - Keep edits within the scoped instructions of any nested
AGENTS.md. - Use
tclintbefore 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) orpunk902z make.tcl projectinside Punk shell. - Clean/resync: Remove
_build/artifacts then reruntclsh make.tcl project; avoid partial cleans that break boot modules. Cleaning _build is generally not required. - Binary images: Use
punk make.tcl projectto 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 errorblocks inside tests for clearer diagnostics.
Linting & Formatting
- Command: N/A - tclint is currently only available as a plugin in vscode (configured via
tclint.tomlin repo root). - Files covered:
.tcl,.tmextend 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, guardpackage requirecalls 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
- Exact path named by the user.
- Active editor file, when the environment provides one.
- Exact proc, symbol, or identifier named by the user.
- 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>/andsrc/lib_tcl<major>/as Tcl-major-version-specific source trees. - Prefer generic source in
src/modules/orsrc/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.tclas 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
- Read the exact file named by the user, if provided.
- Otherwise read the active editor file, if provided and relevant.
- Otherwise search once for the exact proc name.
- Prefer editable source under
src/modules/,src/modules_tcl<major>/,src/lib/, orsrc/lib_tcl<major>/. - If multiple matches exist, prefer the generic source tree unless version-specific behavior is relevant or only a version-specific definition exists.
- If the best hit is
pkgIndex.tcl, use it to resolve the implementation file. - 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 likesrc/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 vcomparecan 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
exprcontents (orifexpressions) - 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 {}{ } - test files may commonly use line continuations - which is ok in this instance outside of proc definitions.
- For test files that include tcl expand syntax based structures - these should not be refactored into line continuations.
- Keep pipelines readable by aligning
% var = ...andpipecasesegments vertically when possible. - Document non-trivial procedures and exports with the standard header template (see below).
Naming Conventions
- Procedures:
lowercase_with_underscoresfor internals,camelCaseallowed 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_UNDERSCORESdeclared vianamespace 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
pipecaseblocks and emit descriptive messages viaputs stderror 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. pipecaseshould 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
fundefinitions 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::libunknownregistries 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.mdfiles exist as of this update. If they appear later, integrate their instructions here. - Always re-run
tclintand 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.mdfiles checked for scope-specific rules. tcllint(andtcllint --fixif needed) executed with clean results.- Relevant tests (
tclsh src/tests/runtests.tcl) executed and passing, or more specifictclsh src/tests/modules/<modulehierarchypath>/tests/all.tclpassing - 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!