repl: configurable limits and environment for --sandbox #49

Closed
opened 2026-10-05 21:07:14 +00:00 by orion · 6 comments
Collaborator

Goal

torb repl --sandbox runs every entry under SCRIPTS.md's grant with Grant's fixed defaults (1,000,000 steps, 64 MB, 2000 ms, no environment variable) and does not narrow which std packages an entry may use. Make the limits, the environment pattern and the std packages of that grant configurable with flags of torb repl, so a session can be given exactly the room it needs. Plain torb repl and torb repl --sandbox without further flags behave exactly as today.

Specification

  • Implements REPL.md section 7 ("What --sandbox does not narrow", "Neither the limits nor the environment pattern are configurable yet") and the closing paragraph of section 13 that leaves both for later. The grant words and defaults are SCRIPTS.md section 4 (steps, time, memory, environment, modules); the import lock follows its "first lock" wording.
  • Code: runRepl and --sandbox in compiler/src/main.trb and compiler/src/cli/repl.trb, newSession and replGrantOf in compiler/src/repl/session.trb (the sandbox's Grant and grantText in compiler/src/vm/sandbox.trb already carry steps, memory, milliseconds and environment), usage text in compiler/src/cli/usage.trb.

Interface (decided by the loop, see the comment below)

Every flag below takes its value as the next argument and is accepted only together with --sandbox (otherwise exit code 2 with `--steps` needs `--sandbox`, so an unrestricted session never looks limited by accident).

Flag Meaning Default
--steps <n> bytecode instructions one entry may dispatch 1000000
--time <ms> wall-clock milliseconds one entry may run 2000
--memory <bytes> bytes one entry may allocate 64000000
--environment <pattern> environment variables an entry reads: a name, or a prefix followed by one *; repeatable; "*" is all none
--modules <module> std module an entry may use; repeatable; a package covers its modules, inside std/os one module at a time every std package, as today

Numbers are positive integers (0, negative or non-numeric values: exit code 2 with a message naming the flag). :reset keeps all of them for the session it makes, as it keeps --sandbox.

Acceptance criteria

  • --steps, --time and --memory set the limits of every entry (fresh budget per entry as today). Shown by tests/repl sessions: a loop that stops at the default limit completes with a larger --steps, and --steps 1000 stops a short loop with the same error: line the default limit produces today.
  • --environment <pattern> (repeatable) lets Environment.get read the matching variables and only those; a variable no pattern matches reads as unset (tests/repl session: PATH readable with --environment PATH, None with --environment NOPE_*).
  • --modules (repeatable): an entry whose use names a std module outside the list is refused before anything of the entry runs, with a message in SCRIPTS.md's style that names the module and the flag (The entry may not import `std/fs`: grant it with `--modules std/fs` ) and the session survives with its bindings intact. Relative imports and the workspace's own packages are not narrowed (REPL.md section 10). :load and :type follow the same rule. Not given: nothing narrowed.
  • Flag errors: a flag without --sandbox, a missing or invalid value, and an unknown module name (not a std package or module) exit with code 2 and a one-line message; torb repl --help/usage text lists the flags.
  • :reset keeps limits, environment pattern and modules (a tests/repl session after :reset).
  • Documented: docs/tooling/torb-repl.md (flag table, the --sandbox paragraph), REPL.md sections 7 and 13 (the "not yet configurable" and "does not narrow" sentences become what is built), the usage.trb text, and the regenerated skills/ (torb docs skill docs skills --check clean). SCRIPTS.md stays as is.
  • Unit tests where the parsing lives (compiler/tests/repl.test.trb or beside cli/repl.trb) for the flag parsing and the module check; existing tests/repl/sandbox session unchanged and green.

Seed

Does not touch the seed: no syntax change, no new native (the runtime already reads memory, environment and the limits from grantText), no new flag of the seed's driver (the flags are torb's own, parsed by source in main.trb), no std name the compiler looks up by string. No seed refresh and no two-step migration.

Size and dependencies

One PR, two Conventional Commits:

  1. feat(repl): configurable limits and environment for --sandbox - --steps, --time, --memory, --environment, flag parsing and errors, tests, docs.
  2. feat(repl): narrow the std modules of --sandbox - --modules and the import check, tests, docs.

