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.
 
 
 
 
 
 

76 KiB

Project Goals

This file is the canonical, harness-agnostic index of technical project goals for ShellSpy. It is referenced from the root AGENTS.md Child DOX Index and is a required read for any non-trivial work, so that agents can discover goals whose scope intersects their work.

Detail prose for goals that need it lives in goals/G-<id>-<slug>.md (see goals/AGENTS.md). The index entry is canonical; a detail file only elaborates and never contradicts its index entry.

Format

Each goal is one block:

### G-<id> [<status>] <short title>
Scope: <repo paths or module areas this goal touches>
Goal: <one line — what done looks like, self-contained>
Detail: goals/G-<id>-<slug>.md            <- optional, omit if absent
Acceptance: <measurable, verifiable pass/fail criterion>

Status tags

  • proposed — not yet started; awaiting user confirmation to go active
  • active — in progress
  • achieved <YYYY-MM-DD> — done; kept as a one-line record
  • abandoned — dropped; one line on why stays in the entry
  • superseded by G-<id> — replaced; do not delete the old entry

Maintenance rules

  • Goals are user-owned. Agents add or edit goal entries only at the user's request or with the user's explicit approval - never on their own initiative, and never in bulk from an agent's own survey of what "should" be goals.
  • Suggesting is always allowed and encouraged when grounded in the work at hand: a discovered gap, a recurring manual step, a deferred design decision, or a natural follow-on that fits what is currently being worked on. Flag it as a candidate goal in conversation or the completion report, optionally with a drafted block ready for approval. A suggestion is not an edit - nothing is written to this file or goals/ until the user approves per the proposal-first rule.
  • Proposal-first: before writing a new goal entry or changing an existing entry's contract (title, status tag, Scope, Goal, Acceptance), show the user the proposed wording - the full block for a new goal, the changed clause(s) for an edit - and get explicit approval. If the user already supplied or approved the exact wording this session, apply it and report what was written.
  • Exception (sanctioned autonomous edit): an agent whose work satisfies a goal's Acceptance: must flip that goal to achieved <date> as part of its DOX closeout pass, and report the flip in its completion summary.
  • Agents must not flip proposedactive. They flag it in their completion report for the user to confirm.
  • Detail files under goals/ may be updated without pre-approval when recording findings, decisions, or verification artifacts from work the user directed on that goal or its subject matter; report such updates in the completion summary. The index entry is canonical - a detail edit must never contradict it.
  • The Goal: line must stay self-contained enough that an agent who skips the detail file still does no harm. Detail files are enrichment, not load-bearing for safety.
  • When the achieved section grows past ~30 entries, the oldest are moved to GOALS-archive.md and their detail files to goals/archive/.
  • If a goal cannot be safely summarized in one line, that is a signal it is really two goals — split it.

Authoring a new goal (for agents)

When the user asks to "write a goal for X" or "help me draft a goal for Y", do the following:

  1. Read this file in full so you know the format and can pick the next free G-<id>.
  2. Ask the user only the questions below. Do not invent answers; ask them one at a time or batched if the user prefers. Stop asking once every required field has a real answer.
    • Scope: Which repo paths or module areas does this goal touch? (paths are preferred; module names are acceptable if paths are not yet known)
    • Goal: In one sentence, what does done look like? Push for an outcome, not an activity ("X compiles to bytecode ≤ 1.10× cost of Y", not "improve compiler performance").
    • Acceptance: What is the measurable, verifiable pass/fail criterion an agent can check against? If the user cannot state one, propose 2-3 candidate criteria and ask them to pick or refine.
    • Status: Default to proposed unless the user says it is already in progress (active).
    • Detail file? Only if the goal has non-obvious rationale, a multi-phase plan, alternatives worth recording, or needs more than ~3 lines of prose to state properly. If yes, propose a slug and offer to draft the detail file too. If no, omit the Detail: line.
  3. Draft the goal block in this file's format and show it to the user for review, applying it only after approval (per the maintenance rules). Do not set it active unless the user confirms.
  4. If a detail file is warranted and the user approves, create goals/G-<id>-<slug>.md using the structure in goals/AGENTS.md.
  5. Do not delete or rewrite existing goals to make room for a new one. Append with the next free ID.

Goals

G-001 [proposed] Pluggable console backends for non-detectable terminals

Scope: src/modules/opunk/console-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/lib/app-punkshell/punkshell.tcl Detail: goals/G-001-pluggable-console-backends.md Goal: an interactive REPL can be launched against a non-detectable terminal-like device (ssh channel, tk text widget) via an ::opunk::Console subclass, with no edits to the base class or punk::console. Acceptance: a subshell started with an ssh-channel-backed and a tk-widget-backed ::opunk::Console subclass runs an interactive REPL that reads/writes through that console; size, at_eof, and can_respond are answered by the subclass overrides; the base ::opunk::Console and punk::console module are unchanged.

G-002 [proposed] Non-nested subshell with console targeting and inter-subshell comms

Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-002-non-nested-subshell.md Goal: a subshell can target a named console (default or non-default) and run without blocking the parent, replacing the synchronous nested interp-eval model. Acceptance: a parent REPL launches a subshell against a named console and continues processing its own input while the subshell runs; the parent can signal/query the running subshell; thread::send -async dispatched from within the subshell's code interp arrives at that interp (so packages like promise work when thread features aren't disabled); the "first subshell asymmetry" TODO at repl-999999.0a1.0.tm:3130 is resolved; existing synchronous subshell punk/safe/safebase/punksafe behaviour is preserved as a default mode.

G-003 [proposed] Configurable resource limits and sandboxing on subshell interps

Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-003-subshell-resource-limits.md Goal: a subshell's code interp can be launched with configurable resource limits (command-count, time) and sandboxing features, building on the resolved first-subshell asymmetry from G-002. Acceptance: a subshell can be launched with at least one resource limit (command-count via interp limit -command, or time via interp limit -time) and one sandboxing feature (e.g. interp hide of a command, or full safe-interp restrictions) applied to its code interp, enforceable regardless of subshell nesting depth; a subshell can be configured anywhere on the spectrum from unrestricted to fully safe via expose/hide of commands; the existing default subshell behaviour (no limits, no extra sandbox beyond the existing safe/safebase/punksafe types) is preserved when no limits are configured.

G-004 [proposed] No executable binaries committed to the repository

Scope: repo-wide (bin/, src/vfs/, src/vendorlib/, src/vendormodules/, src/bootsupport/) Detail: goals/G-004-no-committed-binaries.md Goal: the committed repository contains no executable binaries; zip-based .tm modules are allowed but not if they embed executables. Acceptance: a scan of the committed tree finds no executable binaries (shared libs, .exe, native .so/.dll/.dylib, bare ELF/Mach-O); any zip-based .tm modules present contain no embedded executables; the binary artifacts previously committed are retrievable via G-005 (build from source) or G-006 (pre-built download) so their removal does not break builds.

G-005 [proposed] Zig-based build infrastructure for binary dependencies from source

Scope: src/runtime/, build.zig / build.zig.zon (new), src/make.tcl integration Detail: goals/G-005-zig-build-infrastructure.md Goal: a zig-based build system retrieves and builds binary dependencies (including Tcl9) from source, replacing the committed-binary approach for the vendored/native components. Acceptance: running the zig build produces the binary artifacts the repo previously committed (at minimum: Tcl9 library for one target platform); existing Tcl9-zig experiments brought into the project; tclsh src/make.tcl integrates with the zig build so a normal project build retrieves/builds binaries via zig when not present; no binary artifacts need to be committed for the build to succeed on a clean checkout with the zig toolchain available.

Scope: src/runtime/, src/make.tcl integration, user-config (consent flags) Detail: goals/G-006-prebuilt-artifact-download.md Goal: pre-built binary artifacts can be downloaded from a separate related binary-artifacts repository or user-configured sources, gated by explicit user consent/configuration by default. Acceptance: a download mechanism fetches binary artifacts (the same set the zig build produces) from a configured source on demand; by default the download is gated behind explicit user consent (a config flag or interactive prompt) and does not occur silently; a user-configured source URL overrides the default binary-artifacts repo; downloaded artifacts satisfy the same build requirements as zig-built artifacts so tclsh src/make.tcl project succeeds with downloaded artifacts in place of built ones.

