loomcycle v1.4.0 ships two new substrate primitives. Path (RFC AL) is a Unix-like VFS over Memory + Volumes + Documents using the Linux inode/dirent split: resources keep permanent ids, a dirents row in the runtime store maps (tenant, scope, scope_id, parent_path, name) to resource, one tree spans three resource kinds, renames are cheap dirent updates that never touch the resource. Six ops on the new Path tool (resolve, ls, stat, mkdir as v1 no-op, mv, rm with Linux semantics). Paths reject .. at the boundary; segments [a-zA-Z0-9._-]+, max 64 segments / 1024 chars; tenant-isolated; scope agent/user/tenant matching Memory. A dirent is a name, not an authority grant — the resource's own scope/tenant check still applies. Resources opt in: Memory.set path:, VolumeDef.create mount_at:, Document.create_document path:. SQL Memory stays out of the tree (SELECT doesn't compose with ls). Document (RFC AK Phase 1) is a chunked-graph document where each chunk is a first-class unit with UUID + hierarchy position + optional type + structured fields + graph edges + Markdown body + revision integer. Content/structure split: chunk content (title, body, fields) in Memory keyed by UUID; chunk structure (parent/position/type/status/title/revision + edges + type schemas) in SQL Memory across four tables. Three reasons for the split: different access patterns, dual audit (content + structure), backup composition. 13 ops grouped into document lifecycle, chunk CRUD, edges, query, type defs. Optimistic revision concurrency on update_chunk; atomic deletes in one SQL Memory transaction with bidirectional edge cleanup; delete_chunk refuses the root; move_chunk has a cycle guard; link_chunks validates both endpoints. query_chunks supports structured filters, an under_path Path join, and a validator-gated raw sql: escape hatch through the SQL Memory statement validator. Both primitives are on every transport: POST /v1/_path + POST /v1/_document (HTTP), Path/Document gRPC RPCs riding the existing SubstrateRequest/SubstrateResponse shape, LoomCycle MCP meta-tools path/document, client.path() / client.document() in @loomcycle/client@1.4.0 and python-v1.4.0. Server-side scope/tenant resolution from the authenticated principal, never the wire — an off-run call with scope:"user" keys on the principal's subject, so external UIs and agents interoperate on the same scoped namespace. Both surfaces tenant-confined under ScopeTenant; substrate:admin also satisfies. Bundle semantics for Documents in Path (borrowed from macOS .app): a Document at /docs/foo/v1.0 lists as a directory AND resolves as one resource. Additive — no breaking changes, no wire surface previously consumed. New HTTP endpoints, gRPC RPCs, MCP meta-tools, dirents migration on both backends. Deployments that don't use Path/Document see zero behavior change. Adapters bump to 1.4.0 to add client.path() + client.document(); older adapter code unchanged.
Use RouterBase as an OpenAI-compatible API gateway