Root AGENTS.md "Git Commit Conventions" renamed "Commit Conventions (any
VCS)": the Co-Authored-By/AI-attribution ban and the Assisted-by trailer
apply to git commits and fossil checkins alike (git parses trailers
structurally, fossil comments are free text - either way the trailer is
the last line of the message). Generated projects start fossil-only but
may adopt git; punkshell itself is git-primary today and could flip.
CLAUDE.md mirror section updated to match.
G-027 detail: documentation/goals ownership design input - layout-owned
child AGENTS.md docs ride the pull channel under the
unmodified-since-install classification; project-owned skeletons (thin
root AGENTS.md, GOALS.md, goals/AGENTS.md, empty GOALS-archive.md) are
seeded once and never pulled; commit conventions are part of the seed
(developer-changeable, VCS-neutral); layout-owned marker convention;
transitive chains inherit the parent''s modified docs as their baseline.
G-012 detail: AGENTS.md template payloads recorded as the same hazard
class as live .gitignore payloads - a template AGENTS.md under
src/project_layouts/ is binding DOX for agents walking the punkshell tree
though written for generated projects; needs the same inert storage +
materialize-at-generation treatment.
First field test: the tomlish project was seeded today with the thin root
AGENTS.md + CLAUDE.md + GOALS framework this design describes.
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
Tcl 8.6 windows console channels expose no -inputmode configure key, so
punk::console guards testing -inputmode/-mode classified a real 8.6 console
as a pipe. A twapi console handle for stdin is now treated as definitive
console detection at all three affected sites (stdin only - pipe probes
still never touch the process console; mintty-as-pipes has no console
handle and falls through to the env heuristics as before):
1. get_ansi_response_payload's raw-cycling gate (introduced 0.1.5) skipped
the raw cycle for 8.6 line-mode queries.
2. is_input_console_or_tty returned a false negative, making
settle_can_respond's layer-2 heuristic settle a real 8.6 console as
unable to respond.
3. input_at_eof (introduced 0.1.2) took the pipe branch and performed its
probe read on the drained console channel. This was the line-mode query
killer: verified empirically against clean tclkits 8.6.13 and 8.6.17,
a read on a drained 8.6 console channel makes the channel driver park a
blocking cooked-mode ReadConsole; driver reads sample the console mode
when issued, not when data arrives, so the query's subsequent raw flip
cannot rescue it and the terminal response is swallowed until Enter.
Since get_ansi_response_payload calls input_at_eof immediately before
its raw cycle, every 8.6 line-mode query timed out (~500ms) with the
response later leaking to the line reader as phantom input - also the
source of increased ANSI artifacts (e.g. 'help env') once 0.7.0
brokering made code-interp queries actually reach the terminal.
Interactively verified on punksys (tcl 8.6.13, src launch): line-mode
get_cursor_pos and dec_get_mode succeed mid-command, brokered query loops
run clean, and typed-ahead lines are recovered without phantom input.
Known residue (documented in the G-007 detail notes): queries fired while
the repl reader is armed and idle at a line-mode prompt (including some
repl-init detection queries) still hit the parked-read limitation on 8.6 -
repl init ordering is a follow-up; raw mode is unaffected.
Tests: probes.test gains constraint-gated wiring tests for the twapi
console branch of is_input_console_or_tty and input_at_eof (skip in piped
runs, engage on a real console). Full suite passes at baseline (exec-14.3
only) under Tcl 9.0.3; probes suite also verified under Tcl 8.6.
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
G-001 pluggable console backends for non-detectable terminals (ssh channel, tk widget) via ::opunk::Console subclasses. G-002 non-nested subshell with console targeting and inter-subshell comms, including thread::send -async routing to the code sub-interp and the canonical launch API design (subshell as sole entry point, interp alias as context signal). G-003 configurable resource limits (command-count, time via interp limit) and sandboxing spectrum (interp hide/expose/alias, safe::interpCreate) on subshell interps, downstream of G-002's asymmetry fix.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Assisted-by: harness=opencode; primary-model=unknown; api-location=unknown
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