G-007 [achieved 2026-07-05] Location-transparent punk::console across repl and code interps

Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-007-console-location-transparency.md Goal: punk::console presents one API in every interp/thread of a punk session - code-interp callers see the same console facts and can perform the same queries/operations as the parent, routed to the console-owning context via a punk-side ownership registry, with no repl eval required. Acceptance: from a running punk session's code interp, without repl eval: console_fact_get returns the same values the parent sees and a fact set in the parent is immediately visible; a terminal query (e.g. get_cursor_pos or dec_get_mode) against the default console succeeds and cooperates with the repl reader (no lost or garbled input); a console constructed and owned by code-interp code is operated on locally (no round-trip to the parent); the existing console test suites pass and single-interp (non-repl) usage is unchanged.

G-008 [proposed] Scoped console state for same-console subshells (activatable state sets)

Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-008-scoped-console-state.md Goal: a subshell on the shared console can opt into scoped console state - its terminal mutations (tabstops, modes, cursor style, palette, title) are captured as an activatable per-subshell state set and the prior state is re-established on quit or switch-away, with today's shared/persistent behaviour remaining the default. Acceptance: with a scoped subshell: tabstops, at least one DEC/ANSI mode and at least one palette entry changed inside the subshell are restored for the parent on quit (verified by terminal query where queryable) and the facts store matches the terminal; the default (unscoped) launch behaviour is unchanged; activation is set-based, proven by applying state set A, activating set B, then re-activating A and observing A's state; irreversible outputs (cleared screen/scrollback, emitted text) are documented as out of scope.

G-009 [proposed] Themed subshell profiles binding poshinfo schemes to behavioural configuration

Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/poshinfo-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/island-999999.0a1.0.tm Detail: goals/G-009-themed-subshell-profiles.md Goal: a subshell can be launched from a named profile binding a poshinfo-enumerated scheme to behavioural aspects (e.g. G-003 interp limits/hidden commands, punk::island filesystem access) so that restricted subshells are visually distinct, with the theme's terminal effects and associated profile data riding the G-008 state set. Acceptance: a named profile associating a poshinfo scheme with at least one restriction aspect (an interp limit, a hidden command, or island-restricted filesystem access) launches by name; the scheme's visual state applies on entry (at minimum prompt styling plus one underlying terminal aspect such as a palette change) and is removed/restored on quit via the G-008 mechanism; profile-associated non-terminal data is scoped to the subshell's lifetime; an unthemed launch is unchanged.

G-010 [proposed] Subshell suspend/resume and tree navigation

Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-010-subshell-tree-navigation.md Goal: subshells form a navigable tree - a subshell can be suspended rather than quit, listed, resumed, and the console switched to any live subshell in the tree (e.g. grandchild to grandparent, or across branches) with each subshell's console state re-applied via its G-008 state set, building on the non-nested subshell model of G-002. Acceptance: from a grandchild subshell a single switch command reaches the grandparent without unwinding through the intermediate parent; switching between subshells on different branches preserves each subshell's session state and re-applies its console state set on activation; suspended subshells can be listed and resumed; quit still unwinds to the launching parent as today; a subshell whose switch commands are hidden/restricted cannot initiate switches.

G-011 [proposed] Optional per-console err channel with defined stderr semantics

Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/opunk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm Detail: goals/G-011-console-stderr-semantics.md Goal: a console optionally carries an err channel as an attribute of its canonical {in out} identity - {in out err} specs accepted everywhere -console is, err resolving to process stderr for the default console and to the console's out channel elsewhere - so diagnostics and emit-to-err are first-class per-console operations instead of raw puts stderr. Acceptance: console_spec_resolve and every -console site accept an {in out err} spec (err optional; existing pair/instance-name/object spec forms unchanged); opunk::Console exposes the err channel (nullable, additive base-class change); an unset err resolves to stderr for the default console and to the console's own out channel otherwise; punk::console's own warnings/diagnostics emitted while operating on a resolvable console go to that console's err (raw puts stderr remains only where no console is in play); an emit-to-err path exists and is exercised by at least one real consumer (e.g punk::repl); the effective err is discoverable from any thread/interp via console_fact_get (fact key err, returning the effective err channel name); ownership/fact/mode-cache keys remain canonical {in out}; the existing console test suites pass unchanged.

G-012 [proposed] Template system: inert VCS-config payloads and explicit layout refresh

Scope: src/project_layouts/, src/make.tcl, src/modules/punk/mix/ (layout instantiation), fauxlink module (bootsupport 0.1.1 - promoted if chosen as mechanism) Detail: goals/G-012-template-payload-safety.md Goal: project layouts carry no live nested VCS-config files - template .gitignore payloads are stored inert (renamed, or fauxlink-encoded) and materialized at project generation - and src/make.tcl has an explicit punkcheck-tracked step that refreshes layout payloads from their canonical sources. Acceptance: a scan of src/project_layouts finds no file named .gitignore, and git check-ignore --no-index over every layout file matches only root-.gitignore rules (nested rules provably inert); a project generated from each affected layout receives a working .gitignore whose content matches the canonical payload/target; after editing a canonical source (e.g. root .gitignore), the make.tcl template-refresh step updates the derived layout payloads (punkcheck-tracked), covering vendor/punk layouts as well as custom/_project; the previously hidden template files (layout READMEs, vendored TODO-class files) remain git-tracked without per-file force-add exceptions.

G-013 [proposed] Raw mode as the repl's default input mode

Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm Detail: goals/G-013-raw-mode-default.md Goal: a repl launched without explicit mode configuration starts in raw input mode with a clean display - every per-keystroke debug emission behind its own repl-operable toggle - and raw editing covers the line-mode essentials (history navigation, cursor movement). Acceptance: a default launch lands in raw mode with line mode still selectable; with debug toggles at their defaults (off unless stored configuration via ::punk::config says otherwise - see G-014), typing/editing/submitting a command emits no cursor-positioned debug output; the per-keystroke add_chunk frame and the right-hand live editbuf view are gated separately, each toggleable from within a running repl; arrow-key history navigation and left/right cursor movement work in raw mode (current stubs replaced); the marked-line debugrepl output form is retained and works on terminals without cursor addressing (e.g. vt52); the debugrepl first-word activation mechanism is reviewed and the keep/replace outcome (e.g. a proper Tcl command that interp hide can restrict in subshells) is recorded in the detail file; on tcl 8.6 a background-initiated terminal query at an idle raw-mode prompt succeeds (the residue scenario fail-fast-guarded in punk::console 0.7.1).

G-014 [proposed] ::punk::config stored configuration: toml files with named-subshell scoping

Scope: src/modules/punk/config-0.1.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm, src/vendormodules/tomlish-*.tm (vendored; canonical source in the external tomlish project space) Detail: goals/G-014-punk-config-toml.md Goal: ::punk::config loads stored configuration from toml files in the XDG-located config dir - parsed via the vendored tomlish module, never an ad-hoc parser - and consumers resolve settings with per-named-subshell overrides, so features like the G-013 debug-view startup defaults read declared user configuration instead of hardcoded fallbacks. Acceptance: a setting declared in a toml file under the XDG-located config dir is visible through the punk::config API at repl startup, and with no config files present built-in defaults apply with no errors beyond the existing missing-dir notice; a named subshell resolves its own overriding value for a key also defined at the parent/default scope, and a subshell with no override inherits the outer value (proven with at least one real key); at least one shipped feature (the G-013 editbuf-view startup default is the natural first) reads its default through this path rather than a hardcoded value; all toml reading/writing in punk::config goes through the tomlish module, and the tomlish API procs punk::config consumes carry punk::args (PUNKARGS) documentation - added upstream in the tomlish project and re-vendored here before punk::config implementation proceeds.

G-015 [achieved 2026-07-07] Punk executable script subcommand: reliable non-interactive piped/script execution

