# 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--.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- [] Scope: Goal: Detail: goals/G--.md <- optional, omit if absent Acceptance: ``` ### Status tags - `proposed` — not yet started; awaiting user confirmation to go `active` - `active` — in progress - `achieved ` — done; kept as a one-line record - `abandoned` — dropped; one line on why stays in the entry - `superseded by G-` — 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 to `achieved ` 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.md` and their detail files to `goals/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: 1. Read this file in full so you know the format and can pick the next free `G-`. 2. 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 `proposed` unless 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. 3. Draft the goal block in this file's format and show it to the user for review and edit. Do not commit it as `active` unless the user confirms. 4. If a detail file is warranted and the user approves, create `goals/G--.md` using the structure in `goals/AGENTS.md`. 5. 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.