Browse Source

G-042, G-043 proposed: subshell help topics via punk::config; subshell definition plugins (punk.subshell capability)

Both user-approved after a review of the intended plugin facility (punk::mix::init
pluginmgr todos, the punk::pluginmgr 0.5.1 tcllib fork, punk::cap provider/handler
system, punk::cap::handlers::templates pathtype resolution, punk::overlay
commandset composition and its toml-CLI todo).

- G-042: a named subshell declares help topics (name/aliases/summary/text) in
  punk::config stored configuration, registered into the ::punk::helptopic
  registry on entry and restored on exit, with an explicit shadowing policy.
  Text-content only - config is data; code-bearing topics belong to the plugin
  path where the trust story lives. Detail file records the registry seam
  (punk 0.2.0), dependencies (hard on G-014; beneficial G-040/G-008/G-009),
  and the plugin-facility relationship from the review.
- G-043: the umbrella for that plugin path - a punk.subshell capability whose
  providers supply commandset bindings (punk::overlay import), help topics
  (G-042's registry API) and config defaults per named subshell, with a
  validating punk::cap handler, an equivalent data-only stored-config
  declaration path (absorbing punk::overlay's ".toml configuration files for
  defining CLI configurations" todo), and punk::pluginmgr as the discovery/
  safe-interp trust layer for untrusted providers. Also absorbs punk::cap
  housekeeping found in the review: pkg_unregister api-object cleanup and
  unhandled-capability discoverability (the deliberate punk.isbogus silence).

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
9948810b9b
  1. 12
      GOALS.md
  2. 120
      goals/G-042-subshell-help-topics.md
  3. 112
      goals/G-043-subshell-definition-plugins.md

12
GOALS.md

@ -296,3 +296,15 @@ Scope: src/modules/punk/args-999999.0a1.0.tm (parse form selection, arg_error/us
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 <id>' 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 <cmd> <args...>' and synopsis output indicate the best-matching form(s) for supplied args; explicit -form <single-name-or-index> 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 <topic>' 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 <cmd>'/'s <cmd>' 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.

120
goals/G-042-subshell-help-topics.md

@ -0,0 +1,120 @@
# G-042 Subshell-declared help topics via punk::config with defined shadowing policy
Status: proposed
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)
Acceptance: a subshell whose configuration declares at least one custom topic shows it in 'help topics' and renders its configured content via 'help <topic>' 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 <cmd>'/'s <cmd>' 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.
## Context
Arose from the 2026-07-08 punk::help restructure (punk module 0.2.0), which replaced the
monolithic help_chunks switch with the ::punk::helptopic registry: each topic is a handler
proc plus a punk::args definition, and registering a topic (re)generates the ::punk::help /
::punk::help_chunks definitions so 'help topics' and the 'i help' documented choice table
can never drift from the registered set. That registry was explicitly built as the seam for
this goal: adding a topic at runtime already updates every documentation surface for free.
The user's intent (2026-07-08, during the restructure): the help system should be usable as
a default for customised (punk::config-enabled) subshells with their own topics. Today the
topic set is small and largely orthogonal to command names, so topic-vs-command shadowing
is a non-issue; once subshells declare arbitrary topics, the precedence between a topic
word and the command-info fallthrough (help <cmdname>) becomes a policy that must be
explicit rather than accidental.
## Approach (sketch - to be refined when activated)
1. Registry side (can land ahead of G-014, programmatic API):
- a generic text-topic handler: config-declared topics carry name, aliases, summary and
body text; the handler renders the body as chunks (frametype-aware wrapping optional).
No code execution from configuration - a topic cannot name a proc to run. This is
deliberate: G-003/G-009 restricted subshells must be able to carry custom help without
the config becoming an interp-escape vector. If handler-proc topics are ever wanted,
record the sandboxing rationale here first.
- register/deregister with scoping: subshell entry registers its declared topics,
quit/switch-away restores the prior registry state. Natural shape: save/restore of the
registry dict rides the same lifecycle as the G-008 console state sets (activatable
per-subshell state), but the registry is punk-side data - no terminal interaction -
so it need not wait for G-008.
- collision rule at registration time: reject (or per documented rule, override) a
declared topic whose name or alias matches a built-in topic; the existing register
proc already errors on a missing handler - extend it to police names.
2. Config binding (gated on G-014):
- declaration lives in punk::config stored configuration under the named-subshell
scoping G-014 defines (a subshell resolves its own topics; unconfigured shells
inherit nothing extra). All reading via punk::config API backed by tomlish.
- shape sketch (indicative only): [subshell.<name>.helptopic.<topic>] with keys
aliases, summary, body.
3. Shadowing policy: registered topics win over command fallthrough (unchanged); the
escape hatch for a shadowed command name is 'i <cmd>' / 's <cmd>' (the first-class
command-help route) - document it where the topic set is presented ('help topics'
footer or the ::punk::help -help text).
4. Display: alias folding for declared topics inherits whatever G-040 lands
(-choicealiases); until then aliases appear as separate documented choices, as the
built-ins do today.
## Relationship to the intended plugin facility (code review 2026-07-08)
Reconnaissance of punk::mix::init, punk::cap, punk::pluginmgr and punk::overlay maps the
plugin stack the codebase already intends, which this goal must slot into:
1. Discovery/loading + trust boundary: tcllib pluginmgr-style safe-interp plugin loading.
punk::pluginmgr-0.5.1.tm is a vendored fork of tcllib pluginmgr with initial divergence
("JN - diverging from tcllib" in LoadPlugin: direct plugin.tcl sourcing from plugin
paths); punk::mix::init's todos record the known gaps (tcllib 0.5 bugs around .tm
modules vs packages - reports submitted upstream - and control of module/library path
ordering inside the safe interps).
2. Capability registration/validation: punk::cap - in-process and cooperative (its own
doctools position tcllib pluginmgr as "an alternative which uses safe interpreters").
Provider packages declare (capname capdict) pairs via a registration object; handlers
validate at registration (pkg_register veto) and expose api_<capname> objects.
punk.templates is the only handled capability today.
3. Capability-specific handler APIs: punk::cap::handlers::templates, whose pathtype
vocabulary (module / adhoc / currentproject* / shellproject* / absolute) is the
existing answer to from-kit vs from-src-tree resolution.
Implications adopted for this goal:
- The ::punk::helptopic programmatic registry API is the convergence point. Stored-config
topics (this goal - text only) and any future plugin-provided topics (code-bearing,
arriving as provider packages through the punk::cap layer - e.g. a punk.subshell or
punk.helptopics capability - where provider trust is the plugin facility's concern) land
in the same registry, under the same collision policy, with the same punk::args
regeneration. Nothing in this goal's mechanism needs reworking for plugins later.
- The text-only stance is reinforced, and the boundary is now principled rather than just
cautious: punk::config declarations are data; code-bearing topic handlers belong to the
plugin path where a validation/trust story (cap handler veto, pluginmgr safe interps)
exists.
- Subshell definitions as plugins: punk::overlay::import_commandset is the existing
commandset composition mechanism (rename-imports a commandset namespace's exported
commands under a prefix; explicitly designed so one commandset can serve multiple CLIs
simultaneously), and its own documentation already records the intent "Todo - .toml
configuration files for defining CLI configurations". A future subshell-definition
plugin/profile would compose: commandset imports + help topics + config defaults
(+ G-009 restrictions/theme). This goal deliberately builds only the help-topic slice,
with the registration/restore API shaped so a composite subshell-definition capability
can drive it.
## Alternatives considered
- Handler-proc topics declared in config - rejected as the default: stored configuration
must not be a code-execution vector, especially for restricted subshells (G-003/G-009).
Text-only content covers the motivating use (subshell-specific guidance); revisit with a
sandboxing design if real demand appears.
- Per-subshell complete replacement of the help command itself - rejected: loses the
registry's guarantee that 'help topics'/'i help' match reality, and every subshell would
reinvent the overview/fallthrough machinery.
- Waiting for G-008/G-009 profiles to carry topics as part of themed profiles - not
required: the registry save/restore is plain data and can precede the theming goals;
profiles can later bundle topic declarations as one more profile aspect.
## Notes
- Dependencies: G-014 (punk::config toml + named-subshell scoping - the config substrate;
itself gated on tomlish argdoc work upstream). Beneficial, not required: G-040 (alias
display folding), G-008/G-009 (profile bundling), G-002/G-010 (non-nested subshells -
the restore-on-switch semantics should be specified to survive that rework).
- Seam already in place (punk 0.2.0): ::punk::helptopic::register / resolve / define_docs;
'help topics' derives from the registry; per-topic punk::args ids follow the
::punk::helptopic::<topic> convention consumed by 'i help <topic>' subhelp choiceinfo.
- Related session records: goals/G-040-punkargs-choicealiases.md (choice display folding),
the 2026-07-08 CHANGELOG entries for punk 0.2.0 (registry) and punk::ns 0.1.1
(doc-lookup trace cleanup).

112
goals/G-043-subshell-definition-plugins.md

@ -0,0 +1,112 @@
# G-043 Subshell definition plugins: punk.subshell capability composing commandsets, help topics and config defaults
Status: proposed
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)
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.
## Context
Drafted from the 2026-07-08 code review of the intended plugin facility (conducted while
reviewing G-042). The codebase already contains a deliberate three-layer plugin stack,
two-thirds built:
1. Discovery/loading + trust boundary (placeholder): punk::mix::init records the intent -
"todo: use tcllib pluginmgr to load all modules that provide 'punk.templates'" -
blocked on tcllib pluginmgr 0.5 bugs (.tm modules vs packages; bug reports submitted
upstream) and on controlling module/library path ordering in its safe interps, with
the stated plan "develop punk::pluginmgr to fix these issues".
punk::pluginmgr-0.5.1.tm is that development's start: a vendored fork of tcllib
pluginmgr (snit type; safe-interp loading; -pattern/-api/-check/-cmds/-setup contract)
with one marked divergence (LoadPlugin sources a bare plugin.tcl dropped in a plugin
path) and the .tm gap still commented in place.
2. Capability registration/validation (working): punk::cap - in-process, cooperative
(its doctools position tcllib pluginmgr as "an alternative which uses safe
interpreters"). Providers declare (capname capdict) pairs via a
capprovider.registration object; a handler registered for the capability name can
veto each declaration (pkg_register) and exposes an api_<capname> object. Handlers
are registered by the application (punk::mix::init), deliberately not at package
load. punk.templates is the only handled capability.
3. Capability-specific handler APIs (one real instance): punk::cap::handlers::templates,
whose pathtype vocabulary (module / adhoc / currentproject* / shellproject* /
absolute) is the existing pattern for kit-vs-srctree resource resolution.
Commandset composition already exists and is multi-consumer by design:
punk::overlay::import_commandset rename-imports a commandset namespace's exported
commands under a prefix into a CLI ensemble, explicitly supporting the same commandset
serving multiple CLIs simultaneously. Its punk::args documentation records the intent
this goal absorbs: "This is part of the punk::mix CLI commandset infrastructure - design
in flux. Todo - .toml configuration files for defining CLI configurations." Today's `dev`
CLI is composed by hardcoded import_commandset calls in punk::mix::cli::_init
(catch-guarded optional sets) - the shape a declarative composition replaces.
The user's direction (2026-07-08): support plugins for subshell definitions including
help, and plugin commandsets that may apply to particular subshells.
## Approach (sketch - to be refined when activated)
Two declaration paths with distinct trust models, one composition mechanism:
- Config path (data): stored configuration (G-014 toml) declares a named subshell's
composition - which commandset packages to import (with prefix/separator), which help
topics (G-042 text topics), which config defaults. Config can only NAME already
installed/locatable packages; requiring/importing them is an explicit trust decision
equivalent to today's hardcoded init. No code is carried in config (G-042 stance).
- Plugin path (code): a provider package declares the punk.subshell capability with a
capdict describing what it offers per subshell name (commandset namespace(s) + prefix,
help topics via the ::punk::helptopic programmatic API, config defaults). The
punk.subshell handler validates shape at registration (veto malformed). Providers not
already trusted arrive via punk::pluginmgr discovery/safe-interp loading; in-process
registration remains available for providers the app requires directly (the
punk::cap norm today).
Phases:
1. punk.subshell capability handler (validation + api object) and the composition step
at subshell entry/exit: import_commandset into the subshell's command resolution
scope, register topics, apply config defaults; restore on quit/switch-away. The
restore semantics should be specified to survive the G-002/G-010 non-nested subshell
rework (same consideration as G-042's registry save/restore and G-008's state sets).
2. Config-declared composition (G-014-gated) reusing exactly the same composition step.
3. punk::cap housekeeping absorbed here: pkg_unregister completing handler cleanup
(api-object lifecycle), and unhandled-capability discoverability (a query or report
for declarations that no registered handler accepted - the deliberate punk.isbogus
demonstration in punk::mix::templates documents the current silence).
4. punk::pluginmgr integration: .tm loading in the safe interp, controlled module/library
path ordering, and the api-contract check wired to the punk.subshell registration.
May be deferred as a whole (acceptance allows it) if the fork needs more work than the
composition machinery justifies at the time - record remaining gaps here if so.
## Alternatives considered
- Hardcoding per-subshell composition in repl init code (status quo pattern from
punk::mix::cli::_init) - rejected as the end state: it is exactly what the punk::overlay
toml todo and the punk::mix::init pluginmgr todo set out to replace.
- Config-only (no provider packages): insufficient - commandsets are code; config can
name them but a third-party subshell definition needs a carrier for code plus a trust
story, which is the capability + pluginmgr stack's purpose.
- Plugin-only (no config path): rejected - the common case (compose existing local
commandsets into a project- or task-specific subshell) should not require authoring a
provider package; data-only declaration must stay first-class.
- Extending tcllib pluginmgr in place upstream rather than forking - upstream reports are
filed, but the path-ordering customisation punk needs was already judged (punk::mix::init
note) to need punk-side control; the fork exists. Re-converge upstream if tcllib takes
the fixes.
## Notes
- Dependencies/relations: G-042 (help-topic registry API - consumed by this goal),
G-014 (toml stored config - gates the config path), G-009 (themed profiles - a profile
is a natural bundle of this goal's composition plus theme/restrictions), G-002/G-010
(non-nested subshells - restore-on-switch semantics), G-003 (restricted subshells -
a restricted subshell composing plugin commandsets needs the expose/hide interaction
considered), G-033 (visitor binaries - shellproject-anchored resources vs cwd-project
resources, same anchor question as the templates pathtypes).
- Rough edges catalogued 2026-07-08 (this goal's acceptance covers the first two):
punk::cap pkg_unregister "destroy api objects?" review; silent unhandled-capability
declarations (punk.isbogus); hardcoded _multivendor whitelist in the templates handler
(not this goal's to fix - noted for the templates/layout update-story work under
G-012/G-027).
- The templates handler's registration-time vs call-time path resolution split (and its
documented staleness edge for long-running shells) is the precedent for deciding when
a punk.subshell declaration's resources are resolved.
- Related review record: goals/G-042-subshell-help-topics.md "Relationship to the
intended plugin facility" section (same 2026-07-08 review).
Loading…
Cancel
Save