No dependency on the VM/IR follow-ups (#164), tools/registry (#18) or the documentation module (#32); the only overlap is the regenerated skills/ and docs/tooling/torb-repl.md, resolved by rebasing.

Moved from the planning lists of the docs; the design record stays the specification.

## Goal `torb repl --sandbox` runs every entry under SCRIPTS.md's grant with `Grant`'s fixed defaults (1,000,000 steps, 64 MB, 2000 ms, no environment variable) and does not narrow which `std` packages an entry may `use`. Make the limits, the environment pattern and the `std` packages of that grant configurable with flags of `torb repl`, so a session can be given exactly the room it needs. Plain `torb repl` and `torb repl --sandbox` without further flags behave exactly as today. ## Specification - Implements [REPL.md section 7](docs/design/REPL.md) ("What `--sandbox` does *not* narrow", "Neither the limits nor the environment pattern are configurable yet") and the closing paragraph of section 13 that leaves both for later. The grant words and defaults are [SCRIPTS.md section 4](docs/design/SCRIPTS.md) (`steps`, `time`, `memory`, `environment`, `modules`); the import lock follows its "first lock" wording. - Code: `runRepl` and `--sandbox` in `compiler/src/main.trb` and `compiler/src/cli/repl.trb`, `newSession` and `replGrantOf` in `compiler/src/repl/session.trb` (the sandbox's `Grant` and `grantText` in `compiler/src/vm/sandbox.trb` already carry `steps`, `memory`, `milliseconds` and `environment`), usage text in `compiler/src/cli/usage.trb`. ## Interface (decided by the loop, see the comment below) Every flag below takes its value as the next argument and is accepted **only together with `--sandbox`** (otherwise exit code 2 with `` `--steps` needs `--sandbox` ``, so an unrestricted session never looks limited by accident). | Flag | Meaning | Default | |---|---|---| | `--steps <n>` | bytecode instructions one entry may dispatch | 1000000 | | `--time <ms>` | wall-clock milliseconds one entry may run | 2000 | | `--memory <bytes>` | bytes one entry may allocate | 64000000 | | `--environment <pattern>` | environment variables an entry reads: a name, or a prefix followed by one `*`; repeatable; `"*"` is all | none | | `--modules <module>` | `std` module an entry may `use`; repeatable; a package covers its modules, inside `std/os` one module at a time | every `std` package, as today | Numbers are positive integers (0, negative or non-numeric values: exit code 2 with a message naming the flag). `:reset` keeps all of them for the session it makes, as it keeps `--sandbox`. ## Acceptance criteria - [ ] `--steps`, `--time` and `--memory` set the limits of every entry (fresh budget per entry as today). Shown by `tests/repl` sessions: a loop that stops at the default limit completes with a larger `--steps`, and `--steps 1000` stops a short loop with the same `error:` line the default limit produces today. - [ ] `--environment <pattern>` (repeatable) lets `Environment.get` read the matching variables and only those; a variable no pattern matches reads as unset (`tests/repl` session: `PATH` readable with `--environment PATH`, `None` with `--environment NOPE_*`). - [ ] `--modules` (repeatable): an entry whose `use` names a `std` module outside the list is refused **before anything of the entry runs**, with a message in SCRIPTS.md's style that names the module and the flag (``The entry may not import `std/fs`: grant it with `--modules std/fs` ``) and the session survives with its bindings intact. Relative imports and the workspace's own packages are not narrowed (REPL.md section 10). `:load` and `:type` follow the same rule. Not given: nothing narrowed. - [ ] Flag errors: a flag without `--sandbox`, a missing or invalid value, and an unknown module name (not a `std` package or module) exit with code 2 and a one-line message; `torb repl --help`/usage text lists the flags. - [ ] `:reset` keeps limits, environment pattern and modules (a `tests/repl` session after `:reset`). - [ ] Documented: `docs/tooling/torb-repl.md` (flag table, the `--sandbox` paragraph), REPL.md sections 7 and 13 (the "not yet configurable" and "does not narrow" sentences become what is built), the `usage.trb` text, and the regenerated `skills/` (`torb docs skill docs skills --check` clean). SCRIPTS.md stays as is. - [ ] Unit tests where the parsing lives (`compiler/tests/repl.test.trb` or beside `cli/repl.trb`) for the flag parsing and the module check; existing `tests/repl/sandbox` session unchanged and green. ## Seed Does **not** touch the seed: no syntax change, no new native (the runtime already reads `memory`, `environment` and the limits from `grantText`), no new flag of the seed's driver (the flags are `torb`'s own, parsed by source in `main.trb`), no `std` name the compiler looks up by string. No seed refresh and no two-step migration. ## Size and dependencies One PR, two Conventional Commits: 1. `feat(repl): configurable limits and environment for --sandbox` - `--steps`, `--time`, `--memory`, `--environment`, flag parsing and errors, tests, docs. 2. `feat(repl): narrow the std modules of --sandbox` - `--modules` and the import check, tests, docs. No dependency on the VM/IR follow-ups (#164), `tools/registry` (#18) or the documentation module (#32); the only overlap is the regenerated `skills/` and `docs/tooling/torb-repl.md`, resolved by rebasing. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop). REPL.md section 13 names the gap; how limits, the environment pattern and a package allow-list are configured for torb repl --sandbox is new CLI and Grant surface, so refine will likely need an owner decision. No duplicate found. next: refine (ready buffer is 6, so not before it drops below 2).

[loop:torbscript] intake: in scope (author orion, label loop). REPL.md section 13 names the gap; how limits, the environment pattern and a package allow-list are configured for `torb repl --sandbox` is new CLI and `Grant` surface, so refine will likely need an owner decision. No duplicate found. next: refine (ready buffer is 6, so not before it drops below 2).
Author
Collaborator

[loop:torbscript] decided by the loop: interface of the configurable grant. (1) Flags of torb repl, each with its value as the next argument and only valid together with --sandbox: --steps, --time (ms), --memory (bytes), --environment (repeatable), --modules (repeatable). Why: names follow SCRIPTS.md section 4's grant words (steps, time, memory, environment, modules) and Grant's fields; the value-as-next-argument form follows --project <directory> and --channel; refusing them without --sandbox keeps an unrestricted session from looking limited. (2) Values are positive integers, no "unlimited" spelling: unlimited is plain torb repl, and memory 0 (no limit in the runtime) is therefore not reachable by accident. (3) --modules is a first lock only (import check before the entry runs), as the REPL has no second runtime lock for modules to mirror; it narrows std packages only, relative and workspace imports stay as REPL.md section 10 says. REPL.md section 7 reasoned that the module lock has nothing to check for a person at their own prompt; the issue asks for it anyway as an opt-in for demos and teaching, so the default stays unnarrowed and the design record gets updated, not contradicted. (4) Additive CLI surface, defaults unchanged, so no published contract breaks and no owner question applies. (5) Size: two commits in one PR (limits and environment first, modules second), no seed involvement.

[loop:torbscript] decided by the loop: interface of the configurable grant. (1) Flags of `torb repl`, each with its value as the next argument and only valid together with `--sandbox`: `--steps`, `--time` (ms), `--memory` (bytes), `--environment` (repeatable), `--modules` (repeatable). Why: names follow SCRIPTS.md section 4's grant words (`steps`, `time`, `memory`, `environment`, `modules`) and `Grant`'s fields; the value-as-next-argument form follows `--project <directory>` and `--channel`; refusing them without `--sandbox` keeps an unrestricted session from looking limited. (2) Values are positive integers, no "unlimited" spelling: unlimited is plain `torb repl`, and `memory 0` (no limit in the runtime) is therefore not reachable by accident. (3) `--modules` is a first lock only (import check before the entry runs), as the REPL has no second runtime lock for modules to mirror; it narrows `std` packages only, relative and workspace imports stay as REPL.md section 10 says. REPL.md section 7 reasoned that the module lock has nothing to check for a person at their own prompt; the issue asks for it anyway as an opt-in for demos and teaching, so the default stays unnarrowed and the design record gets updated, not contradicted. (4) Additive CLI surface, defaults unchanged, so no published contract breaks and no owner question applies. (5) Size: two commits in one PR (limits and environment first, modules second), no seed involvement.
Author
Collaborator

[loop:torbscript] refine: rewrote the issue to goal, interface, seven testable criteria, design record points (REPL.md sections 7, 10, 13; SCRIPTS.md section 4), seed statement (does not touch the seed) and size (one PR, two commits); decisions in the comment above; no overlap with the live VM/IR (#164), registry (#18) or documentation (#32) work beyond a rebase of regenerated docs; next: implement

[loop:torbscript] refine: rewrote the issue to goal, interface, seven testable criteria, design record points (REPL.md sections 7, 10, 13; SCRIPTS.md section 4), seed statement (does not touch the seed) and size (one PR, two commits); decisions in the comment above; no overlap with the live VM/IR (#164), registry (#18) or documentation (#32) work beyond a rebase of regenerated docs; next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T08:58Z

[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T08:58Z
argus closed this issue 2026-10-09 04:51:00 +00:00
Author
Collaborator

[loop:torbscript] implement: PR #246 open, CI green (807b5b34), worker usage ~120k tokens, next: review (waiting on the merge gate argus)

[loop:torbscript] implement: PR #246 open, CI green (807b5b34), worker usage ~120k tokens, next: review (waiting on the merge gate argus)
Author
Collaborator

[loop:torbscript] close: landed via PR #246 as 83f49f01 and cf14b601; main CI is green on the later head cf14b601 (success). Issue closed.

[loop:torbscript] close: landed via PR #246 as https://git.torb.dev/torbscript/language/commit/83f49f01 and https://git.torb.dev/torbscript/language/commit/cf14b601; main CI is green on the later head cf14b601 (success). Issue closed.
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#49
No description provided.