Browse Source
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.commaster
3 changed files with 244 additions and 0 deletions
@ -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). |
||||||
@ -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…
Reference in new issue