Scope: src/vfs/_config/punk_main.tcl, src/lib/app-punkshell/punkshell.tcl (script path or a leaner dedicated app package) Detail: goals/G-015-script-subcommand-piped-stdin.md Goal: <punkexe> script [<scriptname>] [<args>...] executes a script file or piped stdin content (scriptname optional when input is piped) in an interp preloaded with the basic punk modules and aliases a punk shell provides by default, and always terminates with the script's success/failure as its exit code - without the shell subcommand's shellfilter channel transforms/logging stacks and without ever dropping into an interactive shell - so agents can reliably make piped script calls to punk executables. Acceptance: piping commands to <punkexe> script runs them and terminates at stdin EOF with no trailing exit required, exit code 0 on success; a failing piped command terminates the process with a nonzero exit code and the error on stderr, never landing in an interactive shell regardless of console availability or PUNK_PIPE_EOF; <punkexe> script <file> [<args>...] executes the file with conventional ::argv0/::argv and propagates its error status the same way; the script path installs none of the shell subcommand's shellfilter stacks/transforms and the launch plumbing itself emits nothing on stdout/stderr (the current stub's stderr diagnostics removed) so exec-style callers see only the script's own output; the motivating example works with no package require boilerplate: piping dev projects.work *<name>* to <punkexe> script emits the matching-project table and exits 0, because the script interp carries the default punk shell module/alias environment.

G-016 [proposed] projects.work discovers git-based projects alongside fossil

Scope: src/modules/punk/mix/commandset/project-999999.0a1.0.tm, src/modules/punk/repo-999999.0a1.0.tm Detail: goals/G-016-projects-work-git-discovery.md Goal: dev projects.work <glob> lists git-based project checkouts as well as fossil-based ones, each result identifying its VCS - fossil discovery stays central-config-db based, and git discovery uses a defined enumeration source (git has no central registry; the chosen mechanism is recorded in the detail file). Acceptance: with a git-only project on disk registered in the chosen enumeration source and matching the glob, projects.work lists its working directory and identifies it as git; existing fossil results are unchanged apart from any added VCS-identifying column; a project that is both git and fossil (e.g. this repo) appears with both indicated rather than duplicated; glob matching remains case-insensitive.

G-017 [proposed] Agents locate local projects via piped projects.work calls, not filesystem scanning

Scope: AGENTS.md (root) or a child doc it indexes (guidance content only - no code) Goal: once G-015 makes piped script calls reliable, repository guidance directs agents asked to locate another local project to query it via a piped projects.work call to a punk executable instead of grepping/globbing the wider filesystem. Acceptance: root AGENTS.md (or a child doc indexed from it) records the exact recommended invocation - executable, subcommand, glob usage, expected output shape - and states when filesystem scanning remains appropriate (projects not registered in any discovery source); the guidance is added only after G-015 is achieved (and notes the fossil-only limitation until G-016); following the documented pattern, an agent locates a named sibling project's checkout dir with a single piped call.

G-018 [proposed] Zig-built plain tclsh kits: self-contained zip-based executables without punk infrastructure

Scope: build.zig / build.zig.zon (per G-005), src/runtime/, src/make.tcl integration Detail: goals/G-018-zig-plain-tclsh-kits.md Goal: developers can use the G-005 zig build system to produce self-contained zip-based tclsh executables that carry no punk-specific infrastructure (no punk boot layer, punk modules, or punk apps) - plain tclsh kits usable independently of the punkshell product. Acceptance: a documented zig invocation on a clean checkout (zig toolchain available) produces a zip-based tclsh executable for at least one target platform that runs conventional tclsh invocations (<exe> script.tcl args, piped stdin) on a machine with no Tcl installation; a listing of the kit's mounted/zip contents shows stock Tcl (plus any declared stock runtime deps) and no punk namespaces, punk boot files, or punkshell apps; the punk-flavoured executables remain producible alongside.

G-019 [proposed] Dependency-scan-driven module trimming for punk-based executables

