Releases: strukto-ai/mirage
Release list
Mirage 0.0.6
We are excited to announce the release of Mirage 0.0.6 🎉🎉🎉
Mirage 0.0.6 is a permissions release. 0.0.5 gave an agent typed programs to act with; 0.0.6 decides what it may do with them. A permissions document replaces the old guard list: allow, ask and deny rules, one role per session, mounts that narrow rather than gate, hidden subtrees that stay hidden through a mutation, an approval door where an asked line reaches a person, and a decision ledger you can query and explain. A policy can now be a program, written in Python or JavaScript and judged at the command, op and session doors. Credentials move behind a secrets plane instead of sitting in a config block. Underneath, a long deduplication pass collapses the backends onto shared HTTP, object-store, hierarchy and render kits, the integration fakes become one TypeScript and Prisma kit that runs off a laptop, bash grows most of tiers 2 and 3, guests see one filesystem through a single stat struct, and Hugging Face Hub arrives as both a mount and a CLI. Python and TypeScript stay mirrored throughout.
pip install mirage-ai==0.0.6 · npm install @struktoai/mirage-core@0.0.6 (and -node, -browser, -server, -cli, -agents)
@struktoai/mirage-dsh joins the shared version line at 0.0.6. It was published once as 0.0.1; the versions between were never released.
Highlights
- Permissions are a document, not a guard list. A permissions document with profiles replaces the guards (#857), carrying allow, ask and deny rules with an approval door where an asked line reaches a person (#865). A session holds one role, and a mount narrows what that role may reach instead of gating it (#876). The path axis gained show entries, per-subtree modes and hide reasons (#896), and a mutation below a hidden path resolves without revealing it (#901). Every decision lands in a ledger with
explainand whole-line judging (#880), reachable through an asks door and workspace-level list-asks, allow and deny (#899). Documented, with(approval <id>)renamed(ask <id>)(#900). - A profile's policy can be a program. A profile takes a script rather than only coded rules (#884), and the policy block's program defines which gate hooks exist:
pre_command,pre_opsandpre_session, probed once per program text, with a hook left out meaning silence and none at all failing closed (#997). The op-door boundary is stated and pinned (#908), codedpre_opsbinds on the command tier (#909), and dsh routes allow, ask and deny through its own approval channel (#890). - Credentials live on a secrets plane. Env-plane managed credentials arrive first (#960), then a config plane and a 1Password source (#973), and finally a mount or CLI credential that reads from that plane rather than holding the value (#978). Alongside it, every TypeScript mount config now validates through one door, with the two languages' field sets gated against each other (#994).
- The backends collapse onto shared kits. One HTTP client kit with notion and discord as exemplars (#835), then every hand-rolled client onto it (#841). One JSON render kit for
.jsonand.jsonlbodies (#823). An object-store kit and a hierarchy kit (#848), taking hf and opfs (#858), postgres, mongodb and the google trio (#868), trello, linear, notion and gcal (#870), discord, slack, gmail and email (#874), and lancedb and qdrant with per-mount routes (#875). The 42 S3-alias resources collapse onto a shared base (#866), and a TypeScript backend is assembled from oneCommandIOtable (#883). - The integration fakes are one TypeScript and Prisma kit. The mock servers unify (#916) and the services follow: dropbox, box and onedrive (#919), slack, notion and mem0 (#925), the hf buckets (#927), databricks, dify and http (#928), and github (#935). They can run somewhere other than a developer's laptop (#905), a run axis rides the URL so two hosts stop sharing one world (#945, #946, #947), and one launcher hosts them all behind pooled sessions (#965).
- Hugging Face Hub is a mount and a CLI. A Hub repo mounts, with the
hfCLI beside it (#931), exercised against a fake in CI (#934), read-only by default (#937), and serving Hub metadata and search (#939). The fake answershf_fserrors the way the live server does (#974), advertises the discovery scopes it claims (#982), serveshf://README.mdbecause the tool document tells the model to read it (#976) and/raw/(#979). - bash tiers 2 and 3. The export attribute and identifier validation (#816); associative arrays, declare attributes,
readonly -fand the jobs flags (#824); thenlet,umask,shopt,alias,mapfile, thereadflags,declare -g/-n,disown/waitandexec(#833). - Guests see one filesystem. Every path-taking
osverb routes through the workspace (#877),symlink,readlinkandsetattrare served (#879), a readdir row carries the link mark (#881), and one stat struct sits at the runtime door with each surface projecting it (#882). Engines and sandbox SDKs are upgraded with the monty Python and TypeScript guest-behavior gaps closed (#904), and the history view and root anchor are withheld from runtimes (#932). Two new providers: a smolvm microVM and a confined sandlock Python runtime (#834), and ssh (#852). - Errors say what the kernel would say. A prefix holding no keys is ENOENT rather than an empty directory (#809, #815), a path under a file is ENOTDIR rather than ENOENT (#813), a directory read carries GNU's errno and exit code (#895),
rmdirrefuses a non-empty directory at the op rather than only in the builder (#854), and every refusal now speaks bash'sPermission deniedinstead of each command's own wording (#993). - Redis reaches the browser through Upstash's REST API, so a browser workspace can use the same cache and store as node (#992).
Breaking Changes
- Guards are gone. The permissions document and its profiles replace them (#857); a session holds one role and a mount narrows rather than gates (#876).
build_resourceis synchronous again (#820), reversing the 0.0.5 change; github hydrates lazily instead. Code written against 0.0.5'sawait build_resource(...)drops the await.FileTypeis the node kind, and content type is its own axis (#878).- core is imported by module path.
index.tsdrops from 1589 lines to 102, so a deep import replaces the barrel (#805), and the dead exports around it are swept (#814). - Builtin commands are per-command packages behind a
BUILTINStable with tiers (#853). ls -lreports the workspace user as owner and the session profile as group (#985).- A Hub mount is read-only (#937).
/dev/nulland/dev/zeroare character devices, not regular files (#910).getState/loadStatesit on the TypeScriptResourcecontract, mirroring Python's base (#800).- Routing is renamed and execution passes through an
ExecContextseam (#944). @struktoai/mirage-dshmoves from its own version line onto the shared one, from0.0.1to0.0.6(#998).
Features
- permissions: the document and profiles (#857); allow, ask and deny with an approval door (#865); one role per session (#876); the path axis, per-subtree modes and hide reasons (#896); the asks door and workspace list-asks/allow/deny (#899).
- policy: decision ledger,
explainand whole-line judging (#880); profiles written by a script (#884); a policy block whose program defines the gate's hooks (#997). - secrets: env-plane managed credentials (#960); config plane and 1Password source (#973); mount and CLI credentials read from the plane (#978).
- cli: virtual
ghworkflows (#915); builtin command catalogs (#929); custom authoring made first-class (#950) with an example (#940) and specs validated at construction (#933); thehfCLI (#931). - shell: bash tier 2 stage 1 (#816); associative arrays, declare attributes,
readonly -f, jobs flags (#824);let,umask,shopt,alias,mapfile,readflags,declare -g/-n,disown/wait,exec(#833). - runtime: smolvm microVM and confined sandlock Python (#834); the ssh sandbox provider (#852); every engine and sandbox SDK upgraded (#904).
- resource: a Hugging Face Hub mount (#931, #937, #939); Redis in the browser over Upstash (#992); mount parents, kit backend ops and a resource class reference (#887).
- core: optional byte-range reads across backends (#810).
- watch:
delta_hookfor ten more backends (#811); push event mapping and subtree invalidation (#817). - integ: a restricted-token GitHub fake,
gh api --jqand notion retrieve-block (#819); branch history recorded when a ref moves (#969); the kit migration (#916, #919, #925, #927, #928, #935) and the run axis (#945, #946, #947, #965).
Bugfixes
- cache: a rename evicts the destination's own listing, across thirteen backends, with disk Windows separators and databricks copy invalidation (#802); a recursive delete or directory rename evicts its subtree (#864, #863); the cache manager walks the ancestor chain (#838); the Redis file cache
addis atomic (#830). - errors: a prefix with no keys is ENOENT (#809, #815); a path under a file is ENOTDIR (#813); a directory read uses GNU's errno and exit code (#895);
rmdirrefuses at the op (#854). - ls: a cross-mount listing is relayed so GNU headers and the global sort survive (#844); a nested mount's root is listed in its parent's
-Rlisting (#847). - rename: directories move whole, on every backend that fakes them (#808).
- search: the grep and rg push-downs are gated on operand count (#851), and the remaining find push-downs with them (#856).
- shell: an orphaned
$varexpands in a redirect target, andrecordis forwarded through the daemon (#926); the tree-sitter engine boots once (#912). - naming: every
<label>__<id>name is budgeted in bytes, not characters (#885); the gmail excerpt and daemon des...
Mirage 0.0.5
We are excited to announce the release of Mirage 0.0.5 🎉🎉🎉
Mirage 0.0.5 is a control-surface release. An agent no longer only reads a workspace, it acts on one through typed programs: a CLI tier turns git, gh, slack, ntn, himalaya, gws, linear, discord and anything you author into installed head words dispatched by name, and a policy layer sits at every door those programs pass through. Underneath, the workspace grows one door per state plane, the runtimes collapse onto a single mount-op vocabulary, background commands stream through a job console instead of arriving whole, and a new @struktoai/mirage-dsh package puts a mirage workspace under DeepSeek Harness as its filesystem and shell. Alongside that, a long conformance sweep pins commands, flags and error text against GNU and the real upstream CLIs. Python and TypeScript stay mirrored throughout, now with a layout parity gate that fails when they drift.
pip install mirage-ai==0.0.5 · npm install @struktoai/mirage-core@0.0.5 (and -node, -browser, -server, -cli, -agents)
New in this release: npm install @struktoai/mirage-dsh@0.0.1, the DeepSeek Harness adapter, on its own version line.
Highlights
- CLIs are a first-class tier. A recursive
CLISpecbuilt onCommandSpecgives a program a typed verb tree (#682), installed host-side into a registry and dispatched by name rather than by operand path, with aclis:section in YAML (#691) and file-reference installs (#798). Builtin families land in waves:himalayaandgws(#699),slack,discord,ntnandlinear(#703),gitover any mount (#710), andghwith the write half of the GitHub fake (#768). You can author your own in code, by pointer, or as a script (#712), and every install is discoverable throughman,typeandwhich(#707) because help renders from the spec. - A CLI that mimics a real program is gated against that program.
ntnruns every shared-battery case a second time against the real npm binary pointed at the same fake, so the grammar cannot drift from upstream without a red build (#740, #747, #756, #794), andhimalayawas realigned to the upstream pimalaya grammar the same way (#709, #723, #761). - A policy layer with hooks at every door.
routebecomespolicyand gains a deny verdict (#659), then a real package withpre_commandabsorbing the old command guards (#690),pre_ops/post_opsat the op doors (#692),ParsedCommandplus a cli fact and registry snapshot (#693), and output safeguards folded in asLimit(#694). Session writes join it: every expansion-time writer (${X:=d},$((X=5)),printf -v,for ((...))) now passes throughSessionView.setinstead of around it (#791). - One door per state plane. Mount structure merges into the door's
readdirandstat(#739), VFS and FUSE ops route through a single door in both languages (#753), and state doors with per-plane views (data, name, session) replace the ad-hoc threading (#771), with a sharedFileHandle/FileTablebehind the buffered handle tables (#760) and per-session hidden paths and vars viaSessionProfile(#778). - Runtimes consolidate onto one vocabulary. A uniform runtime interface and one integ suite for all runtimes (#655), evaluator as a capability with
PythonRuntimedropped (#657), a tiered taxonomy and TS runtime package layout (#726), one mount op vocabulary for the Python (#730) and TypeScript (#732) sandbox runtimes, a resolver protocol (#749), and guest op parity behind oneOpsfacade (#767). pyodide now serves from a custom Emscripten filesystem (#732), flushes without JSPI (#720), and routes guest mutations to the mount with appends staying additive (#728); monty moved to pydantic-monty 0.0.19 (#717);python3parses CPython's real option table (#743). - Background commands stream. A
JobConsolerecords a job's output as timestamped chunks on stdout/stderr/control channels, so a reader can follow a running command from any cursor (#611), with a Redis store and cross-language streaming integ beside the RAM one (#795). - DeepSeek Harness runs on mounted data. The new
@struktoai/mirage-dshpackage providesctx.fsandctx.shellover one workspace (#774), with session binding for the shell executor (#784), a bundle manifest that installs into a stock dsh profile with declarative mounts (#787), and streaming background output, sandbox facts and spill files (#796). - Archivers grew up.
tarandzipplan every member from one shared traversal that merges the backend walk, the namespace's symlinks and the mount table, so a directory operand is walked rather than read, a symlink is stored as a symlink, and a nested mount is refused rather than silently archived (#738);taraccepts GNU's old option style (#734),unzipselects members and exits 11 on unmatched filespecs (#725), and the GPL bzip2 dependency is gone in favor ofmodern-tarplus MITseek-bzip(#741). - Conformance as a gate, not a claim. A layout parity check diffs the Python and TypeScript module namespaces and fails on drift in either direction (#759), the integ runner fails on zero work rather than passing vacuously (#737), resource capabilities and
CommandIOslots are spec-gated (#742), and the Python test tree moved onto the source layout so a source module without a test is visible (#763).
Breaking Changes
- The bundled filetype renderers are gone. Parquet, ORC, feather/arrow/ipc and hdf5 rendering, the
parquet/hdf5/pdfextras and thehyparquet/apache-arrow/h5wasmdependencies are removed; a file with an unregistered extension reads as raw bytes. Registration on a mount survives as the extension point (#651). duhas one backend contract.du_sizeanddu_entriesreplace the flat-listdu_multi; entries are leaf files in mount-relative path space with no summary row, and the generic derives directory rows (#642).- Command handlers take
(accessor, paths, texts, opts). Generics own operands and flag interpretation, builders become wiring (#770), and the dispatcher buildsCommandOptswith typed adapter ops (#772). A handler never declares a flag as a parameter. - One mount-lookup contract:
mountForthrows,tryMountForreturns null (#781). CommandFactsis renamedParsedCommand(#693), andvalue_kindandtypemerge onto oneValueTypeaxis (#689).- One error vocabulary and one stat view per language (#764); absolute operands keep their typed spelling (#765).
PythonRuntimeis dropped in favor of the evaluator capability (#657), and the default python engine is named explicitly (#769).tar -cjis unsupported in TypeScript. Every JavaScript bzip2 compressor is GPL, so TS reads.tar.bz2and refuses to write one; Python still does both (#741).- Notion speaks
Notion-Version: 2025-09-03, where a database is a container plus data sources: the schema lives on the data source, the mount nests a level deeper, and/searchno longer acceptsfilter.value = "database"(#740). - Unknown config keys are rejected rather than ignored, and the index closes and evicts synchronously (#751).
findclassifies walked entries throughstat, never by name; the per-backendis_dir_namehints are gone (#719).
Features
- cli: install registry, dispatch by name, YAML
clis:(#691); CLI tree walk with git-pinned diagnostics (#685); author in code, by pointer, or as a script (#712); install from a file reference (#798);himalaya+gws(#699);slack,discord,ntn,linear(#703);gitover any mount (#710);gh(#768);man/type/whichdiscovery (#707). - policy: policy package with
pre_command(#690);pre_ops/post_ops(#692);ParsedCommandand the cli fact (#693);Limit(#694); deny verdict (#659). - workspace: mount structure in the door's readdir and stat (#739); one door for VFS/FUSE ops (#753); state doors and per-plane views (#771); shared
FileHandle/FileTable(#760);SessionProfilehidden paths and vars (#778); Workspace orchestration split into a package (#681). - shell: job console for streaming background output (#611); Redis console store (#795);
$'...'quoting,git log/showformats, byte-exact MIME parity (#723);sh FILE/bash FILEas a script (#752);export/readonly -p(#661). - runtime: sandbox runtimes with FUSE-mounted workspaces (#590); uniform interface and one integ suite (#655); tiered taxonomy and TS package layout (#726); one mount op vocabulary, Python (#730) and TypeScript (#732); resolver protocol (#749); guest op parity and the
Opsfacade (#767); mount-access conformance suite (#727). - dsh: fs and shell providers over a workspace (#774); session binding (#784); dsh bundle with declarative mounts (#787); streaming, sandbox facts, spill (#796).
- fuse: fskit mount backend and a
MountCore/adapter split (#648). - notion: fake writes, data sources, ntn gated against the real CLI (#740); delete verb and trash bit (#747); comments and object versioning (#756).
- google: Shared Drives in the g* mounts and a configurable Graph service root (#695); folder-scoped creates and Google's own errors (#715); calendar and forms passthrough (#754).
- spec: argparse mirroring with aliases, long-option abbreviation and typed ints (#687); declarative count/multiple/choices/required/default (#679); specs compiled once with short and long flags on one dest (#676); typed spec-validated
FlagViewin TypeScript (#674); capability andCommandIOgating (#742). - cd: a logical cwd, so
pwd -L/-Pmean something (#766). - du:
-S/--separate-dirs(#722). - jq: the rest of jq's flag surface (#713).
- python3: CPython's option table,
sys.pathseeded on pyodide (#743). - integ: jaeger backend and real-server observability (#643); semantic DB virtualization with a JSON harness for every DB backend (#644); standalone suites cons...
Mirage 0.0.4
We are excited to announce the release of Mirage 0.0.4 🎉🎉🎉
Mirage 0.0.4 is an architecture and depth release. Path addressing becomes a real namespace layer with first-class symlinks and attribute overlays that survive restarts; the control plane moves onto pluggable state stores (RAM, disk, Redis, S3) with CAS-guarded writes; the shell grows GNU-grade bash semantics (arithmetic, control flow, brace expansion, printf, getopts, parameter expansion); commands can be run by pluggable runtimes that read and write workspace mounts; and eight new or rebuilt backends land. Python is mypy-clean and TypeScript is tsc-clean, both enforced as CI gates. Python and TypeScript are kept mirrored throughout.
pip install mirage-ai==0.0.4 · npm install @struktoai/mirage-core@0.0.4 (and -node, -browser, -server, -cli, -agents)
Highlights
- The namespace is a real addressing layer. A
Namespacefacade consolidates mount resolution, symlink following, and attribute overlays behind one surface, and the Workspace routes dispatch,apply_io, and post-write invalidation through it instead of holding a dispatcher directly (#420, #424, #426). Symlinks are first-class namespace ops in both languages:ln -screates a real link (not a copy),cat/ls/globfollow on read,rm/mvact on the link entry,cdhonors-L/-Pwith ELOOP on cycles, and the link table is captured into snapshots (#421). FUSE and disk attributes route through the same layer, so a real inode base carries a residual overlay (#505, #509). - A persistent, CAS-guarded control plane. Namespace, observer, and session state unify under one
WorkspaceStateStore(#523) with backends for disk (lockfile CAS), Redis, and S3 (#535, #544). Sessions survive restarts and are shared across processes (#521), with dirty-tracked flushes and generation CAS on both the session and workspace meta records (#530, #533).MIRAGE_HOMEbecomes the single root for the whole tree (#551), and state can be diffed and surgically restored per category (#552). - GNU-grade shell semantics. Bash arithmetic (
(( ))and$(( ))), control flow,setoptions, andtest/[[semantics (#369, #477, #577); brace expansion (#563); full GNUprintfwith Python/TypeScript float parity (#580);getopts(#612); thecommandbuiltin (#595);sort -kKEYDEF grammar (#607); and three waves of agent-facing coreutils coverage — checksums,rmdir,unlink,:,type,chgrp,realpath -e,ln -r,rmsafety flags,env,tr -C/-t,tee --output-error(#603, #613, #617, #618). - Pluggable runtimes that reach the filesystem. A WASI runtime runs CPython on wasmtime (#498), a
node/jsfamily runs on QuickJS in both languages (#504), and Python defaults to the monty sandbox with pyodide on TypeScript (#487). Sandboxed code reads and writes workspace mounts through interception (#508, #514), and a per-line routing ladder picks the runtime from the argument, route, entry script, or VFS (#547, #559). - Cross-mount commands get real strategies. STREAM, FANOUT, and RELAY run per-mount native commands and reassemble the result (#453), with a shared parse so cross-mount lines are parsed against the mount spec like single-mount ones (#474), GNU failure semantics and glob relay (#582), and
du/md5/filefan-out wherecppopulates the read cache (#441). - Eight new and rebuilt backends. Google Drive read/write with a
gwsCLI and fake Workspace server (#549), Box (#562, #579), Dropbox subfolder mounts with a Python port (#558, #568), MongoDB GridFS with native revisions and server-side find (#566), Mem0 (#341), a Prisma-backed fake Slack Web API (#578), nested Trello and Linear CLI families with Linear documents (#581), and a Dify TypeScript backend (#601). OneDrive and SharePoint now share one Microsoft Graph drive core (#532, #534). - Resource change watching. A mount-scoped watch API lets an external agent service react to changes, with a Nextcloud source, attach/detach at runtime, per-root overflow collapse, and nested-mount coverage (#594, #598).
- Provision you can trust. Field-wise combinators and default estimators by command family (#428), one
NodeKindclassification shared by the executor and planner so planner drift is structural rather than accidental (#431), exact glob and recursive-walk estimates with zero-cost stdin stages (#440), and cross-mount plans that sum per-mount estimates (#441). - One declarative integration harness. Python and TypeScript run the same shared harness against every backend (#520), with targets added for s3, onedrive, ssh, nextcloud, sharepoint, hf buckets, gapps, gmail, email, slack, gridfs, box, dropbox, databricks, and dify; the legacy per-backend scripts are retired (#539).
- Types are a gate, not an aspiration. Python mypy went from a 441-module baseline to zero and is enforced (#500 through #522), TypeScript is
tsc --noEmitclean withnoImplicitOverride,noFallthroughCasesInSwitch, and knip dead-code checks in pre-commit (#463, #465).
Breaking Changes
PathSpecis pure-virtual. Theprefixfield and thestrip_prefix/keyproperties are gone; a requiredresource_pathis stamped by the mount at dispatch, withstrip_mount/mount_key/rekey/mount_prefix_ofinutils/key_prefix(#424). Core isPathSpec-only and thestrcoercion shims are removed (#496).- Per-backend op manifests are renamed to
io.py/io.tsexportingIO, and the VFS/FUSE op layer is generated from each backend'sCommandIOtable rather than hand-written (#542, #545, #553). - The Workspace no longer holds a dispatcher directly — resolution, dispatch, and invalidation go through
Namespace(#420). - Session mount grants become a modes vocabulary (read/write/exec), with tuple mounts in TS core (#436, #499).
indexis non-optional; aNULL_INDEXno-op replacesNone(#501).- Python defaults to the monty sandbox, TypeScript to pyodide, for
python3execution (#487). - FUSE sizes changed shape. The 100 MiB sentinel is gone in favor of
direct_io(#491), andFileStat.sizeis render-derived orNone— never a storage-side or source-side number (#488, #489). - Workspace and session ids are UUIDv7, and the reserved defaults are dropped (#526).
MIRAGE_HOMEis the single root and the TypeScript daemon defaults to the disk store (#551).- Per-backend glob boilerplate is deleted in favor of the shared
resolve_glob_withwalk and a custom-backend SDK (#478, #540).
Features
- box: Python + TypeScript Box backend with full read/write and an integ target (#562); special files served raw plus
grep/rgsearch push-down (#579). - coreutils:
envbuiltin,tr -C/-t,tee --output-error(#618); Tier 2chgrp,realpath -e,ln -r,rmsafety flags (#617); Tier 1 flag support (#613); Wave 1 checksums,rmdir,unlink,:,type(#603). - daemon:
config.tomlpath settings and amirage configcommand (#473). - dropbox: subfolder mounts via
rootPath, a Python port, and battery targets (#558);grep/rgsearch push-down viafiles/search_v2(#568). - gdrive: read/write Drive backend,
gwsCLI, fake Workspace server, integ targets (#549). - google: optional
api_baseoverride forGoogleConfig(#596). - gridfs: MongoDB GridFS backend with native revisions and server-side find (#566).
- mem0: read-only Mem0 Memory resource, Python (#341).
- namespace: symlinks as first-class namespace ops (#421); orphaned overlays reconciled on remote delete (#515).
- nextcloud: server-side find via the Files Search API, with partial predicates and fallback (#475).
- printf: full GNU
printfbuiltin with Python/TypeScript float parity (#580). - provision: field-wise combinators and default estimators by command family (#428).
- runtime: WASI runtime (CPython on wasmtime) with
python3safeguards following the script path in TS (#498);node/jscommand family on QuickJS (#504); per-line routing ladder (#547);run_linefor runtimes that run whole lines (#559). - session:
SessionStoreseam so sessions survive restarts and are shared across processes (#521); dirty-tracked flush with generation CAS (#530). - shell: builtin specs —
xargsbatching,timeoutenforcement, GNUecho/read/shift/return(#468); brace expansion in both hosts (#563); GNU control-flow, set-option, builtin, andtest/[[semantics with 147 integ cases (#577);commandbuiltin (#595);getopts(#612). - slack: Prisma-backed fake Slack Web API and integ battery target (#578).
- sort: full GNU
-kKEYDEF grammar (#607). - store: generation CAS on the workspace meta record (#533); S3 backend for the sessions+meta group (#535); disk backend with lockfile CAS (#544).
- trello, linear: nested CLI command families, Linear documents, integ coverage (#581).
- ts: JS sandbox reads and writes workspace mounts (#514).
- version: content-pure commit trees that strip cache and sessions (#536); whole-world commits via the
.mirage/control-plane subtree (#537). - watch: resource change watching with a Nextcloud source (#594); attach/detach runtime surface, per-root overflow collapse, nested-mount coverage (#598).
- Dify TypeScript backend, Databricks JSON harness migration, and a systemic
mkdir -pcache fix (#601). - Codex and Grok Build integrations (#575), a native OpenCode plugin with stale-write protection (#576), and scoped filesystem integration coverage (#587).
Bugfixes
- cache: backend fingerprints thread into
apply_ioso ALWAYS mode stops evicting non-MD5 backends (#434); streamed reads background-drain into the Redis file cache (#439); the drain budget is clamped to the cache limit (#443). - crossmount: the GNU strerror suffix is appended on the not-found branch (#447); GNU failure semantics, relay glob, and dispatcher invalidation (#582).
- **daemon:*...
Mirage 0.0.3
We are excited to announce the release of Mirage 0.0.3 🎉🎉🎉
Mirage 0.0.3 is a large parity and platform release. It lands a GNU-aligned shell environment (history, cwd/env, subshell isolation), a unified command factory shared across every backend, cache read-through with warm serving, the Claude Agent SDK integration, and four new/upgraded backends (SharePoint, Qdrant, OneDrive parity, MongoDB on PyMongo Async). Python and TypeScript are kept mirrored throughout.
pip install mirage-ai==0.0.3 · npm install @struktoai/mirage-core@0.0.3 (and -node, -browser, -server, -cli, -agents)
Highlights
- GNU
historysubsystem (Python + TypeScript). A hiddenObserverrecords every top-level command as timestamp-ordered events;/.bash_historyis a read-only view in GNU histfile format and thehistoryshell builtin (-c -d -a -n -r -w -s -p+ count) routes through the same mount, so the file and the builtin never disagree. History is captured into snapshots and restored on load. (#313) - Claude Agent SDK integration.
MirageServer+build_optionswire a Mirage workspace into the Claude Agent SDK as a tool surface, mirrored in both languages with Python and TypeScript all-tools examples. (#322, #216) - GNU-aligned cwd/env and subshell isolation.
HOME/PWD/OLDPWDmirrors,cd/tilde/CDPATHGNU semantics, relative-path display, and subshell isolation. (#331) - Unified command factory. Backend shell commands are now generated from one shared factory instead of per-backend wrappers, across disk, redis, ram, s3, ssh, google/chat, the database and SaaS families, notion, dify, nextcloud, onedrive, hf, box, dropbox, and email. Flag interpretation lives in the generics; wrappers are wiring only.
- Cache read-through and warm serving. Warm reads are served in place through shared read-through consumers, with invalidation done at the write site via
CacheManager; the file cache is now a store rather than a mount. (#329) - New and upgraded backends: SharePoint multi-site discovery (#365), a Qdrant resource (#367), full OneDrive S3-parity, and MongoDB migrated to PyMongo Async with client metadata (#330).
- Virtual root is now a real mount.
/_defaultis replaced by a real/mount that callers can override with their own/mount.
Breaking Changes
/_defaultis removed. The default scratch space is now a real virtual root mounted at/, overridable by a user-provided/mount.- File cache is no longer a mount. It is exposed as a store; the cache-mount read redirect is removed and warm reads are served in place.
- MongoDB driver migrated from Motor to PyMongo Async (#330).
- Workspace config: the removed
historyfield is dropped from configs; foreign history formats are tolerated on cross-language snapshot load. - Cache API:
invalidate_index_dirsis deleted in favor of write-site invalidation (#329); the factory dropsunsupported_commandsand per-commandrequirestuples.
Features
- sed: GNU-aligned engine:
^/$anchors,s///numeric count andpflag,y(transliterate) andc(change), BRE by default with ERE under-E/-r, multiple-eexpressions,-fscript files, and address negation (addr!cmd) (#340, #326). - diff: full GNU-style recursive
diff -r(py + ts). - find: aligned with GNU coreutils across all backends: GNU start-path emission,
-empty,-not, and unknown-predicate errors (#393, #312). - FUSE: per-mount
Mountspec withFuseManagerownership across both languages, in-memory xattr support, and caller-owned mountpoint cleanup (#345). - github:
grep/rgnarrowing via code search on subdirs and regex, with a-lshort-circuit (#406). - mongodb:
tail -ffollows the change stream and stops caching live reads. - Wasmer and Microsandbox examples running over a Mirage FUSE mount.
Bugfixes
- Many Python/TypeScript divergence fixes:
staton slack/discord/gdrive,duwalk fallback, and assorted GNU command semantics (#419). csplit -fcwd resolution, ssh write recording, and diskmkdirinvalidation ordering (#419).- sed: honor
^/$line anchors in TS substitution and addresses; pattern space excludes the trailing newline (#326). - onedrive:
lstrailing newline (#354), index-cache metadata (#361), and S3-parity command suite (#357). - databricks_volume:
statreadscontent_length/last_modified(#355); record mount-relative write keys intouch/mkdir(#356). - s3/nextcloud: populate
ls -l/statmtime across object-store and API backends (#362). - Cache invalidation completed at every mutation site for create/copy/rm/rmdir (#329).
- Multi-pattern
grep -e/rg -erouted through the generic on search-pushdown backends. - tar: load bzip2/xz codecs via
createRequirefor ESM compatibility; redis read enoent preserves the virtual path; fixedopen()/os interception hijacking real paths under the virtual root.
Changes
- Cross-mount commands (
cp/mv/diff/cmp+ read family) reuse the generics through a dispatch-backed adapter, split into per-command modules. - Shared
epoch_to_iso/epochToIsoutil dedups mtime ISO formatting and enforces second precision; diff flags grouped into a frozen struct. - Dead-code and dead-test sweep (#359, #348).
- Security: resolved CodeQL code-scanning alerts (path-injection, request-forgery, ReDoS), cleared Dependabot vulnerabilities, added server rate limiting, and confined snapshot/load paths (#323, #324, #325, #342, #358, #360).
- Dependencies: bumped joserfc, pyjwt, nodemailer, undici, js-yaml, pypdf, fast-xml-parser, langchain, aiohttp (<3.14 cap lifted), and several GitHub Actions; added an informational
uv auditCI job (#346, #352). - Expanded the cross-language integ harness (history/observer, cache coherence, cross-mount, sed/find/diff, notion database, onedrive).
Contributors
Thanks to everyone who contributed to this release: @zechengz, @sonhmai, @MarshuMax, @hieu650002, @alexbevi, @ki3nd, @anush008, @C1-BA-B1-F3, and @dependabot.
New Contributors
- @MarshuMax made their first contribution: Notion database browsing support (#21)
- @alexbevi made their first contribution: MongoDB PyMongo Async migration + client metadata (#330)
- @hieu650002 made their first contribution: SharePoint multi-site discovery (#365) and OneDrive metadata (#361)
- @anush008 made their first contribution: Qdrant resource (#367)
- @C1-BA-B1-F3 made their first contribution: GNU
findalignment (#393) and compact JSON rendering (#391)
Full Changelog: v0.0.2...v0.0.3
v0.0.2
Release v0.0.2.
TypeScript (npm, @struktoai/*) at 0.0.2:
- mirage-core, mirage-node, mirage-browser, mirage-server, mirage-agents, mirage-cli
Python (PyPI, mirage-ai) at 0.0.3a0 (alpha).
Notable: the CLI now reports its real package version instead of a hardcoded 0.0.0.
v0.0.1 — first public release
The first public release of Mirage — a unified virtual filesystem for AI agents.
Mount S3, Google Drive, Slack, Gmail, GitHub, Linear, Notion, Postgres, MongoDB, SSH, and more behind one filesystem so agents read, write, and pipe across services with familiar shell commands.
What's included
- Python SDK —
mirage-aion PyPI - TypeScript SDKs —
@struktoai/mirage-{core,node,browser,agents,cli,server}(npm publish forthcoming) - CLI + daemon —
uvx mirage-aioruv tool install mirage-ai - FUSE mounts — expose any workspace as a real filesystem (macOS / Linux)
- Agent integrations — OpenAI Agents SDK, Vercel AI SDK, LangChain (deepagents), Pydantic AI, CAMEL, OpenHands, Mastra, Pi Coding Agent
- CLI agent integrations — Claude Code and Codex via FUSE
- Documentation — https://docs.mirage.strukto.ai
Install
# Python (library + CLI)
uv add mirage-ai
# Or run the CLI directly
uvx mirage-aiQuickstart
from mirage import MountMode, Workspace
from mirage.resource.ram import RAMResource
ws = Workspace({"/data": RAMResource()}, mode=MountMode.WRITE)
await ws.execute('echo "hello mirage" | tee /data/hello.txt')See docs.mirage.strukto.ai for the full guide.
License
Apache 2.0. See LICENSE.
Notes
This is an early release. Expect bugs and breaking changes through the 0.0.x line. Report issues at github.com/strukto-ai/mirage/issues or report security concerns per SECURITY.md.