Repository navigation
AetherShell is now IronShell. The binary is ish (ae remains as an
alias), the crate iron-shell, the Python SDK ironshell, the editor extension
admercs.ironshell, and the repository nervosys/IronShell (old links redirect).
Scripts use .ish and variables IRONSHELL_*; the old .ae and AETHER_*
names are not read. A security audit on 2026-11-04 reported 13 findings. This
release fixes them, apart from the residual risks the write-up lists; see
SECURITY_AUDIT_2026-11-04.md.
14.0.0 is a major release because calls that used to be quietly accepted now
fail. Every dispatched builtin carries a declared signature, and the dispatcher
holds calls to it: surplus or mistyped arguments, and pipeline input a builtin
does not take, are refused with E_BAD_ARG before anything runs. Builtins that
used to report success without doing the work now say so with a coded error.
Breaking changes
Calls are checked against their declarations.
- Surplus arguments, wrong types and unwanted pipeline input are
E_BAD_ARG.
Before,journal_clear("a")ignored its argument and cleared the whole
journal. - Optional arguments no longer fall back to a default when they are malformed.
Infs_chmod, the string"0"used to mean 0644; it now means mode 0, and a
malformed mode is refused. A malformedfs_chowngroup is refused instead of
being read as the owner. - A pipeline stage's input goes only to that stage. A failing stage stops the
pipeline with an error that names its index and builtin.
Fake successes are now errors. These used to answer as if they had
worked:
sso_authminted a token for any input. It is nowE_UNIMPLEMENTEDand
mints nothing, sosso_validateanswersvalid: false.finetune_start,job_submit, thecloud_*instance builtins,
remote_exec,repl_serve/repl_connect/repl_broadcast,
workspace_sync,plugin_load,marketplace_installand
marketplace_updatereported work that nothing did.compliance_checkandcompliance_reportcalled every standard compliant,
andaudit_verifycalled an empty log valid.agent_with_mcpreported a run that hit its step limit as completed; it is
nowE_BUDGET_EXCEEDED.web_fetch,web_get,web_scrape,web_downloadandweb_uploadfail on
HTTP 4xx and 5xx.web_downloadof a 404 used to answertrue.
Agent-mode policy. Each of these refuses with E_POLICY_DENY or asks for
approval:
- Network: egress needs approval unless
IRONSHELL_NET_ALLOWnames the host
(*restores the old behaviour).ai_backendscharges, and in agent mode
asks approval for, each endpoint it probes. - Clipboard:
clipboard_get,clipboard_get_imageand
clipboard_historyread nothing unlessIRONSHELL_SECRETS=allowor
IRONSHELL_POLICY=permissive. - Undo and redo:
undo,rewind,session_undoandsession_redoleave
a recorded file outside the workspace jail alone. The step stays in the
journal for a human-mode rewind. - Mode variables:
set_env,env_setandenv_unsetcannot change
IRONSHELL_MODE,IRONSHELL_APPROVE_ALLorIRONSHELL_POLICYfrom agent mode. - Commands that imply agent mode:
ish mcp stdio,ish agent executeand
ish agent interactivenow do, asagent serveandmcp servealready did. - Reclassified effects: many builtins changed effect class, which decides
when agent mode asks.rsync_syncis Destructive.helm_install,helm_upgrade,uv_pipandtest_watchare Exec.- Undo, redo,
journal_clearandsession_endare WriteLocal. - The full list is in CHANGELOG.md.
Renamed or reshaped results.
| Builtin | 12.x | 14.0.0 |
|---|---|---|
proc_kill |
true / false |
{pid, signal, sent: true}, or a coded error |
net_latency |
Int | Float (average round trip) |
nanda_quorum |
total_agents |
electorate |
monitor_sockets (Windows) |
foreign_address |
peer_address, as on every OS |
pkg_list |
status, arch fields; rc packages |
{name, version} for installed packages |
proc_list memory (Unix) |
%MEM | bytes, as on Windows |
from_json, JSON readers |
JSON null as the string "null" |
null |
grep |
substring | POSIX basic regular expression |
npm/pnpm/yarn failure |
record with exit_code |
E_TOOL_FAILED with the stderr tail |
docker_logs / k8s logs |
all output | last 1,000 / 200 lines by default |
crypto_cert_info |
openssl's -text output as a String |
an Array with a Record per certificate |
crypto_cert_verify, no trust store |
false |
E_NOT_FOUND |
crypto_generate_key private key |
PKCS#1 or SEC1 PEM from openssl | PKCS#8 PRIVATE KEY PEM; RSA 2048/3072/4096 only; refused under IRONSHELL_FIPS |
Argument shapes.
| 12.x | 14.0.0 |
|---|---|
docker_run("alpine", "echo hi") |
docker_run("alpine", ["echo", "hi"]); likewise docker_exec, the podman twins and k8s_exec |
tmux_new(name, cmd) |
tmux_new(name), then tmux_send |
age_keygen() returned the key |
an output file is required, and no key is returned |
git_checkout("src/app.rs") restored the file |
the name is read as a revision only |
zip_create, scp_download, age, gpg, xz, zstd overwrote outputs |
an existing output is E_BAD_STATE |
Error codes.
E_DECRYPT_UNAUTHENTICATEDis folded intoE_DECRYPT_FAILED(exit 65).E_CRYPTO_FAILED(exit 70) andE_FIPS_DISALLOWED(exit 77) are new.E_OS_DENIED(exit 77) is new: the operating system refused (file
permissions, another user's or a protected process, a privilege not held).
These wereE_POLICY_DENY, which now means only the shell's own policy.
Migration:catch e { if e.error.code == "E_POLICY_DENY" ... }written for
an unreadable file or a foreign process tests"E_OS_DENIED"instead.applyrefuses a plan of more than 10,000 ops (E_BUDGET_EXCEEDED).- A tool stopped at its deadline is
E_BUDGET_EXCEEDED. - An uncaught
throw, or a failingassertused as a statement, ends the
program with exit 1.
Removed.
- The
askalias ofaiwas advertised but never dispatched. Callai. - The fallbacks that quietly used another tool are gone: rg to grep, fd to
find, and yq to a JSON-only evaluator. A missing tool isE_TOOL_MISSING.
Library and SDK.
- The Python SDK's
Agent.runandSwarm.runbuild the same call as the
agentandswarmbuiltins, and raiseValueErrorfor options those cannot
honour. - In the Rust API,
DQNAgent.stepandMultiAgentRL.stepreturnResult.
Migration
- A script that passed extra arguments, or piped into a builtin that ignored the
pipe, now getsE_BAD_ARG. The message names the parameter and prints the
signature, andish agent schemalists every declaration. - Agents that use the network: set
IRONSHELL_NET_ALLOWto the hosts they
need. - Agents that read the clipboard: set
IRONSHELL_SECRETS=allow, or do it in
human mode. - Modifying a SQLite database: use
db_sqlite_exec.sql,sqlite_query
anddb_sqlite_queryare read-only. - Legacy password hashes: Windows SHA-256 hex hashes and Unix SHA-crypt
($5$,$6$) hashes verify, but only outsideIRONSHELL_FIPS, and should be
rehashed after a successful verify. New hashes are Argon2id (PBKDF2 under
IRONSHELL_FIPS). - Python SDK callers: catch
ValueErrorfromAgent.runandSwarm.run.
New in 14.0.0
ish -bruns the ordinary POSIX subset in-process: 32 of 32 byte-identical to
bash on E6, and 32 of 32 on a held-out corpus. Anything else runs through the
effect gate, neverbash -c.- Data access:
- SQL over typed values and files:
sql,sql_valueand a bundled SQLite. open()parses JSON, JSONL, TOML, YAML and CSV, and.fieldrow syntax
works in pipeline stages.
- SQL over typed values and files:
- Agent tooling:
ish --explainandexplain_effects(code)report a call's
effect class and agent decision without running it. - Native builtins:
- Cryptography on IronCrypto (
ironcrypto0.3.2): signing and
verification with Ed25519, deterministic ECDSA P-256 and P-384, and RSA
PKCS#1 v1.5 with SHA-256 (2048 to 4096-bit keys), interoperating with
openssl dgst; key generation (RSA 2048/3072/4096, P-256, Ed25519) as
PKCS#8 PEM; AES-256-GCM envelopes, Argon2id and PBKDF2 password hashes
(compatible with those 12.x wrote); SHA-2, HMAC-SHA-2 and the random bytes
for keys, nonces and salts; and TLS, throughic-rustls. Noopenssl
process outside theopenssl_*wrappers, and ring is not built. - Certificates on IronSocketLayer's X.509 (
ironsocketlayer0.7.1):
crypto_cert_inforeturns a Record per certificate, and
crypto_cert_verifychecks the chain against the system trust store. - Argon2id password hashing (PBKDF2 under
IRONSHELL_FIPS). - TCP sockets with handles.
- Filesystem watch.
- A one-exchange
web_websocket.
- Cryptography on IronCrypto (
- Real scheduling:
cron_*andat_*have working backends. - Linux system administration: accounts, groups, ACLs, mounts, services,
sudo_execand apt. Verified as root in a disposable Debian 13. - Package listing:
pkg_listcovers apt, pacman, rpm (dnf/yum), Homebrew
and Windows Add/Remove Programs. - Windows:
proc_env,proc_cwd,proc_suspendandproc_resume; file ACLs through
icacls; window listing and operations;fs_mount/fs_unmountof VHD and
VHDX files at an NTFS folder;sudo_execin an already-elevated process
(argv only, no shell; batch files refused);lsof(path), the processes
holding a file open, from the Restart Manager. - macOS: services (launchd), accounts and groups (
dscl), file ACLs
(chmod +a), disk-image mounts (hdiutil),sudo_exec,proc_env, thelibc++
version, clipboard images,
screenshots, and window listing and operations (System Events); read-only
blkid(diskutil),journalctl(log show),monitor_ethtool
(ifconfig) andpkg_history(/var/log/install.log); pointer, key and
text input, the active window and the screen size (Quartz events, which
need Accessibility). - Linux desktop: clipboard types and images (X11 and Wayland), and
gui_screenshot_window(X11). - Rust refactoring and navigation: rename, extract function or variable,
inline, move to file, change signature, definitions, references and callers. - Evaluator speed: in four paired Windows rounds against
570bff8, module
calls ran 3.65x faster and two-argumentreduce2.27x. Workloads with no gain
are listed inbenches/agentic/results/perf-2026-09-29-followup.md. A Linux
rerun of the final code reproduced both, at 4.56x and 1.91x
(benches/agentic/results/perf-2026-10-27.md).
Supported platforms
- Linux and Windows: the full workspace suite passes on both, each test
binary under a memory cap: 264 binaries at b547789.- Linux system-administration and desktop backends are verified only in a
disposable Debian distro. - The Windows service, account, group, scheduled-task, winget, ACL, mount,
window andsudo_execbackends are verified with real changes only on a
disposable GitHub runner.
- Linux system-administration and desktop backends are verified only in a
- macOS: the workspace suite (
cargo test --workspace --features native)
passes on GitHub'smacos-26-arm64image, and the x86_64 and aarch64 Apple
builds succeed. Its service, account, ACL, mount, clipboard-image,
screenshot, window,libc++and process-environment backends are verified
with real changes on a disposable GitHub runner, andsudo_execruns
sudo -nthere as on Linux. Its crontab backend is verified there too. - WASM: the wasm32 library builds without default features. Its behaviour in
a browser is not exercised. - Rust: 1.88 is the MSRV, checked with and without default features. CI
runs Clippy and thelocal_inferencelibrary tests with thecandleand
onnxfeatures; neither loads a real model there.
Known limitations
web_xpathimplements a subset of XPath 1.0 over a lenient in-tree HTML
parser (listed under "No new crates for 13.0.0" below). It is not a full
XPath engine and does not validate XML.count(),following-sibling::and
other axes, variables, parenthesised paths such as(//li)[1], and
comparisons between two node sets are refused with E_BAD_ARG. Use
web_scrapefor a plain tag selector.- The hyphenated PowerShell-style names (
sort-object,where-object,
get-content,get-files) cannot be written in the language, so they have
no declarations. - Windows: clipboard images and window capture are
E_UNIMPLEMENTED, and
so are the Linux system-administration builtins. - Homebrew:
pkg_listhas run only against parser fixtures. crypto_cert_verify: reads its trust store fromSSL_CERT_FILEalone
when it is set, and otherwise from the usual Unix bundle or Git for Windows'
bundle, not the Windows certificate store or the macOS keychain; an unusable
SSL_CERT_FILE, or no bundle, is E_NOT_FOUND. It checks
for TLS server use and checks no host name. RSA keys over 4096 bits are
E_UNIMPLEMENTED.- RSA: keys are 2048, 3072 or 4096 bits for signing, verifying and
generation;crypto_generate_key("rsa", 8192)is E_BAD_ARG. - Key generation:
ssh_keygen,openssl_genrsaandage_keygenwrite
private keys unencrypted. - Processes: a deadline kills a tool's direct child only, so processes
that child started can outlive it. - Output shown unredacted:
env_varsandproc_envredact by variable
name only, so a password insideDATABASE_URLis shown. - Not measured with a live model: the E7 agentic benchmark. It was not run
before release because the current cli/cli corpus ties on one question. - Carried to the next release: the open items in
docs/COMPLETION_PLAN.md,
mostly unimplemented platform branches and end-to-end verification of
operations against real effects. The release went ahead with them open. - Residual security risks are listed under "After the fixes" in the audit
write-up: packages are unsigned, a link swapped between the jail's check and a
write can still redirect it, and approved calls are trusted. - Not checked on real hardware: battery, GPU, sensor and CPU-frequency
readings. - Building
iron-shell-lspon Windows:rustcoverflowed its stack once
compilingiron-shellin that crate's debug profile (0xc0000409). Setting
RUST_MIN_STACK=134217728let it build.
Full changelog: CHANGELOG.md