18 KiB
Project Goals
This file is the canonical, harness-agnostic index of technical project goals for ShellSpy. It is referenced from the root AGENTS.md Child DOX Index and is a required read for any non-trivial work, so that agents can discover goals whose scope intersects their work.
Detail prose for goals that need it lives in goals/G-<id>-<slug>.md (see goals/AGENTS.md). The index entry is canonical; a detail file only elaborates and never contradicts its index entry.
Format
Each goal is one block:
### G-<id> [<status>] <short title>
Scope: <repo paths or module areas this goal touches>
Goal: <one line — what done looks like, self-contained>
Detail: goals/G-<id>-<slug>.md <- optional, omit if absent
Acceptance: <measurable, verifiable pass/fail criterion>
Status tags
proposed— not yet started; awaiting user confirmation to goactiveactive— in progressachieved <YYYY-MM-DD>— done; kept as a one-line recordabandoned— dropped; one line on why stays in the entrysuperseded by G-<id>— replaced; do not delete the old entry
Maintenance rules
- Only the user adds or edits goals. Agents must not invent goals.
- An agent whose work satisfies a goal's
Acceptance:must flip that goal toachieved <date>as part of its DOX closeout pass, and report the flip in its completion summary. - Agents must not flip
proposed→active. They flag it in their completion report for the user to confirm. - The
Goal:line must stay self-contained enough that an agent who skips the detail file still does no harm. Detail files are enrichment, not load-bearing for safety. - When the achieved section grows past ~30 entries, the oldest are moved to
GOALS-archive.mdand their detail files togoals/archive/. - If a goal cannot be safely summarized in one line, that is a signal it is really two goals — split it.
Authoring a new goal (for agents)
When the user asks to "write a goal for X" or "help me draft a goal for Y", do the following:
- Read this file in full so you know the format and can pick the next free
G-<id>. - Ask the user only the questions below. Do not invent answers; ask them one at a time or batched if the user prefers. Stop asking once every required field has a real answer.
- Scope: Which repo paths or module areas does this goal touch? (paths are preferred; module names are acceptable if paths are not yet known)
- Goal: In one sentence, what does done look like? Push for an outcome, not an activity ("X compiles to bytecode ≤ 1.10× cost of Y", not "improve compiler performance").
- Acceptance: What is the measurable, verifiable pass/fail criterion an agent can check against? If the user cannot state one, propose 2-3 candidate criteria and ask them to pick or refine.
- Status: Default to
proposedunless the user says it is already in progress (active). - Detail file? Only if the goal has non-obvious rationale, a multi-phase plan, alternatives worth recording, or needs more than ~3 lines of prose to state properly. If yes, propose a slug and offer to draft the detail file too. If no, omit the
Detail:line.
- Draft the goal block in this file's format and show it to the user for review and edit. Do not commit it as
activeunless the user confirms. - If a detail file is warranted and the user approves, create
goals/G-<id>-<slug>.mdusing the structure ingoals/AGENTS.md. - Do not delete or rewrite existing goals to make room for a new one. Append with the next free ID.
Goals
G-001 [proposed] Pluggable console backends for non-detectable terminals
Scope: src/modules/opunk/console-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/lib/app-punkshell/punkshell.tcl Detail: goals/G-001-pluggable-console-backends.md Goal: an interactive REPL can be launched against a non-detectable terminal-like device (ssh channel, tk text widget) via an ::opunk::Console subclass, with no edits to the base class or punk::console. Acceptance: a subshell started with an ssh-channel-backed and a tk-widget-backed ::opunk::Console subclass runs an interactive REPL that reads/writes through that console; size, at_eof, and can_respond are answered by the subclass overrides; the base ::opunk::Console and punk::console module are unchanged.
G-002 [proposed] Non-nested subshell with console targeting and inter-subshell comms
Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm
Detail: goals/G-002-non-nested-subshell.md
Goal: a subshell can target a named console (default or non-default) and run without blocking the parent, replacing the synchronous nested interp-eval model.
Acceptance: a parent REPL launches a subshell against a named console and continues processing its own input while the subshell runs; the parent can signal/query the running subshell; thread::send -async dispatched from within the subshell's code interp arrives at that interp (so packages like promise work when thread features aren't disabled); the "first subshell asymmetry" TODO at repl-999999.0a1.0.tm:3130 is resolved; existing synchronous subshell punk/safe/safebase/punksafe behaviour is preserved as a default mode.
G-003 [proposed] Configurable resource limits and sandboxing on subshell interps
Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm
Detail: goals/G-003-subshell-resource-limits.md
Goal: a subshell's code interp can be launched with configurable resource limits (command-count, time) and sandboxing features, building on the resolved first-subshell asymmetry from G-002.
Acceptance: a subshell can be launched with at least one resource limit (command-count via interp limit -command, or time via interp limit -time) and one sandboxing feature (e.g. interp hide of a command, or full safe-interp restrictions) applied to its code interp, enforceable regardless of subshell nesting depth; a subshell can be configured anywhere on the spectrum from unrestricted to fully safe via expose/hide of commands; the existing default subshell behaviour (no limits, no extra sandbox beyond the existing safe/safebase/punksafe types) is preserved when no limits are configured.
G-004 [proposed] No executable binaries committed to the repository
Scope: repo-wide (bin/, src/vfs/, src/vendorlib/, src/vendormodules/, src/bootsupport/) Detail: goals/G-004-no-committed-binaries.md Goal: the committed repository contains no executable binaries; zip-based .tm modules are allowed but not if they embed executables. Acceptance: a scan of the committed tree finds no executable binaries (shared libs, .exe, native .so/.dll/.dylib, bare ELF/Mach-O); any zip-based .tm modules present contain no embedded executables; the binary artifacts previously committed are retrievable via G-005 (build from source) or G-006 (pre-built download) so their removal does not break builds.
G-005 [proposed] Zig-based build infrastructure for binary dependencies from source
Scope: src/runtime/, build.zig / build.zig.zon (new), src/make.tcl integration
Detail: goals/G-005-zig-build-infrastructure.md
Goal: a zig-based build system retrieves and builds binary dependencies (including Tcl9) from source, replacing the committed-binary approach for the vendored/native components.
Acceptance: running the zig build produces the binary artifacts the repo previously committed (at minimum: Tcl9 library for one target platform); existing Tcl9-zig experiments brought into the project; tclsh src/make.tcl integrates with the zig build so a normal project build retrieves/builds binaries via zig when not present; no binary artifacts need to be committed for the build to succeed on a clean checkout with the zig toolchain available.
G-006 [proposed] Optional pre-built binary artifact download with consent gating
Scope: src/runtime/, src/make.tcl integration, user-config (consent flags)
Detail: goals/G-006-prebuilt-artifact-download.md
Goal: pre-built binary artifacts can be downloaded from a separate related binary-artifacts repository or user-configured sources, gated by explicit user consent/configuration by default.
Acceptance: a download mechanism fetches binary artifacts (the same set the zig build produces) from a configured source on demand; by default the download is gated behind explicit user consent (a config flag or interactive prompt) and does not occur silently; a user-configured source URL overrides the default binary-artifacts repo; downloaded artifacts satisfy the same build requirements as zig-built artifacts so tclsh src/make.tcl project succeeds with downloaded artifacts in place of built ones.
G-007 [achieved 2026-07-05] Location-transparent punk::console across repl and code interps
Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm
Detail: goals/G-007-console-location-transparency.md
Goal: punk::console presents one API in every interp/thread of a punk session - code-interp callers see the same console facts and can perform the same queries/operations as the parent, routed to the console-owning context via a punk-side ownership registry, with no repl eval required.
Acceptance: from a running punk session's code interp, without repl eval: console_fact_get returns the same values the parent sees and a fact set in the parent is immediately visible; a terminal query (e.g. get_cursor_pos or dec_get_mode) against the default console succeeds and cooperates with the repl reader (no lost or garbled input); a console constructed and owned by code-interp code is operated on locally (no round-trip to the parent); the existing console test suites pass and single-interp (non-repl) usage is unchanged.
G-008 [proposed] Scoped console state for same-console subshells (activatable state sets)
Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Detail: goals/G-008-scoped-console-state.md Goal: a subshell on the shared console can opt into scoped console state - its terminal mutations (tabstops, modes, cursor style, palette, title) are captured as an activatable per-subshell state set and the prior state is re-established on quit or switch-away, with today's shared/persistent behaviour remaining the default. Acceptance: with a scoped subshell: tabstops, at least one DEC/ANSI mode and at least one palette entry changed inside the subshell are restored for the parent on quit (verified by terminal query where queryable) and the facts store matches the terminal; the default (unscoped) launch behaviour is unchanged; activation is set-based, proven by applying state set A, activating set B, then re-activating A and observing A's state; irreversible outputs (cleared screen/scrollback, emitted text) are documented as out of scope.
G-009 [proposed] Themed subshell profiles binding poshinfo schemes to behavioural configuration
Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/poshinfo-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm, src/modules/punk/island-999999.0a1.0.tm Detail: goals/G-009-themed-subshell-profiles.md Goal: a subshell can be launched from a named profile binding a poshinfo-enumerated scheme to behavioural aspects (e.g. G-003 interp limits/hidden commands, punk::island filesystem access) so that restricted subshells are visually distinct, with the theme's terminal effects and associated profile data riding the G-008 state set. Acceptance: a named profile associating a poshinfo scheme with at least one restriction aspect (an interp limit, a hidden command, or island-restricted filesystem access) launches by name; the scheme's visual state applies on entry (at minimum prompt styling plus one underlying terminal aspect such as a palette change) and is removed/restored on quit via the G-008 mechanism; profile-associated non-terminal data is scoped to the subshell's lifetime; an unthemed launch is unchanged.
G-010 [proposed] Subshell suspend/resume and tree navigation
Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm
Detail: goals/G-010-subshell-tree-navigation.md
Goal: subshells form a navigable tree - a subshell can be suspended rather than quit, listed, resumed, and the console switched to any live subshell in the tree (e.g. grandchild to grandparent, or across branches) with each subshell's console state re-applied via its G-008 state set, building on the non-nested subshell model of G-002.
Acceptance: from a grandchild subshell a single switch command reaches the grandparent without unwinding through the intermediate parent; switching between subshells on different branches preserves each subshell's session state and re-applies its console state set on activation; suspended subshells can be listed and resumed; quit still unwinds to the launching parent as today; a subshell whose switch commands are hidden/restricted cannot initiate switches.
G-011 [proposed] Optional per-console err channel with defined stderr semantics
Scope: src/modules/punk/console-999999.0a1.0.tm, src/modules/opunk/console-999999.0a1.0.tm, src/modules/punk/repl-999999.0a1.0.tm Detail: goals/G-011-console-stderr-semantics.md Goal: a console optionally carries an err channel as an attribute of its canonical {in out} identity - {in out err} specs accepted everywhere -console is, err resolving to process stderr for the default console and to the console's out channel elsewhere - so diagnostics and emit-to-err are first-class per-console operations instead of raw puts stderr. Acceptance: console_spec_resolve and every -console site accept an {in out err} spec (err optional; existing pair/instance-name/object spec forms unchanged); opunk::Console exposes the err channel (nullable, additive base-class change); an unset err resolves to stderr for the default console and to the console's own out channel otherwise; punk::console's own warnings/diagnostics emitted while operating on a resolvable console go to that console's err (raw puts stderr remains only where no console is in play); an emit-to-err path exists and is exercised by at least one real consumer (e.g punk::repl); the effective err is discoverable from any thread/interp via console_fact_get (fact key err, returning the effective err channel name); ownership/fact/mode-cache keys remain canonical {in out}; the existing console test suites pass unchanged.
G-012 [proposed] Template system: inert VCS-config payloads and explicit layout refresh
Scope: src/project_layouts/, src/make.tcl, src/modules/punk/mix/ (layout instantiation), fauxlink module (bootsupport 0.1.1 - promoted if chosen as mechanism) Detail: goals/G-012-template-payload-safety.md Goal: project layouts carry no live nested VCS-config files - template .gitignore payloads are stored inert (renamed, or fauxlink-encoded) and materialized at project generation - and src/make.tcl has an explicit punkcheck-tracked step that refreshes layout payloads from their canonical sources. Acceptance: a scan of src/project_layouts finds no file named .gitignore, and git check-ignore --no-index over every layout file matches only root-.gitignore rules (nested rules provably inert); a project generated from each affected layout receives a working .gitignore whose content matches the canonical payload/target; after editing a canonical source (e.g. root .gitignore), the make.tcl template-refresh step updates the derived layout payloads (punkcheck-tracked), covering vendor/punk layouts as well as custom/_project; the previously hidden template files (layout READMEs, vendored TODO-class files) remain git-tracked without per-file force-add exceptions.
G-013 [proposed] Raw mode as the repl's default input mode
Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/console-999999.0a1.0.tm Detail: goals/G-013-raw-mode-default.md Goal: a repl launched without explicit mode configuration starts in raw input mode with a clean display - every per-keystroke debug emission behind its own repl-operable toggle - and raw editing covers the line-mode essentials (history navigation, cursor movement). Acceptance: a default launch lands in raw mode with line mode still selectable; with debug toggles at their defaults (off unless stored configuration via ::punk::config says otherwise - see G-014), typing/editing/submitting a command emits no cursor-positioned debug output; the per-keystroke add_chunk frame and the right-hand live editbuf view are gated separately, each toggleable from within a running repl; arrow-key history navigation and left/right cursor movement work in raw mode (current stubs replaced); the marked-line debugrepl output form is retained and works on terminals without cursor addressing (e.g. vt52); the debugrepl first-word activation mechanism is reviewed and the keep/replace outcome (e.g. a proper Tcl command that interp hide can restrict in subshells) is recorded in the detail file; on tcl 8.6 a background-initiated terminal query at an idle raw-mode prompt succeeds (the residue scenario fail-fast-guarded in punk::console 0.7.1).
G-014 [proposed] ::punk::config stored configuration: toml files with named-subshell scoping
Scope: src/modules/punk/config-0.1.tm, src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm, src/vendormodules/tomlish-*.tm (vendored; canonical source in the external tomlish project space) Detail: goals/G-014-punk-config-toml.md Goal: ::punk::config loads stored configuration from toml files in the XDG-located config dir - parsed via the vendored tomlish module, never an ad-hoc parser - and consumers resolve settings with per-named-subshell overrides, so features like the G-013 debug-view startup defaults read declared user configuration instead of hardcoded fallbacks. Acceptance: a setting declared in a toml file under the XDG-located config dir is visible through the punk::config API at repl startup, and with no config files present built-in defaults apply with no errors beyond the existing missing-dir notice; a named subshell resolves its own overriding value for a key also defined at the parent/default scope, and a subshell with no override inherits the outer value (proven with at least one real key); at least one shipped feature (the G-013 editbuf-view startup default is the natural first) reads its default through this path rather than a hardcoded value; all toml reading/writing in punk::config goes through the tomlish module, and the tomlish API procs punk::config consumes carry punk::args (PUNKARGS) documentation - added upstream in the tomlish project and re-vendored here before punk::config implementation proceeds.