G-031: split the monolithic vfs main (punk_main.tcl: 1190-line apply
block - ~1060 lines boot machinery, ~100 lines dispatch tail) into a
layout-owned boot core (shipped via _vfscommon.vfs, sourced by
vfs-relative path since no package paths exist at boot; pull-updatable
per the G-027 ownership model) and a thin project-owned main declaring
app subcommands at commented customization points. Fork cost measured:
tomlish_main.tcl carries ~20 custom lines on a stale 500-line 2025
vintage copy; project_main.tcl (901 lines) same at template vintage -
boot improvements never reach derived projects. Acceptance: behaviour
parity across dispatch cases and vfs types, project subcommand added by
editing only the thin main (tomlish the proving ground), boot core
versioned/reportable (G-025).
G-032: the default dispatch defines subcommands via punk::args - tabled
-help enumerating built-in and project-registered subcommands, parsed
options with tabled usage errors (script/G-015 or version-report/G-025
as first candidates), G-030 degradation rules (guarded require; parsing
falls back to switch semantics, help to a plain list; rendering degrades
independently). Parked decision: the silent unknown-arg->script
reclassification should stop swallowing typos (candidate rule:
reclassify only when the argument names an existing file).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
G-030 (proposed): make.tcl - the first surface a developer sees - parses
subcommands/options via punk::args and showcases the tabled usage for
help and argument errors; every interactive y/n prompt gains a declared
flag equivalent (interactive stdin prompts as today; flag proceeds;
non-interactive stdin without the flag fails fast with usage instead of
hanging or half-aborting) so agents drive make.tcl with arguments rather
than piped y/n; punk::args joins the bootstrap-tracked staleness set.
Degradation is a hard requirement: boot stays self-contained and the
repair commands (check/bootsupport/modules) keep working with plain
fallback help when the bootsupport punk::args or the ANSI rendering
stack is stale/unavailable - this week''s stale-fileutil and
stale-textblock incidents are the cautionary tales.
G-015 detail: recorded the runx -tcl result-shape observation (dict keyed
{result stdout stderr}, no exitcode key unlike exec mode).
G-020 detail: stamped the 2026-07-07 decision - acceptance gates on a
full testable Windows system without requiring other platforms first.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
src/tests becomes the single source of truth for module test suites: a
punkcheck-tracked make.tcl step generates the packaged test::<modulename>
#modpod modules from src/tests/modules/<namespacepath>/testsuites,
ending hand-maintained 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::<modulename> and verify the module''s behaviour on their own
system - package require + RUN interface, or a wrapped executable''s
-app test - with no source tree or harness. Acceptance proves the
standalone consumer scenario (runs without the project source tree),
suite-result parity with src/tests/runtests.tcl, and byte-for-byte
data fidelity (crlf roundtrip fixtures).
Motivated by the tomlish dual-copy interim (its modpod testsuites were
ported to src/tests while the modpod remains the live test::tomlish
build source - tomlish checkins 20bd00dc, feedb6f0).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Motivated by a make.tcl project deploy failure ("could not delete target
binary") where the locker turned out to be 7-Zip inspecting the exe -
identifying it took several dead ends because Windows has no cheap
file-to-process reverse lookup (name matching and Process.Modules scans
both miss plain file handles; openfiles needs a pre-enabled global flag;
handle.exe is external and elevation-bound).
G-028: a punkboot::utils helper returns the locking processes via the
Windows Restart Manager API (the installers-grade answer to "who is
blocking this file"), with twapi or cffi required lazily at call time -
punkboot::utils stays pure Tcl per the bootsupport no-compiled-extensions
contract, and unavailability degrades to the existing message. make.tcl
kit deploy failures append the locker report when determinable. Recurring
customer: G-023 versioned/dev binaries rewritten every build.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Projects generated by dev project.new receive a layout snapshot that
drifts; the current remedy is a push from punkshell (project.new -force 1
-update 1). G-027: one command run inside the derived project pulls
make.tcl/build.tcl, bootsupport modules/libs and template payloads from
the originating punkshell project - .punkcheck records remain the
provenance basis, origin identity becomes durable to workdir moves (not
relative paths alone; projects.work discovery as re-locator), VCS
awareness on both ends (G-026 clean-checkout policy on the source,
uncommitted-local-modification detection on the target), and the
remote-pull question gets a recorded decision.
Detail file records the motivating incident (tomlish 2026-07-06: a stale
make.tcl whose bootsupport updater was disabled by the very drift it
needed to fix - broken bundled fileutil::traverse under Tcl 9) and the
constraint that the pull entrypoint must not depend on the freshness of
what it updates.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
make.tcl vendorupdate now walks up from each vendor source path to the
nearest fossil and/or git root and warns (non-fatal, once per VCS root)
when the checkout is dirty - vendored artifacts built from uncommitted
source have no committed provenance. Silent for unversioned or missing
locations; dual git+fossil roots report each VCS separately. First real
run flagged 8 dirty source projects (the tomlish 1.1.7/1.1.8 incident -
vendored content whose source history ended at 1.1.6 - motivated this,
remedied upstream by tomlish checkin 37b71e82).
Goal G-026 (proposed) carries the enforcement follow-on: abort with
explicit override, warn-only as configured mode, shared coverage of
bootsupport_localupdate, and a recorded decision on the residual
staleness gap. Abort-by-default now would block routine work given the
dirty-project count.
Project version 0.2.5; vendorupdate doc note in src/AGENTS.md.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
G-023: builds produce punk8|9-<major>-<minor>-<patch>.exe from the
punkproject.toml version plus punk8|9-dev.exe tracking the latest build;
plain punk8|9.exe created initially and replaced only by an explicit
release step. Disk growth tolerated for now; archival/deletion trigger
recorded as a later question.
G-024: src/runtime/mapvfs.config converted to toml parsed via tomlish -
explicit runtime/vfs/name/kittype mappings preserved, plus generative
scheme declarations so the G-023 versioned outputs are one succinct entry
rather than per-version lines. Entry-level validation errors; full
migration preferred over a deprecation window.
G-025: build stamps project version, runtime binary and vfs folder into
the kit; a version-report subcommand prints them machine-parseably, with
the same-named punk-module command as the single implementation (the
subcommand is a thin wrapper) so scripts get the report in-process. Report
keeps build stamp, live runtime facts and source-tree version distinct:
src-mode sessions report stamp and live versions separately when they
differ; unstamped contexts (tclsh src/make.tcl shell, plain tclsh with
punk modules) report stamp fields absent rather than fabricated.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Goal G-022: scriptable safe fossil move/rename in dev repo (all checkouts
repointed, no phantom central config-db entries, no dangling old repo db,
project-name renamable with project-code preserved), then rename this
project fossil repo shellspy -> punkshell through that mechanism via a
G-015 piped script call.
New tests src/tests/modules/punk/mix/testsuites/repo/fossilmove.test pin
current behaviour in a FOSSIL_HOME-isolated sandbox with an isolation
guard: the file-copy + fossil test-move-repository sequence repoints the
checkout but leaves the old db file on disk, a phantom repo: entry in the
central config-db, and a stale ckout: back-reference; file moves never
touch project-name. GAP-marked tests flip when G-022 lands.
shellrun 0.1.4: add missing package require punk::args - the 0.1.3
migration left run/runout/runerr/runx calling punk::args::parse without
requiring it, which broke shellrun in bare interps and made every
src/tests/runtests.tcl run fail at test-file invocation. Full suite now
back to baseline (523 tests: 508 pass, 14 skip, exec-14.3 known failure).
Project version 0.2.4 (changelog entry for the shellrun fix).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
G-018: zig-built plain zip-based tclsh kits with no punk infrastructure
(Tcl 9 kit satisfies acceptance; 8.6 interim = plain non-kit builds, kits
when practical, non-gating). Notes record that wish executables are never
a build target - Tk ships as a loadable package.
G-019: dependency-scan-driven module trimming for punk executables via the
tclparser parse API (c-only library today; punk::lib pure-Tcl fallback is a
stub), with a declared-extras manifest for scan-invisible dynamic requires;
batteries-included builds preserved.
G-020: screen capture + input injection module with per-platform backends -
Windows first (treectrl loupe + twapi, all already shipped in punk9win kit);
X11 (Linux/FreeBSD) and macOS follow behind the same contract; Wayland-native
out of scope. Platform show-stopper assessment recorded in the detail file.
G-021: agent-drivable visual/UI verification - window match, snapshot to
PNG/base64, scripted interactions - through G-015 piped script calls, with
guidance to land alongside G-017. aloupe.tcl stays a standalone app.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
G-015: complete the punk executable `script` subcommand - run a script file
or piped stdin (scriptname optional) in an interp preloaded with the default
punk shell modules/aliases, honest exit codes, no shellfilter transforms, no
interactive-shell fallthrough. Replaces the fragile `...;exit | punkexe`
repl-pipe pattern (currently a stub in punk_main.tcl that only emits stderr
diagnostics). Lean bare-script execution deferred to a later `tclsh`
subcommand expansion.
G-016: extend `dev projects.work` to discover git-based projects alongside
fossil (git has no central registry - enumeration-source candidates recorded
in the detail file).
G-017 (index-only): once G-015 lands, direct agents via repo guidance to
locate sibling projects with a piped projects.work call instead of scanning
the filesystem.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Scope gains the vendored tomlish module (canonical source in the external
tomlish project space). Goal line rules out ad-hoc toml parsing; acceptance
now requires the tomlish API procs punk::config consumes to carry punk::args
(PUNKARGS) documentation, added upstream and re-vendored before punk::config
implementation proceeds. Detail file records the 1.1.8 coverage gap: argdocs
exist only on the cmdline app layer, not the library API (from_toml, to_dict,
from_dict, update_tomlish_from_dict).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
G-013: raw input mode as the repl default - per-keystroke debug
emissions (add_chunk frame, rhs editbuf view) individually gated and
repl-toggleable, raw editor parity for history/cursor movement,
debugrepl marked-line form retained for simple terminals with its
first-word activation mechanism under review; retires the tcl 8.6
idle-prompt query residue guarded in punk::console 0.7.1.
G-014: complete ::punk::config - toml files in the XDG config dir with
per-named-subshell override/inherit resolution; first consumer is the
G-013 editbuf-view startup default. Write-back persistence deferred.
Both proposed; detail files under goals/.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Project layouts carry .gitignore files as payload for generated projects,
but git treats any nested .gitignore as live configuration scoped to its
directory - the templates self-censor, silently untracking their own
content in the outer repo (discovered via the git/fossil tracked-set
verification; stopgap force-adds in fc1c474c). G-012 [proposed] requires
payloads stored inert (neutral rename or fauxlink-encoded - mechanism an
implementation decision recorded in the detail file) with materialization
at project generation, plus a punkcheck-tracked make.tcl template-refresh
step generalising the existing sync_layouts (which covers only
build.tcl/make.tcl into custom/_project) to the vendor/punk layout base
and derived payloads. Acceptance covers a provably-inert nested-rule scan,
generated-project content equivalence, a working refresh after a
canonical-source edit, and retiring the per-file force-add exceptions.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Flip G-007 (location-transparent punk::console) to achieved 2026-07-05 in the
GOALS.md index and detail file. Interactive verification on built punksys
(tcl 8.6) and punk902z (tcl 9) kits (punk::console 0.7.0, opunk::console
0.4.0; punk902z also rerun via src launch against dev modules): fact parity
and immediate cross-context visibility in both directions; brokered terminal
queries from the code interp succeed and cooperate with the repl reader in
raw mode with typed-ahead preserved; a chan-pipe console anchored from the
code interp registers its codethread as owner, operates locally, and clears
its registry entry on forget.
Detail-file Notes record the verification and characterize line-mode reader
cooperation (out of scope, no routing regression - brokered and owner-side
queries behave identically): on tcl 9, complete typed-ahead lines survive
with cosmetic garbling while incomplete typed-ahead starves the query raw
window and leaks responses as phantom input; on tcl 8.6 every line-mode
query fails that way, owner-side included (repro:
repl eval {punk::console::get_cursor_pos}) - candidate owner-side regression
to investigate separately. Also noted: the leaked stderr diagnostics are the
traffic G-011's per-console err channel would house.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Acceptance now names the discovery fact (console_fact_get fact key err,
returning the effective err channel name) so the clause is testable like
G-007's named facts. Detail file additions: "every -console site" is
satisfied at the module's documented resolution choke points
(console_spec_resolve, hybrid_console_spec, opt_console_* helpers,
spec_to_channelpair, shared PUNKARGS fragments) rather than by per-site
audit; the two consumer-shaped acceptance clauses' division of labour is
stated (internal diagnostics migration = first consumer, external consumer
= public emit form); G-001 backends wanting a distinct diagnostic stream
must set err explicitly (default merges into out); and
previous_stty_state_stderr stays as-is (stty-state restoration, orthogonal
to diagnostic routing).
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
punk::console models two channels per console ({in out}); its own
diagnostics fall back to raw puts stderr and subshell/backend/theme goals
(G-001/G-008/G-009) inherit the dual-channel assumption. G-011 defines err
as an attribute of the canonical {in out} console identity: {in out err}
specs accepted everywhere -console is, a nullable err field on
opunk::Console, err defaulting to process stderr for the default console
and to the console's out channel elsewhere, console-directed diagnostics
and an emit-to-err path, and cross-thread discovery via console_fact_get.
Ownership/fact/mode-cache keys stay canonical {in out}, so the G-007 work
is untouched.
Detail file records the gap analysis, the rejected shapes (err-in-identity
triple key, scope-boundary-only, uniform err==out, unset-means-none) and
the G-001 sequencing interaction.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Per-console facts are now visible to every thread of a punk session: the
default console {stdin stdout} keeps its legacy namespace variables as
authoritative local storage, with write traces mirroring every write
(including direct variable writes) into tsv punk_console_facts; non-default
consoles store facts only in tsv with owner-qualified keys (non-std channel
names are thread-local and would otherwise alias). console_fact_set from a
non-owner thread forwards to the owning thread (vt52-alias transport) and
always writes the tsv mirror itself (covers unreachable or older-version
owners). New console_fact_clear for tests/maintenance.
New console ownership registry (console_owner_register/get/forget, tsv
punk_console_owners keyed by canonical {in out} pair): ownership is captured
when an opunk::console instance is anchored - via the new pluggable
::opunk::console::lifecycle_callback (opunk::console 0.4.0, base class
unchanged) wired by ensure_object_integration - and by default_console.
Consult-time liveness validation clears entries for exited threads. For
{stdin stdout} first registration wins and only the owner's forget releases
the entry, so a thread anchoring a local view cannot steal ownership.
dec_has_mode/ansi_has_mode caches moved to tsv punk_console_modecache
(single-key atomic entries shared process-wide).
Infrastructure tsv arrays are now punk_-prefixed to avoid collisions with
application tsv usage in subshells: console -> punk_console (is_raw), with
call-site patches in punk::repl 0.2.1, punk::lib 0.2.1, punk::basictelnet
0.1.1 (rule recorded in src/modules/AGENTS.md; legacy repl/codethread_*/
zzzload_pkg* arrays left for a coordinated follow-up).
punk::console is now loadable in secondary threads without ::argv0
(powershell consolemode fallback guarded).
Tests: consolefacts gains ownership-registry and cross-thread visibility
coverage (worker-thread punk::console load, trace-mirror, forwarded set with
deadline-polled sync - see comments re runtests child-interp topology);
cleanups use console_fact_clear / tsv instead of poking removed internal
stores. Full suite passes (baseline exec-14.3 only).
G-007 flipped proposed -> active (user-confirmed); remaining acceptance work
is the choke-point brokering slice.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Index entries in GOALS.md plus detail files, all proposed:
- G-007 location-transparent punk::console across repl and code
interps: punk-side tsv-backed ownership registry, fact/cache
visibility, choke-point brokering generalising the vt52 alias;
detail records rejected alternatives (audience namespace split,
owner field on ::opunk::Console, opunk-package-namespace registry)
- G-008 scoped console state for same-console subshells: activatable
per-subshell state sets (journal-on-write, re-emit on activation)
rather than a LIFO undo stack, so later tree switching works;
restore of tabstops/modes/palette on quit; opt-in, shared behaviour
stays default
- G-009 themed subshell profiles: poshinfo schemes bound to
restriction aspects (G-003 limits/hidden commands, punk::island) so
restricted subshells are visually distinct; terminal effects ride
the G-008 state set
- G-010 subshell suspend/resume and tree navigation: switch to any
live subshell (grandparent, cross-branch) via attachment handoff +
G-008 state activation; navigation commands governed by G-003
hide/expose; depends on G-002's non-nested model
Sequencing: G-007 -> G-008 -> G-009/G-010, with G-002 prerequisite
for G-010.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Index entries in GOALS.md plus detail files. G-004 targets a binary-free
committed tree, achievable once G-005 (zig-based build of binary deps from
source) or G-006 (consent-gated download of pre-built artifacts) provides
the replacement supply of the previously committed binaries.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
Harness-agnostic technical project goal system. GOALS.md holds the canonical one-line index with format spec, status taxonomy, maintenance rules, and an agent-authoring workflow so agents asked to 'help me write a goal for X' ask the right questions. GOALS-archive.md is the achieved-goals archive stub. goals/AGENTS.md is the DOX child doc covering naming (G-<id>-<slug>.md), when a detail file is warranted, and the no-orphans/archive rule. goals/archive/.gitkeep tracks the archive dir.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Assisted-by: harness=opencode; primary-model=unknown; api-location=unknown