# G-004 No executable binaries committed to the repository Status: proposed Scope: repo-wide (bin/, src/vfs/, src/vendorlib/, src/vendormodules/, src/bootsupport/) 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. ## Context The ultimate aim is that the committed repository contains no executable binaries. This is a hygiene and reproducibility goal: binaries in version control are opaque to review, bloat the repo, and make the build non-reproducible from source. Today the repo violates this — binary libraries are committed in the VFS folders (`src/vfs/`), `src/vendorlib/`, `src/vendormodules/`, and `src/bootsupport/`. These are present because there is currently no automated way to rebuild or retrieve them; removing them before an alternative exists would break builds on a clean checkout. Two further motivations recorded 2026-07-22 (user framing): - **Third-party distribution eligibility**: a binary-free punkshell is a candidate for distribution platforms that disallow checked-in binaries. - **The consent promise as a product commitment**: punkshell guards the promise that binaries reach the user's machine over the network ONLY by explicit user action/consent unless configured otherwise (the G-006 gate and its G-067 sibling are the enforcement points). A binary-free repo makes the promise auditable: everything binary is retrieved, and every retrieval is consented. Zip-based `.tm` modules are a permitted exception to the "no binaries" rule because they are module archives, not executables — but a zip-based `.tm` that embeds an executable (e.g. a native shared library packaged inside the module) is not permitted. The distinction is content, not file extension. This goal is the integrating outcome of two enabling goals: - **G-005** provides the build-from-source path (zig build of Tcl9 and other dependencies). - **G-006** provides the pre-built download path with consent gating. Both must be in place before the committed binaries can be removed without breaking builds, so G-004 sequences after both. A standing repo-wide rule in root `AGENTS.md` (User Preferences) already directs agents not to commit new executable binaries, while explicitly not hassling the developer about existing vendor/vfs binaries committed pending this goal's achievement. ## Approach 1. **Inventory.** Identify every executable binary currently committed across `bin/`, `src/vfs/`, `src/vendorlib/`, `src/vendormodules/`, and `src/bootsupport/`. Classify each by what it is (Tcl9 shared lib, twapi, other native extension) and which goal path (G-005 build / G-006 download) will replace it. 2. **Verify alternatives work.** Before removing any binary, confirm the corresponding G-005 build or G-006 download produces an artifact that satisfies the build. Removal without a working replacement breaks clean-checkout builds — the acceptance explicitly requires the alternative retrieval to work. 3. **Remove.** Delete the committed binaries from the tree. Update `.gitignore` / `.fossil-settings/ignore-glob` if needed to prevent re-addition. 4. **Add a scan to verification.** Add a scan step (script or make.tcl target) that checks the committed tree for executable binaries and fails if any are found, so regressions are caught. The scan must recognise the zip-based `.tm` exception: a `.tm` that is a zip is allowed; a `.tm` (or any zip) containing an embedded executable is not. 5. **DOX update.** Once achieved, the AGENTS.md "no binaries" user-preference note can be simplified from "agents must not; existing violations pending" to "agents must not; scan enforced" — but the rule itself stays. ## Alternatives considered - **Delete binaries now, document manual fetch.** Rejected: no automated retrieval, so every contributor hand-fetches. The intended system (G-005/G-006) exists precisely to avoid this. - **Allow committed binaries permanently.** Rejected: this is the explicit ultimate aim the user stated. Not a real alternative. - **Permit zip-based .tm with embedded executables.** Rejected: the user's wording is explicit — "those zip-based .tm modules that contain executables should also not be directly checked in." The content matters, not the extension. - **Fold G-005 and G-006 into this goal.** Rejected: the build system and download system are each large bodies of work with their own acceptance, and they're independently useful before all binaries are removed. Bundling would make G-004 uncheckable until two large systems are built, and would grow past a one-line-safe summary. ## Notes - 2026-07-22 (user framing): achieving this goal must NOT stop binaries OPERATING in the tree - the no-checkin policy is about the COMMITTED tree only. Two working modes stay first-class forever: (a) quick local experimentation with uncommitted binaries dropped into the working tree; (b) derived projects (dev project.new) with a PERMISSIVE binary policy - generated projects may commit binaries under their own rules. Consequences for the Approach: the step-4 scan targets the committed tree (never a working-tree police); ignore rules added at removal time double as the drop-in enablement (local binaries stay conveniently uncommitted); and boot/loading machinery (auto_path platform dirs, tm roots, libunknown, modpod) must keep supporting in-tree binaries indefinitely - G-114's same-version drop-in-replacement acceptance is the tm-side expression of the same requirement. Layout seeding keeps the binary policy per-project (punkshell strict, derived projects owner-chosen). - 2026-07-22 (user framing + assessment): EXIT PATHS for the src/vfs/*.vfs interim exception - the .vfs binary payloads leave the committed tree via some mix of: (i) suite-built runtime batteries (G-103, achieved 2026-07-22 - see goals/archive/G-103-runtime-kit-family.md - attached images already shrink kit .vfs payloads toward pure punkshell script payload); (ii) per-package punkbin LIBRARY artifacts (G-067 channel - buildsuite-built .tm/pkg libraries as a second punkbin artifact class) declared into kit assembly; (iii) possibly whole zipped binary-carrying .vfs archives as a THIRD punkbin artifact class. Assessment 2026-07-22 (agent, user question): prefer (i)+(ii) as the primary paths - per-package artifacts dedupe across kits, keep provenance/versioning granular, reuse the platform canon and the G-103 metadata pattern, and share one consent story; whole-.vfs archives couple unrelated components and churn on any payload change, so (iii) is recorded as an OPEN option for release-snapshot/derived-project convenience rather than the primary mechanism - decide when removal actually forces the payloads out. A declarative .vfs composition surface (toml-defined payload pulling from (i)/(ii), preserving drop-in simplicity) is the candidate glue - see the G-115 proposal (2026-07-22) if adopted. - Depends on G-005 and G-006. Sequence G-005 ∥ G-006, then G-004. - The scan in step 4 should distinguish "executable binary" from "zip archive" and from "zip archive containing an executable." A naive extension-based check is insufficient; content inspection (file magic, zip listing) is required. - The AGENTS.md user-preference rule is the transition guard: it stops agents from adding new binaries during the G-005/G-006 development period while the developer's existing vendor/vfs binary commits are known and intentional. - No persisted prior chat on this topic was found in project sessions; the motivation is the user's stated ultimate aim.