Limitations

June 12, 2026 · View on GitHub

Status

Living document (updated as limitations are added/lifted)

Summary

The negative spec: what Bashkit deliberately does NOT do (and why), plus known partial implementations. Absences can't be recovered from code, so they're recorded here; everything positive is generated or tested instead:

  • Builtin inventory: generated specs/status/builtins.json (just regen-builtins, drift-checked by builtins-drift.yml)
  • Test counts / pass rates: CI (spec_tests::bash_spec_tests suite); spec cases in crates/bashkit/tests/spec_cases/
  • Resource limit defaults: crates/bashkit/src/limits.rs
  • Hook/binding API surface: rustdoc + binding type stubs

Intentional-limitation IDs (L-<AREA>-<NNN>) are stable: code comments and docs reference them (like TM-* threat IDs). Never renumber; mark lifted limitations as removed in the PR that lifts them. limitations_doc_format in crates/bashkit/tests/integration/ lints the table format and ID uniqueness; evidence cells naming l_* tests must resolve to functions in limitations_evidence_tests.rs (also linted). stance marks rows that are positions rather than testable behaviors.

Intentional Limitations

By design — these conflict with the sandboxed, virtual, stateless execution model. Evidence is a threat-model ID, a test, or stance (untestable position).

IDLimitationWhyEvidence
L-PROC-001exec does not replace the process; exec cmd runs cmd then stops execution (fd redirects work)True process replace would break sandbox containmentTM-ESC-005
L-PROC-002No job control (bg, fg, jobs)Requires process state; interactive-only featurel_proc_002_no_job_control
L-PROC-003No process spawning; external commands run as builtinsCore sandbox model: no fork/exec escape surfacel_proc_003_no_process_spawning
L-FS-001Symlinks stored but never followed in path resolution (ln -s works, read_link() returns targets, traversal blocked)Prevents symlink loops and link-based sandbox escapesTM-DOS-011
L-FS-002No file permission enforcement in the VFSSingle-tenant virtual FS; permissions would be theaterl_fs_002_no_permission_enforcement
L-NET-001No raw network sockets; HTTP only via curl/wget/http builtinsAllowlist-mediated egress is the only network surfacel_net_001_no_raw_sockets
L-NET-002No DNS resolution; hosts must appear in the allowlistResolution would bypass allowlist intentl_net_002_default_deny_no_resolution
L-SIG-001trap stores INT/TERM handlers but no signal delivery in virtual mode (EXIT, ERR fire)No host signals exist inside the sandboxl_sig_001_signal_traps_not_delivered

Design Rationale

Stateless execution model: scripts run in isolated, stateless contexts; each command completes before the next begins. Prevents resource leaks from orphaned work, simplifies limit enforcement, keeps agent runs deterministic. (& background execution + wait are supported within an exec call.)

bash/sh as virtual re-invocation: bash script.sh / bash -c / bash -n re-enter the Bashkit interpreter — same virtual environment, shared state and limits, never an external process. bash --version reports Bashkit. Security analysis: TM-ESC-015 in threat-model.md.

POSIX Compliance Stance

Target: IEEE 1003.1-2024 Shell Command Language.

CategoryStatusNotes
Reserved words, special parametersFullAll 16 / all 8
Special built-in utilitiesSubstantial14/15; exec partial (L-PROC-001); times returns zeros; trap per L-SIG-001
Quoting, redirections, compound commands, functionsFull
Word expansionsSubstantialMost expansions supported
Pipelines and listsFull|, &&, ||, ;, &+wait, !

Shell Features

Not Yet Implemented

FeaturePriorityNotes
History expansionOut of scopeInteractive only

Partially Implemented

FeatureWhat WorksWhat's Missing
Prefix env assignmentsVAR=val cmd temporarily sets env for cmdArray prefix assignments not in env
localDeclarationProper scoping in nested functions
returnBasic usageReturn value propagation
timeWall-clock timingUser/sys CPU time (always 0)
timeoutBasic usage-k kill timeout
bash/sh-c, -n, -e, -x, -u, -f, -o option, script files, stdin, --version, --helpLogin shell

Builtins

Inventory is generated — see status/builtins.json and the builtins spec. No unimplemented builtins currently tracked.

Text Processing

What each tool does is covered by its spec tests (all unskipped tests pass in CI); only divergences and boundaries are recorded here.

IDToolLimitationEvidence
L-AWK-001awkSome complex regex patterns unsupported (engine shared with sed/grep, size-limited)stance
L-JQ-001jqAlternative //: jaq errors on .foo applied to null instead of returning null (upstream jaq divergence)1 skipped spec test
L-GREP-001grep--color/--colour, --line-buffered accepted as no-opsl_grep_001_noop_flags
L-CURL-001curlSpec-test coverage for methods/headers/payloads/auth/redirects not ported (needs http_client + allowlist in harness); behavior covered by integration testsstance

Safety boundaries (enforced, not bugs): printf width/precision caps, output buffer caps, getline file-cache cap, shared regex size limit, curl/wget timeouts clamped to [1, 600] s, multipart field-name sanitization, redirect handling hardened against credential leaks.

Parser

  • Single-quoted strings are completely literal (correct behavior)
  • Some complex nested structures may hit the parser timeout
  • Very long pipelines may cause stack issues
  • Bounded by configurable limits: timeout, fuel, input size, AST depth

Lifting a Limitation / Adding One

  1. Add a spec test demonstrating it, marked ### skip: reason (or an expected-fail differential test)
  2. Add a row here — with an L-* ID if it's an intentional decision
  3. When lifting: un-skip the test, delete the row, update referencing code comments in the same PR