Browse Source

G-033 revised: proj: scope prefix, kit-first canonical, help text persisted

Design review outcomes (2026-07-07):
- Syntax: proj is not a fifth ordered token (category error - the dash
  list is an ordered sequence of path blocks whose order IS the
  same-version tie-break dial, per the verified tm rules and punk_main''s
  own comment). Decided form: [proj:]<block>[-<block>...] - the prefix
  scopes WHICH project root dev/src resolve against (cwd walk-up to the
  nearest VCS repo root vs exe-relative), staying outside the ordered
  list whose semantics are untouched. Explicit prefix = no silent rebind
  on cd. Rejected: auto-detection, an explicit flag (less convenient),
  token-attached qualifiers.
- Shadowing: visitor mode makes cross-lineage same-version-different-code
  ties structurally expected (binary and visited project snapshots are
  different vintages by definition). Order only arbitrates exact ties -
  dev-versioned, higher-versioned and kit-absent modules come from the
  project in either order. Canonical documented invocation is
  proj:internal-src (kit-first: the visiting shell''s infrastructure
  survives ties; for a standalone downloaded binary the kit is its only
  trustworthy lineage and internal is location-independent); proj:src
  documented as the faithful-vintage variant. Trimmed kits (G-019)
  compose gracefully - kit-first only arbitrates ties.
- Required boot notice: detected root + effective precedence.
- packagemode help text drafted and persisted in the detail file as the
  designated G-032 source (live only when the prefix ships); G-032 detail
  cross-references it.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
062ec6fe93
  1. 6
      GOALS.md
  2. 5
      goals/G-032-launcher-punkargs.md
  3. 206
      goals/G-033-proj-mode-cwd-project.md

6
GOALS.md

@ -241,11 +241,11 @@ 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: visitor binary detects the cwd's project and explores it
### 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: an explicit `proj` package-mode token lets an installed ("visitor") punkshell binary - one not built from the project - detect 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) and set up source/dev library resolution against THAT project, so a user can run e.g. `punkshell proj shell` from anywhere inside a project (which need not build its own shell-capable binary, or any binary at all) and explore it interactively; the token gates the behaviour so no `cd` silently rebinds a normal launch.
Acceptance: `<installed-punkexe> proj shell` launched from within a punk project's tree (the binary not belonging to that project) discovers the project root by walking up from cwd to the nearest VCS repo root and adds that project's src/modules, src/bootsupport/modules and src/vendormodules to the module path and src/lib to auto_path (the existing src-mode path machinery, parameterised on the cwd-detected root), so the session loads the project's dev-versioned modules; the detection marker matches punk::repo::is_project_root (a git or fossil repo root, not reliance on punkproject.toml); with no project found by walking up from cwd, `proj` warns and proceeds as `internal` with no false rebind; it works for a project that builds no executable of its own (proven against tomlish or a modules-only project); exe-relative `src`/`dev` discovery is unchanged for a binary that IS in a project's bin/; `proj` composes with the built-vs-source selectors (at least a documented default - proj implying source-tree resolution - with proj+dev / proj+src semantics recorded).
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)

5
goals/G-032-launcher-punkargs.md

@ -26,6 +26,11 @@ in `-help` by registration alone.
with @cmd summaries, package-mode leader documented) and per-subcommand
options. `<punkexe> -help`, `<punkexe> help <subcommand>`, and
`<subcommand> -help` all render tabled usage.
- The packagemode leader's help text is pre-drafted in G-033's detail file
(block semantics, ordering-as-tie-break rule, the `proj:` scope prefix with
the kit-first `proj:internal-src` canonical example) - use that as the source
text, noting the `proj:` portions go live only when G-033 implements the
prefix.
- Parse errors on declared subcommands produce punk::args usage errors
(tabled), not silent fallthrough. The unknown-first-arg -> script
reclassification survives only where it does not swallow obvious mistakes -

206
goals/G-033-proj-mode-cwd-project.md

