Skip to content

feat: expose read-only config snapshot via Shell.config#36

Merged
mkmeral merged 2 commits into
strands-agents:mainfrom
agent-of-mkmeral:feat/expose-shell-config
Jun 19, 2026
Merged

feat: expose read-only config snapshot via Shell.config#36
mkmeral merged 2 commits into
strands-agents:mainfrom
agent-of-mkmeral:feat/expose-shell-config

Conversation

@agent-of-mkmeral

Copy link
Copy Markdown
Contributor

Summary

Adds a read-only configuration snapshot to a constructed Shell across all three surfaces (Rust core, Python, Node), so an embedder can introspect a shell after construction without having held onto the builder or the config object it was built from.

Motivation

Today both bindings build a Shell from a fluent builder / config object and then throw the configuration away. The resulting object only exposes run, set_env/get_env, and the VFS file ops. If you want to embed Strands Shell as a sandbox in a larger framework, you cannot let users hand you a Shell and then build tool descriptions, surface the curl allowlist, or report the active resource caps from it. The Rust core has a Shell::limits() accessor, but it is not surfaced to the bindings and only covers resource caps (not binds/urls/creds).

This PR fixes that with a single read-only config accessor on each surface.

What's exposed

The snapshot reports: binds (source/destination/mode/readonly), credentials, the network allowlist, env, umask, timeout, and resource limits.

Security: secrets are never exposed

Strands Shell's whole pitch is that the agent never sees secrets, so the snapshot never carries resolved credential values. Each credential reports its URL pattern, kind, methods/param, and source — either from_literal = true (a literal token was supplied) or env_var = "NAME" (the variable it is read from) — but never the token itself. The no-leak guarantee is asserted in every test suite (Rust/Python/Node), including the env-var-backed path.

API

Rust

let shell = Shell::builder().allow_url("https://api.example.com/").build()?;
let cfg = shell.config();           // &ShellConfig
cfg.allowed_urls;                   // ["https://api.example.com/"]
cfg.credentials[0].env_var;         // Some("API_TOKEN")  — never the value

Python (frozen dataclasses)

shell = strands_shell.Shell(allowed_urls=["https://api.example.com/"])
cfg = shell.config                  # frozen ShellConfig
cfg.allowed_urls                    # ('https://api.example.com/',)
cfg.credentials[0].env_var          # 'API_TOKEN'  — never the value

Node (deep-frozen object)

const shell = await Shell.create({ allowedUrls: ['https://api.example.com/'] })
const cfg = await shell.config()    // deep-frozen ShellConfigSnapshot
cfg.allowedUrls                     // ['https://api.example.com/']
cfg.credentials[0].envVar           // 'API_TOKEN'  — never the value

Changes

  • src/shell.rs: new #[non_exhaustive] view types ShellConfig, BindInfo, CredInfo, LimitsInfo; snapshot captured at build() time; new Shell::config() accessor; with_kernel() reports a default snapshot. Re-exported from the crate root (src/lib.rs).
  • src/vfs_config.rs: BindMode / CredKind gain Debug/Copy/Eq + an as_str() helper.
  • src/python.rs + python/strands_shell/__init__.py: native carriers + a frozen public dataclass surface (ShellConfig/ConfigBind/ConfigCred/ConfigLimits) behind a Shell.config property.
  • src/js.rs + index.js + index.d.ts: napi object types + a deep-frozen snapshot returned by an async shell.config(), with full TS declarations.
  • Tests: tests/config.rs, tests/python/test_config.py, tests/js/test_config.mjs, and TS type coverage in tests/ts/api.types.ts.
  • README: new "Inspecting configuration" section.

Verification

cargo xtask check passes end to end — cargo fmt --check, clippy, cargo test --workspace --all-targets, cargo doc (with -D warnings), plus the Python (maturin develop + pytest) and Node (npm run build + tsc + npm test) binding gates. The one new clippy nit introduced by making CredKind: Copy (a clone_on_copy in resolve_creds) is fixed in this PR; remaining clippy warnings are pre-existing and unrelated.

New tests: 7 Rust, 9 Python, 8 Node, plus TS type checks. Full suites stay green (no regressions).

Notes / open question

The snapshot is read-only (frozen on every surface), matching the issue's "read only is fine." I deliberately withhold raw credential token values for the security reason above — if you'd prefer the literal token values exposed too, that's a one-field change, but I'd lean against it.

cc @mkmeral — addresses the StrandsShell config introspection request. Marked as draft pending your review of the API shape (especially the credential-source-vs-value decision).

Add a read-only configuration snapshot to a constructed Shell across all
three surfaces (Rust core, Python, Node), so embedders can introspect a
shell after construction without having held onto the builder/config.

This enables using Strands Shell as a sandbox in a larger framework: you
can build tool descriptions, surface the curl allowlist, and report the
active resource caps from a shell object you were handed.

Core (src/shell.rs):
- New view types ShellConfig, BindInfo, CredInfo, LimitsInfo (all
  #[non_exhaustive]); captured at build() time and returned by a new
  Shell::config() accessor. with_kernel() reports a default snapshot.
- Re-exported from the crate root.

Python (src/python.rs + python/strands_shell/__init__.py):
- Native config carriers plus a frozen public dataclass surface
  (ShellConfig/ConfigBind/ConfigCred/ConfigLimits) behind a Shell.config
  property.

Node (src/js.rs + index.js + index.d.ts):
- napi object types plus a deep-frozen snapshot returned by an async
  shell.config(); full TypeScript declarations.

Security: secret values are never exposed. A credential reports only its
URL pattern, kind, and source (a literal was supplied, or the name of the
env var it reads from) -- never the token itself.

Tests: Rust (tests/config.rs), Python (tests/python/test_config.py), Node
(tests/js/test_config.mjs), and TS type coverage (tests/ts/api.types.ts).
All exercise the no-secret-leak guarantee. README documents the feature.

cargo xtask check passes (fmt, clippy, test, doc + Python/Node bindings).
@mkmeral mkmeral marked this pull request as ready for review June 17, 2026 21:08
@mkmeral mkmeral enabled auto-merge (squash) June 19, 2026 19:20
@mkmeral mkmeral merged commit 2d5d5cb into strands-agents:main Jun 19, 2026
21 checks passed
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.

3 participants