Skip to content

feat(cli): --bundle — single-file distribution with optional attached tape (#413)#550

Merged
InauguralPhysicist merged 1 commit into
mainfrom
feat/413-bundle
Jul 11, 2026
Merged

feat(cli): --bundle — single-file distribution with optional attached tape (#413)#550
InauguralPhysicist merged 1 commit into
mainfrom
feat/413-bundle

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

Closes #413

eigenscript --bundle app.eigs out [--with-tape tape] copies the runtime binary and appends an archive — the script, the adjacent eigs_modules/ tree, the stdlib lib/ modules (so import json works on a bare machine), and optionally a trace tape — producing one executable that runs on a machine with no EigenScript checkout.

How it runs

Startup (eigs_bundle_selfexec, before any flag handling) detects a 24-byte trailer magic on the binary's own tail, extracts entries to a mkdtemp dir (removed at exit), and rewrites argv to run the extracted script. The script's directory becomes the resolve base, so every existing resolution rule just worksimport nameeigs_modules/name/name.eigs, import jsonlib/json.eigs. No VFS, no resolver changes. In bundle mode all arguments belong to the bundled script; only --replay (first arg) is intercepted.

The executable bug report

With a tape attached, out --replay re-runs the recorded run byte-identically, serving every nondet input from the tape — no network, no env, no luck. The #411 version contract is pinned by construction: the tape names its recording version and the bundle carries that exact binary, so the pair can't drift.

EIGS_TRACE=fail.tape eigenscript app.eigs
eigenscript --bundle app.eigs repro --with-tape fail.tape
./repro --replay        # the failure, exactly, forever

Format & hardening

Fmt 1 (little-endian, same x86-64 assumption as the JIT): [u32 plen][path][u64 size][bytes]* + [u64 off][u32 count][u32 fmt][EIGSBNDL]. Torn archives (misparsed headers, traversal paths) refuse with exit 3 rather than running garbage; re-bundling from a bundle copies only the runtime image so archives don't accrete. src/bundle.c is CLI_ONLY — excluded from embed/LSP/freestanding/fuzz builds.

Tests & docs

  • tests/test_bundle.sh (suite [42g], 8 checks): script+modules+stdlib from a bare cwd (cd /), arg passthrough to args of null, byte-identical --replay whose output equals the recorded run's stdout, no-tape refusal (exit 3), torn-archive refusal (exit 3), re-bundle size stability.
  • docs/BUNDLE.md: format, the tape-carrying story, and ouroboros AOT documented as the native-speed tier of the same single-file deliverable.
  • Demo: eigenscript --bundle examples/data_pipeline.eigs pipeline && ./pipeline (verified from /).

Validation

Release suite 2745/2745 with [42g] green; ASan+UBSan detect_leaks=1 full run green (the one earlier failure was the test's own oracle comparing print formatting against the tape's %.17g serialization — fixed to compare replay stdout against the recorded run's stdout, which is the stronger check anyway).

🤖 Generated with Claude Code

https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm

Comment thread src/bundle.c Fixed
Comment thread src/bundle.c Fixed
Comment thread src/bundle.c Fixed
Comment thread src/bundle.c Fixed
Comment thread src/bundle.c Fixed
Comment thread src/main.c Dismissed
Comment thread src/main.c Dismissed
Comment thread src/main.c Dismissed
Comment thread src/main.c Fixed
Comment thread src/main.c Fixed
@InauguralPhysicist InauguralPhysicist force-pushed the feat/413-bundle branch 2 times, most recently from ba3a01c to 3a0d187 Compare July 11, 2026 02:18
Comment thread src/bundle.c Dismissed
… tape (#413)

Closes #413

`eigenscript --bundle app.eigs out [--with-tape tape]` copies the
runtime binary and appends an archive: the script (always the first
entry), the adjacent eigs_modules/ tree (whole tree — dependency
analysis can't see dynamic imports and the superset is cheap), the
stdlib lib/ modules (so `import json` works on a bare machine), and
optionally a trace tape. One executable, runs anywhere.

Startup (eigs_bundle_selfexec, called before any flag handling)
detects the 24-byte trailer magic on the binary's own tail, extracts
entries to a mkdtemp dir (removed at exit), and rewrites argv to run
the extracted script — the script's dir becomes the resolve base, so
every existing resolution rule just works: no VFS, no resolver
changes. In bundle mode all args belong to the bundled script; only
`--replay` (first arg) is ours — it points EIGS_REPLAY at the
extracted tape, making a tape-carrying bundle an executable bug
report that replays byte-identically with no environment. The #411
version contract is pinned by construction: the tape names its
recording version and the bundle carries that exact binary.

Format (fmt 1, little-endian): [u32 plen][path][u64 size][bytes]*
entries + [u64 off][u32 count][u32 fmt][EIGSBNDL] trailer. Torn
archives (misparsed entry headers, traversal paths) refuse with exit
3. Re-bundling from a bundle copies only the runtime image, so
archives don't accrete. src/bundle.c is CLI_ONLY — excluded from
embed/LSP/freestanding/fuzz builds like main.c/repl.c/step.c.

tests/test_bundle.sh (suite [42g], 8 checks): script+modules+stdlib
from bare cwd, arg passthrough, byte-identical --replay serving the
recorded nondet value, no-tape refusal, torn-archive refusal,
re-bundle size stability. docs/BUNDLE.md documents the format and
positions ouroboros AOT as the native-speed tier of the same story.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm
Comment thread src/bundle.c Dismissed
@InauguralPhysicist InauguralPhysicist merged commit aac803b into main Jul 11, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the feat/413-bundle branch July 11, 2026 02:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--bundle: single-file distribution (script + eigs_modules appended to the runtime binary; optional attached tape)

2 participants