@ -1,4 +1,4 @@
# G-033 `proj` package-mode: visitor binary detects the cwd's project and explores it
# G-033 `proj:` package-mode scope prefix: visitor binary resolves dev/src against the cwd's project
Status: proposed
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)
@ -7,68 +7,153 @@ Acceptance: as in root GOALS.md index (canonical).
## Context
The earlier intent (recalled 2026-07-07): an installed punkshell binary sitting
in PATH - possibly a downloaded binary, not built from the project - should be
able to detect when the cwd is inside a punkshell project and set up the
appropriate source/dev library resolution for it, so the user can explore that
project interactively via the `shell` subcommand. The project being worked on
might not build a shell-capable binary, or might build no executable at all
(e.g. a modules-only project like a library).
in PATH - possibly a downloaded binary, not built from any local source tree -
should be able to detect when the cwd is inside a punkshell project and set up
the appropriate source/dev library resolution for it, so the user can explore
that project interactively via the `shell` subcommand. The project being worked
on might not build a shell-capable binary, or might build no executable at all
(e.g. a modules-only project).
History check: this was **never active** in the full sense. `src` mode is new
(checkin 3d2d098d) and discovers the project root **exe-relative** (backtrack
from the executable's `bin/`) - it assumes the binary belongs to the project.
`dev` mode is likewise exe-relative. `os` mode is the only cwd-relative piece,
and only shallowly (adds `[pwd]` and cwd-relative `modules`/`modules_tcl<N>`
ad-hoc `.tm` sources - no walk-up, no `src/` structure). The comments in
punk_main.tcl name "the info nameofexecutable or info script or pwd relative
paths" as design axes, so the *intent* seeded `os` mode, but cwd project-
structure detection was never built into the boot modes.
Crucially, the cwd-relative detector **already exists at the runtime layer**:
from the executable's `bin/`); `dev` is likewise exe-relative; `os` is the only
cwd-relative piece and only shallowly (adds `[pwd]` and cwd-relative
`modules`/`modules_tcl<N>` ad-hoc `.tm` sources - no walk-up, no `src/`
structure). The comments in punk_main.tcl name "the info nameofexecutable or
info script or pwd relative paths" as design axes, so the intent seeded `os`
mode, but cwd project-structure detection was never built into the boot modes.
The cwd-relative detector **already exists at the runtime layer**:
`punk::repo::find_project` walks up from cwd via `is_project_root`, and `dev`
commands (module.templates, module.new, ...) already use it. So the marker
commands (module.templates, module.new, ...) already use it. The marker
question is answered: `is_project_root` defines a project as a **VCS repo root**
(git or fossil) that is not an excluded location - deliberately NOT relying on
`punkproject.toml` (its own comment notes that file also appears in layout
templates, and tomlish has no punkproject.toml yet but IS a fossil root). This
goal aligns the boot-time package modes with that existing runtime detection.
templates; tomlish has no punkproject.toml yet but IS a fossil root). This goal
aligns the boot-time package modes with that existing runtime detection.
## Syntax: scope prefix, not a fifth token (decided 2026-07-07)
The existing modes (internal/dev/src/os) are **ordered path-source blocks**:
punk_main assembles `new_tm_path` token-by-token in dash-string order, and
because the head of tcl::tm::list wins same-version ties (rules verified
2026-07-06), **earlier blocks win same-version collisions** - deliberately so
(punk_main comment: "the lib/module paths based on the project being run should
take preference if 'dev' is earlier in the list, even if the version number is
the same"). The dash-list is the user's tie-break dial.
`proj` answers a different question - WHICH project root dev/src resolve
against - so it has no meaningful position in that ordering; a positional token
(`os-proj-src-internal`) reads as noise because it is a category error. Decided
syntax:
[proj:]<block>[-<block>...] e.g. proj:internal-src
- The `proj:` prefix scopes root discovery to cwd-walk-up; everything after the
colon is the unchanged ordered block string with unchanged semantics.
- A `proj:` string containing no root-using block (dev/src) warns that proj has
no effect (os/internal do not reference a project root).
- Parser impact is small: recognise an optional `proj:` prefix on arg 0, strip
it, then validate dash-tokens as today. Explicit prefix = opt-in; no `cd`
silently rebinds a normal launch.
- Rejected: automatic cwd-detection without a token (silent rebind surprise);
an explicit -flag route (less convenient for everyday use - user decision);
a token-attached qualifier like `src@proj` (binds the root choice to a
precedence slot; the root choice is launch-wide).
## Same-version shadowing: why kit-first is the canonical default (decided 2026-07-07)
Order only decides **exact-version ties**. The project's own code is unaffected
by the choice: dev-versioned modules (999999.0a1.0, package prefer latest) and
higher-versioned modules load from the project in either order, and anything
absent from the kit has no tie so the project supplies it. The decision governs
only same-version-different-content drift - rare within one lineage (punkshell
version-bump discipline, G-026 provenance), but **structurally expected in
visitor mode**, where the binary and the visited project's bootsupport/
vendormodules snapshots are different vintages by definition.
Failure modes are asymmetric:
- Project-first (`proj:src`): faithful to the project's snapshot vintage
(reproduces its bugs), but the visiting shell's own machinery loads the
project's older copies - a stale project can degrade the visiting shell
(the 2026-07-06 stale-textblock/shellfilter silent-stdout class, imported).
- Kit-first (`proj:internal-src`): the binary's tested infrastructure survives
ties; robust session; drifted same-version project copies are silently
masked (less faithful, invisible when it matters).
**Canonical documented invocation: `proj:internal-src` (kit-first).** The
project's genuinely-own code wins in either order; ties involve infrastructure
snapshots nobody explores; and for a standalone downloaded binary the kit is
its only trustworthy lineage. `proj:src` is documented as the faithful-vintage
variant for reproducing a project's behaviour exactly. No special-casing: both
fall out of the existing ordering semantics (explicit `internal` placement),
preserving one uniform mental model.
Standalone-binary semantics (downloaded, installed on PATH, no source tree):
- `internal` = the kit's own vfs contents - location-independent; kit-first
needs nothing from any source tree.
- plain `src`/`dev` (exe-relative) find no project and degrade to warned no-ops
(existing behaviour) - `proj:` is precisely what gives such a binary a
project context.
- Trimmed kits (G-019) compose gracefully: kit-first only arbitrates ties, so
modules missing from a trimmed kit still flow from the visited project.
- Note for docs: installing a binary INTO some project's bin/ makes exe-relative
modes adopt that project (by design - adoption by location).
## Required boot notice
A `proj:` launch must report the detected project root and the effective path
precedence (and warn-and-proceed when no project is found walking up from cwd)
- the rebind must never be silent. Candidate (non-acceptance) hardening: a
shadow-report diagnostic listing name+version collisions between kit-internal
and project paths, pairing naturally with G-025's buildinfo.
## packagemode help text (source draft for G-032)
This is the designated source text for the packagemode leader in the launcher's
punk::args definition (G-032 renders it; making it live is part of THIS goal's
implementation - live help must not describe unimplemented behaviour, so it
ships with the prefix, not before):
packagemode -optional 1 -default internal -help
"Package-source mode: an ordered dash-separated list of path blocks,
optionally scoped with the 'proj:' prefix.
Blocks (each adds a group of module/library paths):
internal - paths inside the executable's kit (always included;
appended last unless listed explicitly)
dev - the project's built output (<projectroot>/modules ...)
src - the project's unbuilt source (src/modules,
src/bootsupport/modules, src/vendormodules, src/lib)
os - ad-hoc .tm paths from the current directory/environment
Without 'proj:', dev/src resolve against the executable's own project
(executable in <projectroot>/bin). With 'proj:', they resolve against
the nearest project root at or above the current directory (a git or
fossil repository root) - for an installed punkshell binary visiting
a project that builds no shell of its own.
ORDER MATTERS: earlier blocks win when the same version of a module
exists in more than one location.
Examples:
src work on the executable's own project source
proj:internal-src explore the cwd project; the executable's own
copies win version ties (robust visitor default)
proj:src explore the cwd project; ITS copies win version
ties (faithful to the project's snapshot vintage)
The launch reports the detected project root and effective precedence."
## Approach
- New explicit token `proj` in the package-mode list (dev/os/src/internal/proj).
Explicit gate = no `cd` silently rebinds a normal launch; the visitor
behaviour is opt-in.
- On `proj`: walk up from `[pwd]` to the nearest VCS repo root (the
`is_project_root` marker) and use that as the project root, then feed it into
the **existing src-mode path machinery** (which is already parameterised on a
root variable - adds src/modules, src/modules_tcl<N>, src/bootsupport/modules,
src/vendormodules to the tm path, src/lib to auto_path, registers #modpod
modules, sets package prefer latest). The only new part is cwd-relative
*discovery*; the setup is reused.
- Boot chicken-and-egg: `find_project`/`is_project_root` live in `punk::repo`,
which is not loadable at the early package-mode phase (punk_main.tcl avoids
package requires there by design). Options, decision to record: (a) a lean
inline VCS-root walk-up in punk_main mirroring is_project_root (fossil:
_FOSSIL_/.fslckout/.fos; git: .git) using only Tcl builtins; (b) defer proj
setup to a post-boot phase where punk::repo is available. (a) matches how the
src-mode #modpod scan already inlines logic at boot.
- Composition: decide `proj` + built-vs-source selectors. Natural default:
`proj` alone implies source-tree resolution (like src) against the detected
root; `proj-dev` selects built `modules/` output; document the matrix.
- No-project case: `proj` from a non-project cwd warns and proceeds as
`internal` - never a false rebind.
- Exe-relative `src`/`dev` for a binary that IS in a project bin/ stays
unchanged; `proj` is the visitor-binary path.
## Alternatives considered
- Automatic cwd-detection with no token - rejected (user decision 2026-07-07):
silently rebinding the module world on `cd` is surprising; an explicit `proj`
token is the safer gate.
- A dedicated project-marker file (punkproject.toml) as the sole signal -
rejected: not universal (tomlish lacks it; it also appears in layout
templates), and is_project_root already provides a VCS-root marker that works
today.
- On `proj:`: walk up from `[pwd]` to the nearest VCS repo root (the
`is_project_root` marker) and feed that root into the **existing src-mode
path machinery** (already parameterised on a root variable - adds
src/modules, src/modules_tcl<N>, src/bootsupport/modules, src/vendormodules
to the tm path, src/lib to auto_path, registers #modpod modules, sets
package prefer latest). Only the discovery is new; the setup is reused.
- Boot chicken-and-egg: find_project/is_project_root live in punk::repo, not
loadable at the early package-mode phase. Options, decision to record:
(a) lean inline VCS-root walk-up in punk_main using only Tcl builtins
(fossil: _FOSSIL_/.fslckout/.fos; git: .git) - matches how the src-mode
#modpod scan already inlines logic at boot; (b) defer proj setup to a
post-boot phase where punk::repo is available.
## Notes
@ -76,10 +161,11 @@ goal aligns the boot-time package modes with that existing runtime detection.
-> punk::cap `punk.templates` plugin handlers) uses find_project and has
unpolished plugin issues, plus an 8.6 shell-context zip-modpod-mount failure
(G-034). This goal deliberately does NOT gate on synchronising with that
machinery - it only reuses the find_project detection concept.
- Related: G-018 (the installable generic/plain binary this serves), G-031
(boot core is where proj discovery belongs; the template project_main.tcl
lacks even src mode - fork drift), G-015 (`script` also benefits: a visitor
binary running `proj script` against a cwd project), G-027 (if a universal
project marker is ever seeded, proj could prefer it over the structural VCS
heuristic).
machinery - it only aligns with the find_project detection concept.
- Related: G-018 (the installable generic/plain binary this serves), G-019
(trimmed kits borrow from the visited project gracefully under kit-first),
G-031 (boot core is where proj discovery belongs; the template
project_main.tcl lacks even src mode - fork drift), G-032 (renders the
packagemode help text above), G-015 (`proj:... script` also benefits),
G-027 (if a universal project marker is ever seeded, proj could prefer it
over the structural VCS heuristic).

Loading…
Cancel
Save