feat: release strands shell - #1
Merged
Merged
Conversation
Four independent CI failures on the release commit: - Rust: cargo doc (-D warnings) failed on a broken intra-doc link in vfs_config.rs; ShellBuilder is not in scope there. Qualify the path to crate::shell::ShellBuilder::config_file. - Python: maturin develop aborted with "Couldn't find a virtualenv". Create and use a .venv explicitly in the workflow. - Node 20: the quoted test glob 'tests/js/*.mjs' requires Node's own glob support (21+); unquote it so the shell expands it on all versions. Also drop the always-failing `npm ci` fallback since package-lock.json is gitignored. - Security audit: npm audit needs a lockfile (ENOLOCK); generate an ephemeral one with --package-lock-only before auditing. Also remove a stray docs/js-bindings.md reference in a JS test name.
A sandbox for adversarial AI agents must never panic on the input it
sandboxes — across the Python/Node FFI a Rust panic aborts the host
process. Six trivially-reachable panics are fixed here:
- ${VAR%?} / #/%% / ## on multibyte text: byte-level glob match offset
could land mid-codepoint; guard each &str slice with is_char_boundary.
- exit/return/break/continue with an empty-expanding arg (e.g.
`exit $UNSET`): indexed args[0] on an empty Vec; index defensively.
- uniq -s N: byte-sliced the line; skip by char boundary instead (also
matches the documented "first N characters").
- mktemp X (template shorter than 6 chars): .max(6) forced a count past
the template length, underflowing the slice; only default to 6 X's
when none are present.
- printf '%.Ns': byte-sliced the precision and padded by byte length;
truncate and pad by character.
Adds regression tests covering each panic trigger.
A single command that mirrors .github/workflows/ci.yml: cargo fmt --check, clippy (advisory — not a CI merge gate yet), the workspace test suite, cargo doc with -D warnings, and the binding suites. When their toolchains are set up it runs Python (maturin develop + pytest) and Node (build + tsc typecheck + test); otherwise those steps are skipped with a note, so the command is useful whether or not the bindings are built. Also adds a TypeScript type-check (`npm run typecheck` → tsc --noEmit) over the hand-authored public declarations (index.d.ts, native.d.ts) against a usage test in tests/ts/, and wires it into the Node CI job. Previously nothing validated the .d.ts surface, so it could silently drift from the JS. Implemented as a std-only xtask crate (no new Rust deps) plus a .cargo/config.toml alias, the idiomatic Rust-native task runner. Documents the commands in CONTRIBUTING.md and CLAUDE.md.
zastrowm
previously approved these changes
Jun 15, 2026
zastrowm
reviewed
Jun 15, 2026
zastrowm
reviewed
Jun 15, 2026
- Security Model: trim the detailed protect-against / best-effort / not-protected lists to a short summary and defer the full threat model to SECURITY.md (which already carries it). Drops the "escapes from Kernel mediation" phrasing a reviewer flagged as confusing. - MCP Server: condense to a readme-appropriate length and lead the example args with `--mcp`. - release.yml: drop the crates.io publish job (not publishing to crates.io for this release) and the unadvertised CLI-binaries job. PyPI + npm only. - AGENTS.md: stop describing the library as published on crates.io.
zastrowm
reviewed
Jun 15, 2026
zastrowm
reviewed
Jun 15, 2026
Replaces the bare command list in the README with a per-command reference documenting, for each of the ~56 builtins and isolated commands, what is implemented and the notable gaps — missing flags, missing features, and known correctness divergences from GNU/BSD. Every entry was validated by running the release binary and diffing against the system tools. Notable findings captured: regex engine has no backreferences/ lookaround (grep -P unsupported); sed lacks branching and multiline cycle commands; cut/uniq silently process only the first file and head/tail reject multiple files; ls -l omits owner/group columns; date +%s isn't expanded; test/[ and arithmetic treat non-numeric operands as 0; set -o is unsupported; jq (jaq) throws on missing nested keys. SSRF/credential controls verified intact and called out as security guarantees, not gaps. The README "Supported Commands" section now links to COMMANDS.md for detail.
Drop the push-on-every-branch trigger (it double-ran with pull_request and wasted CI) and scope pull_request to `main` with explicit event types, plus workflow_dispatch — matching the convention in strands-agents/sdk-python. Key concurrency on the PR number so superseded runs cancel cleanly.
zastrowm
previously approved these changes
Jun 15, 2026
WASM is a build target, not a published v0.1 artifact (it's not in the release or CI workflows), so it doesn't belong in the product README. Removed the section; the build details already live in CONTRIBUTING.md, which now also carries the reduced-surface note and states WASM isn't a release artifact. Collapsed the per-category command list in the README to a short summary plus a link to COMMANDS.md, which now holds the full command set and a "Shell language" table for the shell machinery (pipelines, redirections, loops, expansion, ...). Fixed the now-dangling README#webassembly-wasm anchors in AGENTS.md and CONTRIBUTING.md.
The release workflow's `napi build` omitted `--js native.js --dts native.d.ts`, so napi defaulted to writing its generated loader to index.js/index.d.ts — overwriting the hand-authored customer wrapper (Shell.create, the ShellError hierarchy). A real npm publish would have shipped the raw napi loader and the wrong TypeScript types instead of the public API. Match the flags used by package.json's build script so the generated loader goes to native.* and the tracked index.* wrapper is left intact.
zastrowm
approved these changes
Jun 15, 2026
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Initial open-source release of Strands Shell — a virtual, Bourne-compatible
shell for AI agents that runs entirely in-process. There is no
fork, noexec,and no direct syscalls; every filesystem, network, and process effect flows
through a single
Kernelmediation boundary, giving callers fine-grained controlover what an agent can see and do (files, network domains, credentials) without
containers, microVMs, or firewalls.
One Rust crate is the single source of truth and compiles to multiple targets:
strands-shell, including the--mcpstdio server) and a Rust library,strands-shellon PyPI) via PyO3/maturin,@strands-agents/shellon npm) via napi-rs,wasm32-wasip2WASM module for any WASI runtime.What's included
Kernelsecurity boundary (src/os.rs) with the bundledVfsKernel(
src/vfs_kernel.rs) over an in-process VFS (src/vfs.rs); host directoriesare exposed via
copy(snapshot) ordirect(pass-through) bind mounts.cd,export,set,trap,getopts,read, …) and33 isolated coreutils-style commands (
cat,grep,sed,sort,jq,curl, …), plus an embedded Lua 5.4 interpreter.curland the kernel's HTTP path block RFC1918,link-local, loopback, and IMDS/ECS-task-role addresses at DNS-resolution time
via
SafeResolver; credentials are injected by URL prefix at request time andnever leak across redirects or to non-allowlisted hosts.
src/mcp.rs) that exposes the shellas tools, and an MCP client (
src/mcp_client.rs) that surfaces configured[[mcp]]servers as Lua modules.CONTRIBUTING + AGENTS guides, issue/PR templates, and a CI matrix
(Rust on Linux/macOS, Python matrix, Node matrix, security audit) plus a
tag-driven release workflow (PyPI Trusted Publishing, npm, crates.io).
Release positioning
Shipped as v0.1 — an opt-in extra with an explicit no-API-stability
disclaimer. Command coverage is a curated subset rather than full coreutils
parity; the scope statement in the README documents which commands are full
reimplementations vs. subsets.
Related Issues
Documentation PR
N/A — user-facing docs (README, CONTRIBUTING, AGENTS, SECURITY) are included in
this PR.
Type of Change
New feature
Testing
cargo test --workspace --all-targets,pytest tests/python,npm test)cargo fmtandcargo clippyThe full suite runs in CI across the Rust (Linux/macOS), Python, and Node
matrices. Integration tests live in
tests/(shell_integration.rs,curl_integration.rs,lua_integration.rs,mcp_integration.rs,vfs_unit.rs)alongside
tests/python/andtests/js/.Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.