6.0 KiB
G-031 Componentized kit boot: thin project-owned main + shared layout-owned boot core
Status: proposed 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) 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).
Context
src/vfs/_config/punk_main.tcl is a 1190-line single apply block mixing two
very different concerns:
- Boot machinery (~1060 lines): vfs mount detection (zipfs/metakit/cookfs), starkit handling, package-mode token parsing (dev/os/src/internal), module and auto_path setup, libunknown, src-mode #modpod registration.
- Application dispatch (~100 lines at the tail): subcommand extraction and the tclsh/shellspy/punk/shell/script cases.
Every kit's main.tcl is already a fauxlink to one such file per project
(main.tcl#..+_config+<name>_main.tcl#@punk::boot,merge_over), and derived
projects fork the whole file to customize the tail. Measured cost (2026-07-07):
- tomlish_main.tcl: 547 lines, of which the genuinely tomlish-specific dispatch tail is ~20 lines - the rest is a 2025-vintage copy of the boot boilerplate, already 632 diff-lines adrift from current punk_main in the first 450 lines. Boot improvements since (src mode, modpod registration) never reached it.
- project_main.tcl (layout template): 901 lines, same story at template vintage.
A project developer wanting one custom subcommand must wade through - and then permanently own - a thousand lines of boot code.
Approach
- Split into:
- Boot core (layout-owned): the boot machinery plus the default dispatch,
shipped inside the kit via _vfscommon.vfs (every kit already merges it) and
sourced from the thin main by vfs-relative path. Layout-owned per the G-027 ownership classification -> pull-updatable in derived projects, so boot fixes propagate instead of dying in forks. - Thin project main (project-owned skeleton): declares project subcommands and launch defaults at clearly commented customization points, then hands over to the boot core. This is the file a project developer reads and edits.
- Boot core (layout-owned): the boot machinery plus the default dispatch,
shipped inside the kit via _vfscommon.vfs (every kit already merges it) and
- Boot-phase constraint: the boot core cannot be a package (no package paths exist yet) - it is sourced by vfs-relative path from the thin main. The default dispatch portion runs post-boot and may be package-based if that proves cleaner; record the split point here when decided.
- Registration model: the thin main declares subcommands (name -> handler package/command, plus optional punk::args definition id for G-032) before invoking the default dispatch; built-ins (tclsh/shellspy/punk/shell/script, and G-025's version-report) come from the boot core, project additions merge in. Default-subcommand and no-args behaviour are declared, not hardcoded (a shell-like default remains the punkshell behaviour; a tool-like default such as tomlish's -help injection becomes a declared choice).
- Boot core carries its own version/identity so a kit can report the boot vintage it embeds (G-025 stamping is the natural vehicle).
- Layout skeletons follow through the established sync channels (custom/ _project sync step now; G-012/G-027 for the rest) - noted in completion reports, never hand-synced.
Alternatives considered
- Leaving the monolith and documenting "edit the tail" - rejected: the fork cost is proven (tomlish, project_main both adrift); documentation does not stop vintage divergence, pull-updatable payload does.
- Making the entire main (incl. dispatch tail) layout-owned and pushing project customization into data/config only - rejected for now: subcommand handlers are code; a thin project-owned code file with a clear contract is simpler than inventing a config schema for arbitrary launch behaviour. Revisit if the thin mains themselves start accreting boilerplate.
Notes
- Sequencing with G-015: resolved - G-015 proceeded first on the monolith (achieved 2026-07-07 as the dedicated app-punkscript package, see goals/archive/G-015-script-subcommand-piped-stdin.md), so its dispatch logic moves into the boot core here and this goal must preserve the script subcommand's behaviour.
- Related: G-027 (ownership + pull channel this is designed for), G-025 (boot-core vintage reporting), G-032 (punk::args-defined dispatch built on the registration model), G-012 (layout payload hygiene), G-018 (plain tclsh kits deliberately carry NO punk boot layer - out of scope here).
- The tomlish silent-exe incident (2026-07-07, tomlish 1.1.10 fix) is a reminder that launch-path contracts are easy to break invisibly - behaviour parity in the acceptance means exercising each dispatch case, not just booting.