Scope: src/make.tcl, src/modules/punk/lib-999999.0a1.0.tm (tclparser use), src/vfs/ (kit assembly), scanning module (new or existing punk module - to be determined) Detail: goals/G-019-dependency-scan-module-trimming.md Goal: a package-dependency scan from an executable's entrypoint (candidate basis: the tclparser parse API - currently satisfied only by the c-only tclparser library, with punk::lib's pure-Tcl fallback an unimplemented stub) determines the module closure the executable actually requires, so a build can ship only those modules - while 'batteries included' builds remain a supported alternative, not a casualty. Acceptance: for at least one punk-based executable target, the build can run a dependency scan from its entrypoint producing the closure of required packages/modules plus a mechanism to declare dynamically-loaded extras the scan cannot see; a trimmed kit assembled from that closure starts and passes its basic function check (e.g. repl launch or the app's smoke test) with no missing-package errors; the trimmed kit's module listing is a strict subset of the batteries-included equivalent (demonstrating real exclusion); batteries-included builds remain producible unchanged.

G-020 [proposed] Screen capture and input injection module with per-platform backends (Windows first)

Scope: src/modules/punk/ (new module - name TBD), src/vfs/punk9win.vfs/lib_tcl9/ (existing treectrl/Img/twapi payloads); scriptlib/aloupe.tcl stays untouched as a standalone app Detail: goals/G-020-screencap-input-module.md Goal: a punk module drives screen/window capture and mouse/keyboard injection from scripts via per-platform backends - Windows (treectrl loupe capture + twapi input/window-location) is the initial complete target, with the backend contract designed so X11 (Linux/FreeBSD) and macOS backends can be added without changing callers, and Wayland-native sessions explicitly out of scope. Acceptance: on Windows from a punk shell or script: a screen region and a window located by title/class pattern are each captured to a Tk photo and written as a valid PNG; mouse movement/click and key events injected into a located test window produce their observable effect (typed text arrives, click acts); window location returns the handle and geometry for a pattern; a capability-introspection call reports per-feature support and an unsupported platform/backend yields a clean capability-based refusal, not a crash; the backend interface (capture / input / window-locate) is documented well enough that a non-Windows backend can be added without modifying callers; the aloupe script remains functional and unmodified.

G-021 [proposed] Agent-drivable visual/UI verification via piped snapshot and interaction calls

Scope: src/modules/punk/ (G-020 module's agent-facing surface), AGENTS.md guidance (post G-015 pattern), src/tests/ (visual-verification test hooks) Detail: goals/G-021-agent-visual-verification.md Goal: a tool-calling agent can, during a session, use piped script calls (G-015) to a punk executable to locate the applicable UI window, snapshot it to a PNG file and/or base64 output suitable for AI image analysis, and drive mouse/keyboard interactions - enabling tests whose verification is visual-only and/or input-driven. Acceptance: on Windows, single piped script calls (no interactive session) can: list/match windows for a pattern with machine-parseable output; save a located window's snapshot to a caller-specified path and optionally emit it base64 on stdout; run a scripted interaction sequence (focus, click at offset, type text, snapshot) end-to-end; failures exit nonzero with the error on stderr per G-015 semantics; the invocation patterns are documented for agents alongside the G-017 guidance; at least one real visual-or-input-driven verification (e.g. a Tk app smoke test) is exercised through this path.

G-022 [proposed] Scriptable safe fossil move/rename in dev repo; rename this project's fossil repo to punkshell

Scope: src/modules/punk/mix/commandset/repo-999999.0a1.0.tm, src/modules/punk/repo-999999.0a1.0.tm, src/tests/modules/punk/mix/testsuites/repo/ Detail: goals/G-022-fossil-rename-punkshell.md Goal: the dev repo commandset can move and rename fossil repositories non-interactively and safely - all checkouts repointed, no phantom central config-db entries, no dangling old repo db, fossil project-name renamable with project-code unchanged - and this project's fossil repo (currently project-name 'shellspy') is renamed to 'punkshell' through that mechanism via a G-015 piped script call, not by hand. Acceptance: the commandset provides a flag-driven (no stdin prompts) move/rename operation which on a scratch repo with an open checkout: repoints every registered checkout, leaves the central config-db listing only the new path, removes or archives the old repo db file (per option), clears stale ckout: back-references, and applies a requested project-name change while preserving project-code; the GAP characterization tests in src/tests/modules/punk/mix/testsuites/repo/fossilmove.test are updated to assert the clean behaviour and pass; after G-015 is achieved, this repo's fossil db (shellspy.fossil / project-name shellspy) is renamed to punkshell via the new operation invoked through a piped script call, with fossil info in this checkout showing the new repository path and project-name and fossil all ls free of the old path.

G-023 [proposed] Version-named punk binaries per Tcl generation (versioned / dev / release-gated plain names)

Scope: src/make.tcl, src/runtime/ (mapping config - see G-024), bin/ (build outputs) Detail: goals/G-023-version-named-binaries.md Goal: project builds produce version-named punk executables for tcl 8.6 and tcl 9 as the project version advances - punk8---.exe / punk9---.exe per version, punk8-dev.exe / punk9-dev.exe tracking the latest build, and plain punk8.exe / punk9.exe created initially then replaced only when an actual release is tagged - tolerating the disk growth for now. Acceptance: a project build at the current punkproject.toml version produces punk8---

.exe and punk9---

.exe (names derived from the version, not hand-maintained) plus punk8-dev.exe / punk9-dev.exe updated to that same build; rebuilding at an unchanged version refreshes that version's binaries and -dev without touching other versions' outputs; plain punk8.exe / punk9.exe exist and are replaced only by an explicit release step - a normal build never overwrites them; the scheme is declared succinctly via the G-024 toml mapping (no per-version config edits); archival/deletion of accumulated versioned binaries is out of scope with the trigger question recorded in the detail file.

G-024 [proposed] mapvfs.config converted to toml (tomlish-parsed) with succinct scheme declarations

Scope: src/runtime/mapvfs.config (replaced/deprecated), src/make.tcl (parsing), src/bootsupport/modules/tomlish-*.tm (parser dependency) Detail: goals/G-024-mapvfs-toml.md Goal: the runtime-to-vfs-to-executable build mapping moves from the custom line format of src/runtime/mapvfs.config to a toml file parsed with the tomlish package - still supporting explicit per-executable mappings (runtime, vfs folder, output name, kit type) while also expressing generative schemes like the G-023 versioned naming in a single succinct declaration. Acceptance: a mapvfs toml file parsed via tomlish (no ad-hoc toml parsing) drives the build: every mapping currently active in mapvfs.config is expressible and at least one existing target builds identically from the toml; the G-023 versioned/dev/release-gated output scheme is declared in one entry that expands to its outputs without enumerating versions; malformed or unresolvable entries fail the build with a clear message naming the entry; the legacy .config format is either fully migrated (old parser removed) or explicitly deprecated with documented precedence between the two files.

G-025 [proposed] Punk executables self-report project version and build provenance

Scope: src/vfs/_config/punk_main.tcl (subcommand dispatch), src/make.tcl (stamping build info into the vfs), src/vfs/ (stamp payload location), src/modules/punk/ (in-shell command - the single implementation) Detail: goals/G-025-exe-selfreport.md Goal: a punk executable reports its identity from embedded data rather than its filename - a documented subcommand prints the punkproject.toml project version it was built from plus the input runtime binary name and vfs folder name used to assemble it - with the same-named command available in the punk module so scripts running in any punk shell (including tclsh-hosted ones like tclsh src/make.tcl shell) get the same report in-process without exec, stamp fields reported as absent rather than fabricated when there is no stamp. Acceptance: the build stamps project version, runtime binary name, and vfs folder name into the kit; the built executable invoked with the version-report subcommand prints those fields machine-parseably on stdout and exits 0 with no other output (G-015-compatible; no repl fallthrough); a same-named command in the punk module returns the same fields in-process (subcommand implemented as a wrapper over it - one implementation) and works from the code interp; the report distinguishes stamped provenance from live facts: a stamped kit reports its stamp, a src-mode or source-tree session additionally reports the live punkproject.toml version as a distinct field when it differs, and unstamped contexts (tclsh src/make.tcl shell, plain tclsh with punk modules) report stamp fields explicitly absent with live runtime facts (actual info nameofexecutable) still provided; the report is correct when the executable file has been renamed or copied; executables built before stamping existed fail gracefully with a clear message rather than fabricating values.

G-026 [proposed] Enforceable clean-checkout provenance policy for vendor and bootsupport pulls

Scope: src/make.tcl (vendorupdate and bootsupport steps), src/vendormodules/include_modules.config, src/bootsupport/modules*/include_modules.config Detail: goals/G-026-vendor-provenance-policy.md Goal: pulling vendored or bootsupport artifacts from local source projects enforces committed provenance - the warn-only dirty-checkout check added to vendorupdate in project 0.2.5 becomes a policy that can abort with an explicit override, covers the bootsupport update path as well, and the residual staleness question (built modules that predate or postdate the committed source even in a clean checkout) has a recorded design decision. Acceptance: vendorupdate and the bootsupport update refuse to pull from a source project whose fossil/git checkout is dirty unless an explicit documented override is given (warn-only selectable as a configured mode); the check reports each VCS root once per run and does not fire for unversioned source locations; bootsupport_localupdate is covered by the same shared check (no second divergent implementation); the staleness gap - a clean checkout whose built modules/ artifacts do not correspond to the committed source - is either detected (mechanism chosen and implemented) or explicitly recorded in the detail file as accepted risk with the considered mechanisms; behaviour is exercised by a test or documented manual verification against a scratch dirty checkout.

G-027 [proposed] Pull-based infrastructure updates for punkshell-derived projects

Scope: src/modules/punk/mix/commandset/project-999999.0a1.0.tm (project.new push path), src/modules/punkcheck-999999.0a1.0.tm (install provenance records), src/make.tcl (derived-project pull entrypoint) Detail: goals/G-027-derived-project-pull-updates.md Goal: a project generated from a punkshell layout can pull infrastructure updates (make.tcl/build.tcl, bootsupport modules and libs, layout template payloads) from its originating punkshell project by running one command inside the derived project - replacing the current push model (dev project.new -force 1 -update 1 run from punkshell) - with install provenance robust to derived-project workdir moves (not local relative paths alone), VCS-state awareness on both ends, and a recorded decision on pulling from remote sources. Acceptance: one documented command run inside a derived project updates its punkshell-derived infrastructure from the source punkshell project; the update still works after the derived project's working directory has been moved (proven by moving a scratch derived project and pulling); VCS integration on both ends: the pull applies the G-026 clean-checkout policy to the punkshell source, and reports (or refuses per option) when target files it would overwrite carry uncommitted local modifications in the derived project's git/fossil checkout; .punkcheck records remain the provenance basis (updates are recorded and unchanged targets skipped, as with existing punkcheck-tracked installs); the push flow keeps working until explicitly retired; the remote-pull question (updating from a remote punkshell repository rather than a local checkout) has a recorded design decision - implemented, or deferred with rationale in the detail file.

G-028 [proposed] Name the process locking a file when builds cannot replace a target

Scope: src/modules/punkboot/utils-999999.0a1.0.tm (locker-report helper), src/make.tcl (kit deploy failure reporting) Detail: goals/G-028-file-locker-identification.md Goal: when a build cannot delete/overwrite a target file (typically a built executable held open by another program), the failure message names the locking process(es) - via a punkboot::utils helper using the Windows Restart Manager API through optionally-available twapi or cffi, degrading cleanly to the current message when the API or bindings are unavailable or on other platforms. Acceptance: on Windows with twapi or cffi loadable, a punkboot::utils proc given a file path returns the locking processes (at least pid and process name; empty list when unlocked); punkboot::utils itself stays pure Tcl - the binary binding is required lazily at call time and its absence yields a clean 'unavailable' result, not an error (bootsupport must not gain a compiled-extension dependency); make.tcl kit deploy failures include the locker report when determinable (e.g. "could not delete target binary ... in use by: 7zFM.exe (pid 1234)"); non-Windows platforms and binding-less environments produce the existing message unchanged; verified against a deliberately held handle (documented manual verification acceptable).

G-029 [proposed] Build packaged test:: #modpod modules from src/tests

Scope: src/make.tcl (test-module packaging step), src/tests/ (source of truth), src/modules/test/ (generated #modpod targets), src/modules/punk/mix/ (modpod tooling as needed) Detail: goals/G-029-testmodules-from-srctests.md Goal: src/tests is the single source of truth for module test suites - a punkcheck-tracked make.tcl step generates the packaged test:: #modpod modules from src/tests/modules//testsuites content, ending hand-maintenance of parallel copies under src/modules/test/; the packaged form is a distributable in its own right - a user who downloads a built module can optionally download the matching test:: and verify the module's behaviour on their own system (package require + RUN, or an executable's -app test) with no source tree or test harness required. Acceptance: a make.tcl step generates a test:: #modpod under src/modules/test/ from the corresponding src/tests testsuites (punkcheck-tracked, skipped when sources unchanged); the generated package works through the packaged path - loadable via package require test:: and runnable via its SUITE/RUN interface (e.g a built executable's -app test) - reporting the same test names and pass counts as running the same suites directly via src/tests/runtests.tcl; the consumer scenario is proven standalone: the generated package (plus the module under test and their dependencies) runs in an environment without the project source tree present; suite data files (e.g roundtrip toml files with deliberate crlf/mixed line endings) survive packaging byte-for-byte; documentation states src/tests is the source of truth and the generated modpods are build artifacts not to be hand-edited; proven end-to-end for at least one real module (tomlish, whose src/tests port and still-live modpod created the dual-copy situation, is the natural first).

G-030 [proposed] make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags

Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) Detail: goals/G-030-maketcl-punkargs.md Goal: make.tcl - the first surface a developer sees - parses its subcommands and options via punk::args and showcases the tabled usage output for help and argument errors, every interactive y/n prompt gains a declared flag equivalent so agents can drive make.tcl with arguments instead of piped input, punk::args joins the bootstrap-tracked staleness set, and the boot phase plus the environment-repair commands keep working with degraded plain help when the bootsupport punk::args (or the table-rendering stack) is stale or unavailable. Acceptance: tclsh src/make.tcl and -help render punk::args tabled usage listing every subcommand with a summary, and make.tcl help <subcommand> (or <subcommand> -help) shows that subcommand's definition; invalid arguments produce a punk::args usage error rather than ad-hoc messages; every y/n prompt has a documented flag equivalent (proven at least for vfscommonupdate and the project-build confirmations: a run with the flag completes non-interactively with stdin closed) and a non-interactive stdin without the flag fails fast with usage rather than hanging or half-aborting; punk::args is added to the bootstrap-tracked buildversion set with the doc contract updated (src/bootsupport/AGENTS.md, src/modules/AGENTS.md); with bootsupport punk::args unavailable or unloadable, make.tcl still boots and check, bootsupport and modules remain usable with plain-text fallback help (the guarded-require degrade rule); layout make.tcl copies follow via the established sync/G-027 channels (noted, not hand-synced).

G-031 [proposed] Componentized kit boot: thin project-owned main + shared layout-owned boot core

Scope: src/vfs/_config/ (punk_main.tcl, project_main.tcl restructure), src/vfs/_vfscommon.vfs (boot core delivery), src/project_layouts/ (thin-main skeleton, via established sync channels) Detail: goals/G-031-componentized-kit-boot.md Goal: the per-project vfs main script becomes a thin project-owned file - declare the application's subcommands and launch defaults at clearly commented customization points, then hand over to a shared layout-owned boot core (vfs mounts, package modes and paths, libunknown, src-mode modpod registration) and default dispatch pulled in from within the kit - so project developers add app-specific subcommands without wading through or forking ~1000 lines of boot boilerplate, and boot improvements reach derived projects as pull-updatable payload instead of dying in vintage forks (tomlish_main.tcl: ~20 custom lines carrying a stale 500-line 2025 copy of the rest). Acceptance: punkshell's own kits boot through a thin main plus shared boot core with behaviour parity - package modes including src mode, existing tclsh/shellspy/punk/shell/script dispatch semantics, and supported vfs types (zipfs/metakit/cookfs) all unchanged; a project-specific subcommand is added by editing only the thin main at a commented customization point (proven end-to-end in a derived project - tomlish replacing its forked main is the natural first); the boot core ships as layout-owned payload (via _vfscommon/layout channels) and the thin main as a project-owned skeleton, per the G-027 ownership classification; the boot core is versioned/identifiable so a kit can report which boot-core vintage it carries (ties to G-025 stamping).

G-032 [proposed] Kit launcher dogfoods punk::args: tabled help and parsed subcommands

Scope: src/vfs/_config/ (default dispatch), src/lib/app-punkshell and sibling app packages as touched Detail: goals/G-032-launcher-punkargs.md Goal: the default launch dispatch defines its subcommands via punk::args - <punkexe> -help and argument errors render the tabled usage enumerating built-in and project-registered subcommands with summaries, and subcommand options parse through punk::args so projects can declare complex arguments - with the G-030 degradation rules (boot never fails and help degrades to plain text when punk::args or the ANSI rendering stack is unavailable). Acceptance: <punkexe> -help renders tabled usage listing all subcommands including project-registered ones, each with a summary; at least one built-in subcommand's options are declared and parsed via punk::args with tabled usage errors on invalid input (the G-015 script subcommand or the G-025 version-report subcommand are the natural candidates); a project-registered subcommand's help appears by registration alone - no edits to the shared dispatch; with punk::args or the rendering stack unloadable, boot proceeds and help degrades to a plain subcommand list; verified on both a zipfs-based and a non-zipfs kit where both remain supported.

G-033 [proposed] proj: package-mode scope prefix: visitor binary resolves dev/src against the cwd's project

Scope: src/vfs/_config/punk_main.tcl (package-mode dispatch and boot-time root discovery), src/modules/punk/repo-999999.0a1.0.tm (find_project / is_project_root - reuse or lean boot mirror), bin/AGENTS.md (mode docs) Detail: goals/G-033-proj-mode-cwd-project.md Goal: a proj: prefix on the package-mode string (e.g. punkshell proj:internal-src shell) makes the dev/src path blocks resolve against the punk project containing the current working directory - walking up to the nearest VCS repo root, the marker punk::repo::is_project_root already uses - instead of the executable's own project, so an installed ("visitor") punkshell binary, including one downloaded standalone with no source tree around it, can interactively explore a project that builds no shell-capable binary or no binary at all; the prefix scopes WHICH project, staying outside the ordered dash-list whose block order remains the same-version tie-break dial, and the explicit prefix gates the behaviour so no cd silently rebinds a normal launch. Acceptance: <installed-punkexe> proj:internal-src shell (the documented canonical visitor invocation - kit copies win same-version ties, protecting the visiting shell's infrastructure; proj:src is the documented faithful-vintage variant where the project's copies win) launched from within a punk project's tree discovers the project root by walking up from cwd to the nearest VCS repo root and feeds it to the existing src-mode path machinery (src/modules, src/bootsupport/modules, src/vendormodules on the module path, src/lib on auto_path), so the session loads the project's dev-versioned modules while ordinary version resolution still lets the project supply anything the kit lacks or exceeds; the launch reports the detected project root and effective path precedence (never a silent rebind); with no project found walking up from cwd, or a proj: string containing no root-using block (dev/src), it warns and proceeds without false rebind; proven for a standalone binary outside any source tree (internal = kit contents regardless of binary location) against a project that builds no executable (tomlish is the natural first); exe-relative src/dev discovery is unchanged for a binary that IS in a project's bin/; the packagemode help text drafted in the detail file becomes the live punk::args documentation when implemented (rendered via G-032).

G-034 [proposed] Zip-based #modpod modules mount in the shell code-interp on Tcl 8.6

Scope: src/modules/punk/mix/ (modpod mount path), vfs::zip availability in the repl code interp, src/modules/punk/cap/ (templates capability handler) Goal: zip-based #modpod modules (e.g. punk::mix::templates) mount and their punk::cap handlers register in the shell subcommand's code interp on Tcl 8.6, matching the script/main-interp context - so dev module.templates and other punk.templates-capability consumers work in an interactive 8.6 shell instead of failing with invalid command name vfs::RegisterMount. Acceptance: dev module.templates in an interactive 8.6 punk shell (shell subcommand) lists the template providers with no failed to load ZIP archive-based module / invalid command name vfs::RegisterMount / Unable to register any template providers / invalid command name ::punk::cap::handlers::templates::api_punk.templates errors, matching the script-subcommand output on the same binary (verified 2026-07-07: script works, shell fails); root cause fixed (the code interp lacks the vfs::zip library that provides vfs::RegisterMount for pre-zipfs Tcl, present in the main interp - restore it to the code interp or use an alternative modpod mount path there); Tcl 9 (built-in zipfs) behaviour is unchanged.

G-035 [proposed] Characterise mixed .tm / pkgIndex.tcl provision of the same package

Scope: src/tests/modules/punk/libunknown/testsuites/ (characterization suite), src/modules/punk/libunknown-0.1.tm and src/modules/punk/packagepreference-999999.0a1.0.tm (as characterised, fixed only if outright bugs surface), src/modules/AGENTS.md + src/lib/AGENTS.md (resulting guidance) Detail: goals/G-035-mixed-tm-pkgindex-provision.md Goal: the behaviour when the same package is provided both as a .tm module and as a pkgIndex.tcl-based library - same or differing versions, under the standard package unknown, punk::libunknown and punk::packagepreference - is characterised by committed tests, and the currently informal working rule ("avoid mixing provision forms for one package - unexpected behaviour even with libunknown's improvements") is either substantiated with the specific failure modes named in AGENTS.md guidance, or retired if the characterisation shows the machinery now handles mixing predictably. Acceptance: a committed test suite (extending src/tests/modules/punk/libunknown/testsuites/) characterises at least: same name+version provided via .tm and via pkgIndex.tcl (which registration wins, and whether it is deterministic across scan-trigger orderings) under the standard scanner, under punk::libunknown, and with punk::packagepreference active; differing versions across the two forms (version selection integrity including package prefer latest, and whether the losing form's registration lingers); re-registration effects (package forget then re-require crossing forms); surprising-but-accepted behaviours are pinned with GAP/known-quirk comments (the fossilmove characterization pattern), outright bugs fixed or filed as goals; the resulting do/don't guidance lands in src/modules/AGENTS.md and src/lib/AGENTS.md naming the characterised failure modes (or explicitly lifting the avoid-mixing rule if unwarranted).

G-036 [achieved 2026-07-08] Root-cause the Tcl 9 console+udp worker-thread event-loop wedge; minimal repro for possible upstream reporting

Scope: src/modules/shellthread-999999.0a1.0.tm, src/bootsupport/modules/shellthread-1.6.2.tm, src/modules/shellfilter-999999.0a1.0.tm (as characterised - no product-code changes required by this goal; the punkshell mitigations are separate fixes) Detail: goals/G-036-tcl9-udp-console-worker-wedge.md Goal: the Tcl 9-only wedge - a worker thread that has used a tcludp syslog socket stops servicing its event queue (timers, thread::send) when the punkshell process is console-attached, the proximate trigger of the piped-stdin exit/quit hang - is root-caused to a named component (Tcl 9 Windows console driver, tcludp, Thread extension, or a specific interaction) with the smallest demonstrating repro, so the user can decide on and manually file an upstream report. Acceptance: (reworked 2026-07-08 after the root cause was found) the wedge mechanism is identified and written up in the detail file - DONE: bundled tcludp 1.0.12's Windows per-thread UDP_ExitProc closes the process-global synchronization events, proven by dump handle-table analysis plus a live CloseHandle breakpoint and confirmed by the upstream 1.0.12->1.0.13 diff, which already fixes it (so no upstream report is required; the standalone minimal repro originally required here is waived as moot by the user); the tcl9 kits bundle tcludp >= 1.0.13 with the in-context batch harness baseline resolved - DONE 2026-07-08 (run-2 syslog workers alive vs the 4/4-wedged 1.0.12 baseline); DONE 2026-07-08 (punk::lib 0.3.0 has_libbug_udp_threadexit, surfaced via 'help tcl' in punk 0.2.1): a has_bug-style detection in the punkshell check machinery (in the vein of punk::lib::check::has_tclbug_* / punk::console::check::has_bug_*, surfaced through the same reporting as 'help tcl'/'help console') reports the vulnerable combination - simple version-based detection (loaded/bundled tcludp < 1.0.13 on Tcl 9 Windows) is sufficient, no behavioural probe needed; loose-end decisions (punk8win 8.6 kit's udp 1.0.12 swap; optional upstream tickets for residual tcludp trunk weaknesses) recorded in the detail file when made (open as of 2026-07-08 - non-gating).

G-037 [achieved 2026-07-08] Propagate platform vendor libraries into kit vfs lib_tcl trees via make.tcl

Scope: src/make.tcl (new or extended step), src/vendorlib_tcl8 + src/vendorlib_tcl9 (sources), src/vfs/.vfs/lib_tcl8 + lib_tcl9 (targets), punkcheck tracking Detail: goals/G-037-vendorlib-vfs-propagation.md Goal: platform-specific vendored binary packages under src/vendorlib_tcl/ reach the kit vfs lib_tcl trees through a make.tcl step instead of hand-copying - updating a vendored package becomes a vendorlib drop plus standard build invocations (motivating case 2026-07-08: tcludp 1.0.12 -> 1.0.13 for the G-036 wedge fix - libs, vfscommonupdate and project all completed while every kit vfs still bundled udp 1.0.12, requiring a manual copy into each vfs lib_tcl9 folder). Acceptance: with a newer package version placed under src/vendorlib_tcl9/, one documented make.tcl invocation updates the participating src/vfs/*/lib_tcl9 trees - installing the new package and removing or explicitly retiring the superseded version (no silent mixed-version provision, per the G-035 concerns) - with punkcheck-tracked provenance; which vfs folders participate is explicitly declared per kit rather than blanket-copied (kit vfs package sets may intentionally differ), with the declaration mechanism recorded (candidate home: the G-024 mapvfs toml); a subsequent make.tcl project yields kits loading the new version (provable via the tcludp case: built punk902z reports package require udp == 1.0.13 with no udp1.0.12 folder remaining in its vfs); the lib_tcl8 tree gets the same treatment or an explicit exclusion rationale in the goal record.

G-038 [proposed] Piped-to-interactive restart continues the same session (context preserved)

Scope: src/lib/app-punkshell/punkshell.tcl (eof-restart handover), src/modules/punk/repl-999999.0a1.0.tm (eof-restart done-mode that skips codethread teardown), src/modules/punk/repl/codethread-999999.0a1.0.tm (as touched) Detail: goals/G-038-piped-session-continuity.md Goal: when piped stdin ends and app-punkshell opens the interactive console shell, the session continues rather than restarts - the piped phase's codethread/code interp survives (variables, procs, namespaces, loaded packages, cwd, ::errorInfo/::errorCode) and only the input channel and repl reader are renewed - so 'set ::jjj blah' | <punkexe> shell leaves ::jjj inspectable at the prompt, replacing today's silent fresh-session swap (least-surprise violation; motivating transcripts in the detail file) and obsoleting the standalone piped-error-record mechanism this goal described before its 2026-07-08 rework. Acceptance: after 'set ::jjj blah;error xxxx' | <punkexe> shell reaches the interactive prompt: set ::jjj returns blah; the xxxx message, errorInfo traceback and errorCode are inspectable (via preserved ::errorInfo if nothing in the handover overwrites it, else a documented record - the chosen mechanism noted in the detail file); a proc defined and a package required during the piped phase remain available; a cwd change from the piped phase persists; a one-line notice at the restart says the session continued from piped input (mentioning the error when the last piped command errored, quiet otherwise); after the restart a terminal query from the code interp succeeds (e.g. help console runs its cursor-position test instead of being refused by the stale settled can_respond=0 anchor); interactive exit/quit teardown afterwards is clean (the G-036 regression harness still passes); PUNK_PIPE_EOF policy semantics and the script subcommand are unchanged; verified on both Tcl generations.

G-039 [proposed] Investigate the orphaned-shell one-core spin on a dead console

Scope: src/modules/punk/repl-999999.0a1.0.tm (console reader/event loop and EOF/error paths), src/modules/punk/console-999999.0a1.0.tm; investigation-first Detail: goals/G-039-orphan-console-spin.md Goal: the observed failure mode - an interactive punk902z left running after its hosting terminal/console went away spins roughly a full core indefinitely (observed 2026-07-08: a 37-minute orphan with a single hard-looping thread) - is reliably reproduced and root-caused, then fixed or mitigated so a shell whose console dies exits or reaches zero-CPU idle cleanly. Acceptance: a documented procedure reproduces the spin on the current kit (e.g. launch an interactive shell in a terminal, then kill/close the hosting terminal or conhost), or the investigation records the attempts made and what evidence would reopen it; the spinning code path is identified (prime suspect: a console read/event loop treating a dead console's immediate EOF/error as retryable without backoff or termination - adjacent to the console-EOF restart path G-038 takes ownership of); after fix/mitigation, the same procedure shows the orphaned process exiting or settling at effectively zero CPU within a short grace period, with live-console interactive behaviour unchanged; the wedge-scoring hazard note (orphans polluting process-liveness checks in test harnesses) is updated to match the outcome.

G-040 [achieved 2026-07-08] punk::args choice aliasing (-choicealiases) with parse normalization, display folding, and doc-lookup parity

Scope: src/modules/punk/args-999999.0a1.0.tm (parse + usage rendering), src/modules/punk/ns-999999.0a1.0.tm (cmdinfo/cmd_traverse choice resolution parity), src/modules/punk-999999.0a1.0.tm (punk::help topic argdoc as first consumer), src/tests/modules/punk/args/testsuites/, src/tests/modules/punk/ns/testsuites/ Detail: goals/G-040-punkargs-choicealiases.md Goal: punk::args supports choice aliases (-choicealiases {alias canonical ...}) accepted at parse and normalized to the canonical choice in results, folded into the canonical entry in usage display - and the punk::ns doc-lookup walk resolves choice words by the same rules as the parser (aliases, -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist) - so alias sets like punk::help's topics|help and console|term|terminal collapse to one displayed entry per topic with help X and i help X agreeing. Acceptance: a definition using -choicealiases parses an alias (and an alias prefix where -choiceprefix allows) to its canonical choice in the parse result, with -choicerestricted 0 passthrough and the deny/reserve lists honoured unchanged; usage display shows one entry per canonical choice with aliases folded (no duplicate rows; -choicelabels attach to the canonical); punk::ns::cmdinfo/cmd_traverse resolve subcommand words to docids with the same outcome as the parser for alias, prefix, denied, reserved and unknown words (the pre-goal characterization tests updated from pinned-GAP to fixed); punk::help's topic definition adopts the feature so i help lists one entry per registered topic while help h/help e still fall through to command lookup; definitions without -choicealiases behave unchanged (existing punk::args and punk::ns suites pass).

G-041 [proposed] punk::args multi-form matching: automated form selection for parsing and documentation

Scope: src/modules/punk/args-999999.0a1.0.tm (parse form selection, arg_error/usage form marking), src/modules/punk/ns-999999.0a1.0.tm (cmdhelp/synopsis closest-form indication), src/tests/modules/punk/args/testsuites/ Detail: goals/G-041-punkargs-form-matching.md Goal: for multi-form definitions punk::args determines which form(s) an argument list matches - parse without -form attempts all permitted forms instead of effectively form 0, -form accepts the documented list-of-forms restriction, and the documentation surface indicates the match ('i after cancel ' presents the cancel form; 's after cancel someid' marks the closest synopsis) - with explicit single-form restriction retained for callers that require it. Acceptance: parsing a multiform definition (after-like fixture) without -form succeeds when the args match exactly one form (the pinned GAP tests in forms.test flip to auto-selected results); an argument list matching no form (or several) produces an error naming the candidate forms rather than a form-0 type error; -form with a list of form names/indices restricts parsing to that subset (currently an 'Expected int 0-N or one of ...' error); 'i <args...>' and synopsis output indicate the best-matching form(s) for supplied args; explicit -form behaviour is unchanged; the full punk::args and punk::ns suites pass.

G-042 [proposed] Subshell-declared help topics via punk::config with defined shadowing policy

Scope: src/modules/punk-999999.0a1.0.tm (::punk::helptopic registry), src/modules/punk/config-0.1.tm (stored declaration source), src/modules/punk/repl-999999.0a1.0.tm (subshell entry/exit hooks) Detail: goals/G-042-subshell-help-topics.md Goal: a named subshell can declare its own help topics (name, aliases, summary, text content) in punk::config stored configuration - registered into the ::punk::helptopic registry on subshell entry and removed/restored on exit - so 'help' inside a customised subshell presents that subshell's topics with 'help topics' and 'i help' staying accurate (the registry already regenerates the punk::args definitions), under a defined precedence policy between topics and command-name fallthrough. Acceptance: a subshell whose configuration declares at least one custom topic shows it in 'help topics' and renders its configured content via 'help ' inside that subshell, and 'i help' lists it as a documented choice; on quit/switch-away the parent's topic set is restored (no leakage, proven by declaring a topic in a subshell and checking the parent after exit); configuration is read through punk::config (toml per G-014 - no ad-hoc parsing) and a shell with no topic configuration behaves unchanged; config-declared topics are text-content only - they cannot name code to execute (or a recorded design decision to the contrary with its sandboxing rationale in the detail file); the shadowing policy is implemented and documented: a declared topic colliding with a built-in topic is rejected (or explicitly overrides per a documented rule), a topic name shadowing a command name wins over command fallthrough as today with 'i '/'s ' documented as the command-help escape hatch; depends on G-014 for the stored-config substrate - the registry-side registration/restore mechanism may land earlier behind a programmatic API, with the config binding completing when G-014 lands.

G-043 [proposed] Subshell definition plugins: punk.subshell capability composing commandsets, help topics and config defaults

Scope: src/modules/punk/cap-999999.0a1.0.tm (+ new punk.subshell handler), src/modules/punk/overlay-999999.0a1.0.tm (commandset composition), src/modules/punk/pluginmgr-0.5.1.tm (discovery/trust layer), src/modules/punk/mix-999999.0a1.0.tm (init wiring precedent), src/modules/punk/repl-999999.0a1.0.tm (subshell entry/exit), src/modules/punk/config-0.1.tm (data-declaration overlap with G-014/G-042) Detail: goals/G-043-subshell-definition-plugins.md Goal: a named subshell's definition - commandset imports (punk::overlay), help topics (the G-042 registry API) and config defaults - can be supplied by provider packages registered through a punk.subshell capability (punk::cap handler validating declarations) and/or declared in stored config (toml per G-014, naming already-installed commandset packages - absorbing punk::overlay's "toml configuration files for defining CLI configurations" todo), with punk::pluginmgr as the discovery/safe-interp trust layer for providers not already trusted - so entering a subshell composes its command surface and help from declarations instead of hardcoded init code. Acceptance: a provider package declaring the punk.subshell capability supplies at least a commandset binding (namespace + prefix) and a help-topic set for a named subshell, and entering that subshell composes them (prefixed commands callable, topics in 'help topics'/'i help') with quit/switch-away restoring the parent surface (no leakage); the punk.subshell punk::cap handler validates declarations (malformed declarations vetoed with a useful message); a subshell's commandset composition can equivalently be declared in stored config without a provider package (G-014 substrate), and the existing hardcoded 'dev' CLI composition keeps working unchanged; declarations for capabilities with no registered handler are discoverable (query or report - closing the silent punk.isbogus gap); punk::cap pkg_unregister leaves no stale handler state (the 'destroy api objects?' review resolved); punk::pluginmgr-based discovery/loading of a provider is either demonstrated end-to-end (including .tm module loading in the safe interp) or explicitly deferred with the remaining pluginmgr gaps recorded in the detail file; G-042's registry mechanism is consumed, not duplicated.

G-044 [proposed] punk::args-driven interactive command completion and hinting in the repl (raw mode primary)

Scope: src/modules/punk/repl-999999.0a1.0.tm (editbuf/reader integration, provider seam), src/modules/punk/args-999999.0a1.0.tm + src/modules/punk/ns-999999.0a1.0.tm (introspection surfaces as consumed), src/modules/punk/console-999999.0a1.0.tm (rendering) Detail: goals/G-044-repl-command-completion.md Goal: the interactive repl (raw mode primary) offers command completion and hinting driven by punk::args documentation - the command word resolved through the same doc-lookup flow as 'i' (ensembles, subcommands, ensemble parameters) and the argument position through the definition (options, choices with parse-consistent matching, literals, form awareness per G-041) - via an activation scheme that preserves the editbuf's literal-tab support (not exclusively plain Tab), behind a per-subshell completion-provider seam so alternative-language subshells (e.g. an interactive xtal session) can replace, augment or cleanly disable the Tcl-centric completer. Acceptance: in a raw-mode interactive session a documented trigger (recorded in the detail file; a literal tab remains enterable into the editbuf) presents completions for command words, ensemble subcommands (resolved via the punk::ns doc-lookup flow without executing candidate commands), option flags and choice values (matching consistent with parse semantics: prefix/deny/reserve, and aliases once G-040 lands); a hint display shows the synopsis of the form(s) matching the partial input (consumes G-041's candidacy API when available - until then all-forms or form-0 display with the limitation noted is acceptable); no per-keystroke terminal queries are added when no completion display is active (G-013 approach note); the completer is a provider interface with the punk::args-driven implementation as the default - a subshell can declare an alternative provider or none, proven at minimum by a subshell with completion disabled showing no Tcl-centric interference (the xtal minimum bar; full xtal completion out of scope but not precluded by the interface); line-mode behaviour is unchanged unless a documented subset is added; G-013's raw editor essentials are a prerequisite and this goal does not weaken G-013's acceptance.

G-045 [proposed] punk::args definition authoring ergonomics: record continuation, @cmd unindented fields, constructed-definition normalization

Scope: src/modules/punk/args-999999.0a1.0.tm (record parsing in resolve, tstr interplay, arg_error @cmd rendering), src/tests/modules/punk/args/testsuites/ (rendering.test/defquoting.test as the safety net), src/modules/punk-999999.0a1.0.tm (::punk::helptopic::define_docs de-hacked as the consumer proof) Detail: goals/G-045-punkargs-authoring-ergonomics.md Goal: authoring punk::args definitions no longer requires backslash line-continuations or ad-hoc workarounds for multi-line records and constructed definitions - a parser-recognised record-continuation mechanism (candidate: an unquoted trailing -& token, with the detail file recording the collision analysis and the element-count disambiguation alternative), -unindentedfields honoured for @cmd fields, and constructed (string-built) definitions able to opt into the same whole-block indent normalization file-style definitions get - with the container quoting rules (braced=literal, quoted=Tcl backslash semantics, ${ escape) promoted from defquoting.test into the define documentation. Acceptance: a definition using the chosen record-continuation mechanism parses identically to its backslash-continuation equivalent (existing definitions unchanged - continuation is additive), with the token's collision rules documented and an escape/rejection story for values that legitimately match it; @cmd -help/-summary honour -unindentedfields (the rendering.test GAP rendering_unindentedfields_cmd_help_GAP flips to aligned); a constructed definition can request whole-block normalization so embedded continuation indentation behaves as in file-style definitions (the rendering_constructed_def_indent_characterization expectations updated to the chosen semantics), and ::punk::helptopic::define_docs drops its manual pre-normalization to prove it; the quoting rules from defquoting.test appear in the punk::args::define -help documentation; the full punk::args suite (128 tests incl. the rendering invariants: nesting independence, relative-indent preservation) passes with GAP tests flipped, none weakened.

G-046 [proposed] punk::args deferred -help resolution (parse-time performance + reentrancy) and rendering/value-shape fixes

Scope: src/modules/punk/args-999999.0a1.0.tm (resolve/get_dict: display-field deferral, dynamic-cache subst path, prefix writeback, string renderer, cmdhelp-facing messages), src/modules/punk/ansi-999999.0a1.0.tm (mark_columns argdoc as the reentrancy/perf testbed), src/tests/modules/punk/args/testsuites/ (GAP tests flip; perf verification) Detail: goals/G-046-punkargs-deferred-help-and-fixes.md Goal: argument resolution no longer processes -help and other display-only fields - their tstr expansion is deferred to display time (separately cached, per the existing in-source review notes) - so first parse of heavily documented commands gets measurably faster and definitions whose -help calls punk::args-parsing commands (the punk::ansi::mark_columns class) neither loop nor stall; alongside, the mechanical defects pinned by the characterization suites are fixed: @dynamic double-substituted multiline values align at their insertion column, prefix-normalized choice values keep the same shape as exact input, the -return string renderer aligns cmd-help continuations under the first line, and the misleading goodargs parse-error prefix in 'i ' output is fixed. Acceptance: parsing/argument resolution provably skips -help expansion (a definition whose -help contains a ${[...]} that would error or record its invocation shows the substitution did NOT run during a parse-only path, only for help display); first parse of punk::ansi::mark_columns drops from ~4s to well under a second with 'i punk::ansi::mark_columns' still rendering the embedded example, and a -help that parses its OWN definition id resolves or errors cleanly rather than looping; first-parse timing improves for at least one other heavily documented command (recorded in the detail file); rendering_atdynamic_multiline_help_insertion_GAP flips to all-aligned; choicegroups_imap_prefix_listwrap_GAP flips to shape-identical (prefix input yields the same plain string as exact input); the -return string renderer's cmd-help continuations align under the first line with relative indents preserved (rendering_string_renderer_characterization updated); the 'Bad number of leading values...' prefix shown by goodargs parsing in 'i string is'-style output is reworded or suppressed for the usage-display path; full punk::args and punk::ns suites pass with no non-GAP expectations weakened.

G-047 [proposed] Declared primary VCS in punkproject.toml with per-developer commit-target override

Scope: punkproject.toml (schema), punkproject.local.toml (new, uncommitted per-checkout override), root AGENTS.md (Commit Conventions (any VCS) section), .gitignore + .fossil-settings/ignore-glob (ignore rules for the local file, per the coexistence contract), src/project_layouts/ (layout template payload - default values and ignore seeding only; project.new validation is follow-on work) Detail: goals/G-047-declared-primary-vcs.md Goal: a [workflow] vcs = "<system>" field in punkproject.toml declares the team's primary upstream VCS - the authoritative interchange history and the default target for unqualified "commit"/"checkin" requests - while the same field in an uncommitted per-checkout punkproject.local.toml lets an individual developer redirect their own unqualified commit instructions to their preferred system (mixed git/fossil-preferring teams), resolution order local override > project field > filesystem detection; the declaration governs developer commit workflow only - punk internal machinery (punkcheck tracking of related projects, upstream infrastructure pull per G-027, central project discovery per G-016) remains standardized on fossil regardless of the declared field; punkshell itself carries [workflow] vcs = "git" and derived-project layout templates default to fossil. Acceptance: punkshell's punkproject.toml contains [workflow] vcs = "git", and root AGENTS.md "Commit Conventions (any VCS)" documents the resolution order (punkproject.local.toml field, then punkproject.toml field, then filesystem detection, with the existing prose as final fallback) as the source agents consult for unqualified commit/checkin requests; punkproject.local.toml is ignored by both VCS per the .fossil-settings coexistence contract (git check-ignore matches it, ignore-glob covers it, the contract's verification comparisons stay clean); a reader resolving the primary VCS anchors at the project root via the punk::repo::is_project_root marker and ignores any nested punkproject.toml/punkproject.local.toml [workflow] vcs; the fossil-machinery carve-out is recorded in root AGENTS.md alongside the field documentation (a git-primary ecosystem project still maintains its fossil repo for punkcheck/pull/discovery machinery), and the field stays advisory to G-016 discovery with detection as fallback; the mixed-team sync semantics are documented (team primary = authoritative interchange; a developer committing granularly to the secondary owns batching their work up to the primary); project version patch-bumped with a CHANGELOG entry for the schema addition; make.tcl/project.new validation of the field against detected VCS systems stays out of scope (follow-on work).