Skip to main content
loomcycle
apache-2.0 · agentic kernel · in Go
Loomcycle

An agentic kernel you self-host.

A self-contained Go binary (around 80 MB) that owns the agent loop and ships with everything an agent needs to be useful at scale: agentic memory with bi-temporal validity and subject-document identity, a document store with per-piece derived search units, per-scope SQL memory, a Decision tool for typed probability outputs, a Teams primitive for multi-agent state-machine workflows, a Crypto tool whose keys the model never sees (loomcycle-sealed or an external KMS), ephemeral git-source volumes for code the agent reads, no-trace runs that deliver what they say and store none of it, access-control rule lists with groups and a sign-in gate per identity provider, Office, PDF, scan and recording import into searchable documents, three context-retention modes with a Recall tool over evicted spans, a tool-usage harness that lets small local models call tools at measured 10/10 success, a bundled development toolchain and headless Chromium, a visual canvas (LoomBoard) for building and debugging workflows, multi-replica HA on Postgres, OpenTelemetry, and a deployment-shape snapshot that carries the whole deployment in one archive.

Apache-2.0 · v1.125.0 shipped October 2026 · loomcycle.cloud is live: try the runtime in a browser tab at loomcycle.cloud; hosted chat at board.loomcycle.cloud. The arc from v1.106 → v1.116 added the Decision tool, Teams-as-one-file state machines, poll-mode detached sub-agents, team decision nodes, a deployment-shape snapshot, no-trace runs that store none of what they handle, restricted tokens that expire and bind to agents, queued runs with call lanes and run-slot lending, ephemeral git-source volumes the forge token never leaves, forge webhooks + signed hook deliveries, and a Crypto tool whose keys the model never sees (loomcycle-sealed or in Vault / AWS KMS / Google Cloud KMS). The arc from v1.119 → v1.125 answered an independent security review (re-audit 8/10, up from 6.5), and added access-control rule lists with groups and bindings, sign-in gates (password with TOTP, OIDC, OAuth), a run inbox with the File and Git tools, and Office/PDF import with OCR and speech-to-text. Memory retrieval reaches 0.74 on LoCoMo. Documents retrieval reaches 0.966. · Two months of continuous production operation at JobEmber.ai under real user load, with multi-replica HA on Postgres LISTEN/NOTIFY. loomcycle and the LoomBoard UI are under continuous improvement and optimisation across the runtime and the operator-facing surfaces.

§ 02½ - last week delivered

Seven minor releases this week: v1.119 → v1.125.

The arc from v1.119 to v1.125 landed between October 21 and October 27, 2026. Much of it came from building a document-based reference system on loomcycle: many readers with different rights, sources that arrive as scans, spreadsheets and recordings, and a reviewer who reads the code. Each card links to its writeup; the per-release detail lives in REVISIONS.md.

Security review, answered

v1.119.0 → v1.121.0 · Oct 21–22

An independent SRE review graded loomcycle 6.5/10 for startup use and 4/10 for regulated enterprise. The answer: file tools that open each volume as an os.Root with an identity check per path component, Bash killed by process group, credential header values redacted, open mode refused on a public listener, peppered token hashes with loomcycle tokens rewrap. A re-audit ran proof tests against the pre-fix commits and corrected two ticks in our own table: 8/10 and 6/10. v1.121 closed its residuals. writeup →

Access control: rule lists, groups, bindings

v1.122.0 → v1.124.0 · Oct 24–26

Rules of {effect, actions, resources, when} over every primitive, documents by path included. An explicit deny beats any allow and order never matters. Groups nest and map to identity-provider groups; bindings attach a list to a user, group, token or tenant with an expiry. LOOMCYCLE_ACL goes compat → shadow → enforce, so tomorrow's refusals show up in the audit before anyone gets one. Inside a run the caller's rules narrow tools, volumes and memory, through a pause, a restart and a night-time schedule. A simulator in Settings → Access. writeup →

Sign-in gates for the Web UI

v1.123.0 · Oct 26

The browser no longer holds the API token. Server-side sessions with an opaque HttpOnly cookie, a CSRF header, a sign-out that ends the session on the server, and a strict mode. Three gates: password (Argon2id, NIST SP 800-63B-4 policy, TOTP and recovery codes), OIDC (Google, Entra, Okta, Keycloak, Cognito, Identity Center, Auth0) and OAuth (GitHub, GitLab, Gitea, organisation required on a public instance). A provider says which groups a person is in; it never rewrites an operator's rules. writeup →

Run inbox, File and Git tools

v1.122.0 → v1.125.0 · Oct 24–27

A file a tool returns lands in the run's inbox, and the model sees one stub line: name, type, size, SHA-256, source. Never the bytes. The File tool keeps, downloads, uploads (Microsoft Graph ranged upload included), extracts and imports; v1.125 puts it on HTTP. The Git tool runs on go-git: no process, no system git config, the push credential held by the runtime, commits signable with a Crypto-tool key. writeup →

Office/PDF import, OCR, speech-to-text

v1.122.0 → v1.125.0 · Oct 24–27

Pure-Go extraction of DOCX, XLSX, PPTX, HTML and PDF into Markdown, imported as a Document tagged untrusted, pictures as image chunks by page and slide. Pages with no text layer go through OCR by a vision model, with page caps and a dry-run cost estimate. v1.125 adds speech-to-text (File op=transcribe) through any whisper server and a usage report by purpose. Search filters by path, type, status, tag and as_of act inside every retrieval leg, not after it. writeup →

§ 03 - why this exists

What makes loomcycle different.

Most agent platforms pick one of three shapes: a library you embed, a hosted service you rent, or a gateway that does not run the loop. loomcycle is a self-hostable runtime that owns the loop, ships with the memory, documents, decision model, teams, canvas, bundled dev toolchain and headless browser an agent actually needs, and speaks every wire surface (HTTP, gRPC, MCP, TypeScript adapter, Python adapter).

01

Self-contained Go binary, ~80 MB.

No Node, no Python, no JVM in the model path. The binary ships with the dev toolchain agents need (Python, Go, Rust, Node, git, gh, curl, jq, sqlite3), a headless Chromium, and ephemeral per-run volumes, so an agent is a run away from compiling, scraping, or screenshotting with nothing else to install.

02

Security by design: secrets never touch the LLM.

Three unconditional guarantees: (a) Per-run credentials are substituted at the MCP transport boundary; agents see credential names, never values. (b) The redact run-loop plugin scrubs operator-declared and heuristically-matched secrets (Authorization headers, sk-…, ghp_…, AWS/Slack/generic key=value) from every outbound LLM request. (c) Value-based redaction at rest catches anything that bypassed (a) and (b): the persisted transcript and snapshot never carry literal tokens, even if an agent inlined one into a Bash command.

03

Multi-replica HA, two months in production at JobEmber.ai.

Postgres LISTEN/NOTIFY backplane. Every replica can run the scheduler (DB-claimed slots so two replicas never fire the same job twice). Children of a parent agent survive pause, restart, and replica move. Two months of continuous production operation at JobEmber.ai under real user load with multi-replica HA.

04

Agentic memory with bi-temporal validity and subject-document identity.

Facts carry observed_at, valid_at, invalid_at; a correction never destroys the record; an as_of predicate reads the timeline at any past instant. A subject IS its own Document in the Path tree at /entities/<type>/<name>, so placement is one decision and both halves of a fact land together or neither does. Every row carries a provenance envelope (tenant, session, run, agent, model, compaction generation, source-quote span, server-stamped origin). architecture drawn →

05

Memory retrieval at 0.74 on LoCoMo.

Final paired-benchmark accuracy with the recall_attach_traces runtime grant, a cascade with a Decision-model verifier, and the derived-search-units index. The grant reattaches source turns to a facts recall; the cascade routes most queries past the expensive gate; the verifier catches unanswerables with high recall. retrieval-quality writeup →

06

Documents retrieval at 0.966.

Each chunk derives multiple search units: heading path, prose, code block, transclusion each get their own embedding: so a query for the code block does not compete with the heading for the same vector. The resolution index returns the whole chunk with the matching unit highlighted. 186 of 3,000 heading-only chunks on the reference store were invisible before this arc. documents-indexing writeup →

07

A Decision tool: a model that cannot say the wrong word.

Decision models answer typed questions with calibrated probabilities over a fixed set of options. They cannot emit something that is not an option. Three question types (choice: 2–26 options; noul: yes/no; score: ordered levels), 1–64 questions per call. Available inside a run via Context grant, from outside via HTTP, gRPC, MCP, TS, Python. Shipped in v1.107. the Decision model category →  ·  Decision tool writeup →

08

Teams as one file.

A multi-agent workflow is a state machine. A TeamDef now carries its own local agents, skills, channels, schedules, and webhooks, plus declared variables a start sets. Schedules and webhooks can start a Team directly. TeamDef op=verify returns severity: refused | unrunnable | advisory with JSON paths at fault, before you save. Teams writeup →

09

Detached sub-agent runs that survive restarts.

Agent op=spawn with mode: "poll" returns immediately with {child_run_id, state: "running"}; the parent collects later with Agent op=poll. Children survive pause, restart, replica move. idempotency_key for safe retries, max_wall_seconds for lifetime caps on detached runs, result: "object" for structured child outcomes. Scheduled runs are no longer capped at 10 minutes. orchestration writeup →

10

Three context-retention modes with a Recall tool over evicted spans.

append (baseline, every turn kept), recap L1 (reasoning kept, log evicted), stateful L2 (JSON-schema-validated state Σ carried forward, everything else evicted). A tier-routed context.mode: auto picks the mode from the resolved provider. An opt-in Recall tool queries any span the distillation dropped; an opt-in harvest_to_memory bridges those spans into durable memory for future runs. Working range on a 200-turn chat: about one-fifth of the baseline tokens at stateful on a task-shaped run. context compaction writeup →

11

Local models call tools at measured 10/10.

Small models running in default service positions (memory extraction, document ingest, low-tier chat) used to fight parser failures and first-turn tool-call misfires. The tool-usage harness landed three changes together: 159 per-operation help articles, help inlined into every failed tool-call error (schema plus one worked example in the error body), and a stateful memo that keeps the failing call and the help response together in the next turn's context. On a four-model benchmark against loomcycle v1.100, both stateful models: cloud deepseek-v4-flash and local ornith-1.5:35b: hit 10 out of 10 tasks. tool-usage writeup →

12

Snapshots carry the whole deployment.

A snapshot now carries users and budgets, schedules, webhooks, memory peers, document sources, volume mounts, the Path tree, and the consolidation queue: with HMAC-signed secret references instead of literal secrets. Restore re-validates every definition against the current runtime version; a missing field or an unresolvable credential is flagged at a specific JSON path. One loomcycle snapshot create + restore moves a working deployment to a new VM. snapshots writeup →

Agentic SaaS backend: for teams whose product IS the agents.

You are shipping a product whose agents need to run at scale, in parallel, under multi-tenant constraints, with audit and observability: and you want the whole backend to be the runtime, not an application that bolts an agent framework on. loomcycle is self-hostable, speaks every wire surface (HTTP, gRPC, MCP, TS adapter, Python adapter), and ships with memory, documents, decision model, teams, canvas, dev toolchain, and headless browser in the binary.

The first agentic feature most teams ship is interactive: a user clicks a button, an agent answers, the conversation ends. The second is harder. Agents need to run at 3am whether or not anyone is logged in. They need to react to a GitHub PR opening, a Stripe invoice failing, a Linear issue moving. They need to scale to many users without each user starving another. They need OTEL, a packet-capture residency story, and a trust boundary that holds when a secret accidentally lands in a tool call. None of this is the loop's problem; it is the surrounding substrate's problem, and loomcycle ships that substrate.

The substrate primitives: Memory with bi-temporal validity, Documents with per-piece derived search units, TeamDef, Decision tool, Channel, Scheduler, Webhook, A2A, Evaluation, Context: emerged from real consumer pain. JobEmber.ai (an AI-driven job-search SaaS) runs on loomcycle: its nightly per-user run touches three per-user MCP servers (jobs, Slack, Telegram) without exposing tokens to the agent, fires on a cron schedule per user tier, and survives nightly load under multi-replica HA. Two months of continuous production operation under real user load.

What you keep: a complete agentic backend with the data substrate, the toolchain, the browser, and the ops already assembled. Multi-tenant authorization writeup → · Retrieval-quality arc →

Claude Code's side runtime: for engineers who already drive their day through Claude Code.

Claude Code stays the operator and the conversation surface. loomcycle is the side runtime where the multi-agent work runs. One MCP call from Claude Code starts a Team walk whose states fan out across sub-agents, each running on the model you pick, each with its own channels and variables. Claude Code reads the Team's End node output; its own context never carries the sub-agents' transcripts. Prefer a dedicated chat window? LoomBoard is a native desktop app that talks to the same runtime.

The shape: a Team definition carries its own local agents, skills, channels, schedules and webhooks as one file, declares the variables a start sets, and validates with TeamDef op=verify before saving. Claude Code starts a walk via one MCP call; the walk fans out across sub-agents in poll mode; children survive pause, restart and replica move. The parent collects structured results with Agent op=poll, reads the Team's End node, writes the summary. The 86 files of the target repo never enter Claude Code's context. Teams writeup → · Detached sub-agents →

Your existing .claude/agents/*.md and .claude/skills/*/SKILL.md move into the loomcycle substrate without rewriting: the importer maps the YAML frontmatter onto AgentDef fields, copies the skill body into the system prompt at config-load, and registers everything as content-addressed Defs. The reverse direction is the claude-code-plugin-loomcycle repo: a drop-in Claude Code marketplace plugin that gives Claude Code one-keystroke surfaces to drive your loomcycle substrate (slash commands, skills, opt-in hooks). Claude Code plugin writeup →

The cost angle: Claude Code burns Claude tokens for the conversation that matters. loomcycle can run the delegated agents on DeepSeek, Ollama (nimble / clef / clef-flash / tev1 for decision models; qwen / ornith for chat), vLLM, llama.cpp, or any other provider the structured work does not need Claude for. Same MCP wire surface; the model swap is one AgentDef field. A code-as-agent (provider: code-js) costs zero LLM tokens at all. Local models call tools at 10/10 →

Production-shaped: for teams that need OTEL, multi-tenant, multi-replica, signed boundaries, and a residency story.

Self-hosted by design. Multi-replica HA on Postgres LISTEN/NOTIFY (no Redis dep). Three drop-in OTEL profiles. A2A on both sides. Signed input webhooks. Per-run credentials never reach the agent's view of its credentials map. Value-based redaction at rest plus an outbound-scrub plugin chain. Apache-2.0, residency you can prove with a packet capture.

Whatever stack you are integrating, the trust boundaries hold: A2A on both sides: loomcycle publishes an AgentCard at /.well-known/agent-card.json with three protocol bindings (REST, JSON-RPC, gRPC); external A2A peers from Microsoft Agent Framework, Google ADK, and LangGraph call loomcycle agents as remote skills, and loomcycle agents call external A2A peers as synthetic a2a__<peer>__<skill> tools. Signed input webhooks: HMAC-SHA256 over the raw body, two-layer idempotency (in-memory + durable), strict JSONPath payload projection. Per-run credentials: the substrate substitutes resolved secrets at the MCP transport boundary; agents see credential names, the wire sees values, persisted state sees redacted placeholders.

Two-layer secret discipline: a redact plugin in the run-loop scrubs secrets before the model sees outbound data; value-based redaction at rest catches anything an agent inlined into a tool call so SQLite/Postgres never persist the literal token. The two layers compose: Layer 1 stops secrets reaching the LLM; Layer 2 stops them landing in the DB. An operator's typo (assigning a token to a differently-named shell var) is caught anyway because the match is value-based. writeup →

Three drop-in OTEL profiles: self-hosted Grafana/Tempo/Prom/Loki, Honeycomb, Datadog APM. Plus a bearer-authed /metrics Prometheus endpoint live-read from runtime counters. Pick your backend; no vendor SDK in the loop. Multi-replica HA on Postgres LISTEN/NOTIFY; two months of continuous production operation at JobEmber.ai under real user load. Snapshots carry the whole deployment: users, budgets, schedules, webhooks, memory peers, document sources, volumes, the Path tree, the consolidation queue: so a move between machines is one loomcycle snapshot create + restore. snapshots writeup → · A2A writeup →

§ 04 - what this is not

What loomcycle is not.

A short, candid section. If your situation matches any of these, you'll save time by picking a different tool - and we'd rather route you to the right one than waste your day.

Not a Python or TypeScript framework you embed. If you want a library that lives inside your app's process and gives you an agent abstraction at the function-call level, you don't want loomcycle: you want a framework, and there are good ones. loomcycle is the runtime under that framework, or the runtime instead of it.

Yes, we have a canvas now. The old copy on this page used to say loomcycle was not a visual builder. That stopped being true. The LoomBoard teams canvas renders a Team definition as nodes and edges with live run visualization, drag-to-inject channel and variable nodes, Input and End nodes, a tri-view (Canvas / JSON / Split) with cursor sync between the two, and a Check button that calls TeamDef op=verify before you save. You can still build everything in YAML; the canvas is a view, not a replacement. canvas writeup →

Not a replacement for Claude Code. If you live in Claude Code, you don't want loomcycle to replace it: you want loomcycle to be where Claude Code delegates the multi-agent work it doesn't want carrying in its own context. One MCP call starts a Team walk whose states fan out across sub-agents in poll mode; Claude Code reads the Team's End node output and never carries the sub-agents' transcripts.

§ 05 - primitives

The primitives that make agentic systems learnable.

Memory and Channel are the data substrate: Memory in four facets (key-value, vector, SQL, and the bi-temporal entity graph with subject-document identity). Document and Path give humans and agents one shared name-space, now with per-piece derived search units. AgentDef and TeamDef compose single-agent and multi-agent work; TeamDef carries its own agents, skills, channels, schedules and webhooks as one file. Decision is the typed-probability primitive. Context is the introspection primitive that closes the loop. Scheduler and Webhook are the autonomous triggers. Volume is the per-agent filesystem boundary with ephemeral-per-run defaults. CredentialDef, OperatorTokenDef, HookDef and TokenLimit are the security and governance surfaces. Toolbox (bundled dev toolchain + headless Chromium) and Snapshot (a deployment-shape snapshot, not a transcript) close the self-contained-system story.

Memory

shipped v0.8.0 · bi-temporal v1.75 · subject=document v1.100

Persistent state per agent, per user, per tenant. Four facets: key-value (atomic incr, TTL, cross-run continuity), vector (semantic search via sqlite-vec / pgvector with provider-agnostic embedders, now with per-piece derived search units), SQL (per-scope SQL database the runtime hosts; sqlite + postgres tiers, default-deny sql_scopes gate, explicit + nested transactions, vector columns), and the bi-temporal entity graph (facts carry observed_at / valid_at / invalid_at, a correction never destroys the record, an as_of predicate reads the timeline at any past instant). A subject IS its own Document in the Path tree. The optional recall_attach_traces runtime grant reattaches source turns to a facts recall: LoCoMo final retrieval 0.74.

// recall at a past instant with the trace grant on
{"tool":"memory",
 "input":{"op":"recall",
         "scope":"user",
         "query":"what medicine was I on in April",
         "as_of":"2026-04-15"}}

Channel

shipped v0.8.4

Persistent inter-agent message bus. One agent publishes; another subscribes; no orchestrator handoff. Cursor-based delivery.

// publish to a channel
{"tool":"channel",
 "input":{"op":"publish",
         "name":"jobs.scored",
         "payload":{...}}}

AgentDef

shipped v0.8.5

Content-addressed, forkable, lineage-tracked. The substrate for self-evolution - and loomcycle import claude-code lifts .claude/agents/*.md + .claude/skills/*/SKILL.md directly into the substrate without rewriting.

// fork a new definition
{"tool":"agentdef",
 "input":{"op":"fork",
         "from":"matcher.v4",
         "prompt":"…"}}

Evaluation

shipped v0.8.5

Rate runs against versioned definitions. Selection stays policy - never auto-promote. Humans (or downstream agents) choose.

// score a run
{"tool":"evaluation",
 "input":{"op":"score",
         "run":"r_82a1",
         "rubric":"match.v2"}}

Context

shipped v0.8.7

The introspection primitive. Ten ops covering self · tools · agents · history · help · time. The closing loop that makes the substrate learnable - an agent that can read itself can rewrite itself.

// what tools do I have?
{"tool":"context",
 "input":{"op":"tools"}}    // → list with shapes, costs, allowed-hosts

Scheduler

shipped v0.21 · RFC E

Cron-driven autonomous runs. on_complete hook → channel publish. max_fires self-retire. RFC S adds Channel.await fan-in and Context op=time so the substrate finally has a clock for cycle bucketing and deadline math.

// declare a cron schedule
{"tool":"scheduledef",
 "input":{"op":"create",
         "cron":"0 3 * * *",
         "agent":"nightly-scan",
         "max_fires":30}}

Webhook

shipped v0.22 · RFC H

Signed-by-default external trigger. HMAC-SHA256 over the raw body - Stripe, GitHub, Linear, n8n envelopes all auto-detected. Two-layer idempotency (in-memory + durable). Never silently degrades.

// declare a webhook endpoint
{"tool":"webhookdef",
 "input":{"op":"create",
         "path":"github-pr",
         "delivery":"spawn",
         "agent":"pr-reviewer"}}

Volume

shipped v1.1.0 · ephemeral by default

Per-agent ro/rw filesystem roots. {name, path, mode}. Ephemeral per-run by default: a volume auto-purges when the top-level run completes (clone a repo, work, vanish: nothing persists across runs). Durable mounts are opt-in via the operator's volumes: config. Static volumes from YAML plus a runtime-mutable VolumeDef substrate (tenant-scoped, runtime-derived path, never caller-supplied). Spawn-narrow: a sub-agent's volume set ⊆ its parent's. The Bashbox tool honors ro volumes via an in-RAM write overlay. VolumeDef.create mount_at: registers a volume_mount dirent in the Path tree.

// ephemeral volume for an on-demand workspace
{"tool":"volumedef",
 "input":{"op":"create",
         "name":"lc-src",
         "mode":"rw",
         "ephemeral":true}}

Path

shipped v1.4.0 · RFC AL

Unix-like VFS over Memory, Volumes, and Documents. Tenant-rooted, scope-aware. Borrows the Linux inode/dirent split: resources keep permanent ids, a dirents row maps (parent_path, name) → resource. One tree spans three resource kinds; renames are cheap dirent updates that never touch the resource. Six ops (resolve / ls / stat / mkdir / mv / rm). Paths reject ..; segments [a-zA-Z0-9._-]+. Resources opt in to a name: Memory.set path:, VolumeDef.create mount_at:, Document.create_document path:. SQL Memory stays out of the tree. A dirent is a name, not an authority grant: the resource's own scope/tenant check still applies. On every transport.

// list a directory
{"tool":"path",
 "input":{"op":"ls",
         "path":"/docs/launches/",
         "scope":"user"}}

Document

shipped v1.4.0 · derived search units v1.100

Chunked-graph documents. Each chunk is a first-class unit: UUID, hierarchy position, optional supertag-like type, structured fields, graph edges, Markdown body, optimistic revision. Per-piece derived search units (v1.100): a chunk with a heading, prose, a code block and a transclusion now generates one embedding per piece: a query matching the code block does not compete with the heading for the same vector; the index returns the whole chunk with the matching unit highlighted. 186 of 3,000 heading-only chunks on the reference store were invisible before. Documents retrieval final 0.966. Content/structure split (chunk content in Memory keyed by UUID, structure in SQL Memory); query by structured filter plus under_path Path-join plus a raw sql: escape hatch through the SQL Memory validator; atomic deletes; bidirectional edge cleanup; move_chunk cycle guard. A Document lists as a directory in Path and resolves as one resource.

// query the chunk graph under a path
{"tool":"document",
 "input":{"op":"query_chunks",
         "under_path":"/docs/launches/",
         "type":"publication",
         "status":"draft"}}

CredentialDef

shipped v1.11.0 · RFC AR

Encrypted per-tenant secret store. Envelope AES-256-GCM: a deployment KEK (LOOMCYCLE_SECRET_KEY) plus a per-tenant DEK derived via HKDF-SHA256. GCM AAD binds each ciphertext to its row identity (key_id | tenant | scope | scope_id | name), so a row copied to another tenant fails authentication at decrypt. Scope precedence agent > user > tenant. Consumers: $cred:<name> substitution in HTTP MCPServerDef headers resolves per-request; tenant + user provider-key override by env-var name (a CredentialDef named ANTHROPIC_API_KEY at tenant scope shadows the operator host key for every Anthropic call from that tenant). Backends: inline (default) plus stubs for Vault / AWS Secrets Manager / GCP Secret Manager / 1Password Connect. Snapshots exclude sealed rows by design; a restore requires the target deployment to hold equivalent CredentialDefs.

// store a per-tenant API key
{"tool":"credentialdef",
 "input":{"op":"create",
         "name":"ANTHROPIC_API_KEY",
         "scope":"tenant",
         "backend":"inline",
         "value":"sk-ant-..."}}

TokenLimit

shipped v1.11.0 · RFC AW

Per-scope token budgets with soft-warn + hard-cap tiers. A budget is {tenant, scope, scope_id, window, soft, hard}; scope is operator / tenant / user; window is a calendar-month UTC. Most-restrictive-of-the-three-scopes wins. At admission, limits.Check refuses over-hard runs (429 on HTTP, ResourceExhausted on gRPC). In-flight, the ledger emits an EventLimit event on newly-crossed thresholds, riding the same channel as text / tool-use / thinking events on HTTP SSE + gRPC + MCP + adapters + the Web UI's run terminal (amber banner soft, red hard, inline in the transcript). The in-memory tracker boot-seeds from the token_usage ledger, so a restart doesn't reset counters. The Web UI Limits page renders the live month-to-date used column with K/M/G shorthand in the editor.

// set a monthly cap for a user
{"tool":"tokenlimit",
 "input":{"op":"set",
         "scope":"user",
         "scope_id":"alice",
         "soft":"5M",
         "hard":"10M"}}

Skill (on-demand)

shipped v1.14.0

SkillDefs are not bundled into the system prompt at boot; agents fetch them on demand under a pattern allowlist. A Skill tool with two ops: list enumerates the agent-visible catalog (static bundles + inline defs + the caller's tenant SkillDefs) filtered by the allowlist + an optional /-glob pattern; invoke loads and runs a permitted skill. The agent's skills: field is a pattern allowlist. Empty means allow-all with the Skill tool auto-added; -* means deny.

// list writing-domain skills
{"tool":"skill",
 "input":{"op":"list",
         "pattern":"writing/*"}}

TeamDef

shipped v1.17 · one-file v1.104 · verify v1.105

A multi-agent workflow as a state machine. A Team definition carries its own local agents, skills, channels, schedules, and webhooks as one file, plus declared variables a start sets. States interpolate prior answers (${steps.triage.answer}) and capture into named variables; routing nodes gate transitions on conditions or on Decision-tool probabilities. Schedules and webhooks can start a Team directly. TeamDef op=verify returns severity: refused | unrunnable | advisory with JSON paths at fault, before saving. Operator can watch the Team's own local channels (read-only).

// start a Team walk
{"tool":"teamdef",
 "input":{"op":"run",
         "name":"support-triage",
         "variables":{"ticket":"..."}}}

Decision

shipped v1.107

A model that answers with calibrated probabilities over a fixed set of options. It cannot emit something that is not an option. Three question types: choice (2–26 options), noul (yes/no with probability of yes), score (ordered levels with expected position). 1 to 64 questions per call. Available inside a run via Context grant, from outside via HTTP, gRPC, MCP, TS, Python. Powers the memory reranker (LoCoMo recall@5 lifted 0.588 → 0.740), the cascade verifier, and any classification / routing / triage agent that was fighting prose-model parsers. the category hub →

// classify sentiment with calibrated probabilities
{"tool":"decision",
 "input":{"question":"what sentiment?",
         "context":"the food was great but...",
         "type":"choice",
         "options":["neg","neu","pos"]}}

Snapshot

shipped v1.101

A deployment-shape snapshot, not a transcript archive. Carries users and budgets, schedules, webhooks, memory peers, document sources, volume mounts, the Path tree, and the consolidation queue. HMAC-signed secret references instead of literal secrets (the archive never carries literal credentials). Restore re-validates every definition against the current runtime version; a missing field, a removed op, or an unresolvable credential is flagged at a specific JSON path. Default is refuse; a degraded-mode flag quarantines flagged items. One loomcycle snapshot create + restore moves a working deployment to a new VM.

// create a whole-deployment snapshot
{"tool":"snapshot",
 "input":{"op":"create",
         "include_queue":true}}

OperatorTokenDef

shipped v0.17 · multi-tenant

Per-principal bearer tokens for multi-tenant auth. A token is {tenant, user, scopes, rate_limits, expires_at}; the server verifies on every request. Scopes bind to specific transports and specific tool classes. Two access modes for a tenant's own users: isolated (scope-locked to own data) and member (full tenant HTTP plane minus operator carve-outs). URL-free sign-in handoff via origin-checked postMessage + same-origin POST /ui/session keeps bearers out of every access log. Tokens survive snapshots as references, not values.

// mint a per-user token
{"tool":"operatortokendef",
 "input":{"op":"mint",
         "user":"alice",
         "mode":"member"}}

HookDef

shipped v1.80 era · audit on every tool call

Pre and post hooks for tool calls, prompts, and run lifecycle events. A hook can observe, narrow, delay, or deny: never widen. Hook decisions are audited and reach the operator (the Web UI renders each decision as a readable line in the transcript). A failing hook never silently drops the tool's error classification. Hook callbacks pass through the SSRF guard so a tenant hook cannot reach private addresses. Shipped alongside the structured-error (errorCategory, isRetryable, retryAfterSeconds) surface that makes failures a model can respond to.

// register a hook that audits every memory write
{"tool":"hookdef",
 "input":{"op":"register",
         "event":"tool_call_pre",
         "match":{"tool":"memory"}}}

Toolbox + Headless browser

in the binary

The ~80 MB loomcycle binary ships with the development tools agents need (Python, Go, Rust, Node, git, gh, curl, jq, sqlite3) and a headless Chromium in-process. An agent that needs to compile code, run tests, scrape a page, submit a form, or take a screenshot does not need an external sidecar, a separate toolbox image, or a Playwright install. Volumes default to ephemeral per-run: intermediate files are cleared when the run ends; durable mounts are opt-in via the operator's volumes: config. The deployment stays clean by default.

// fetch and render a page in the bundled browser
{"tool":"browser",
 "input":{"op":"fetch",
         "url":"https://example.com",
         "screenshot":true}}
§ 06 - trust model

Security by design. Same binary. Two postures.

Security by design - the substrate makes three guarantees about secrets:

  1. Per-run credentials never reach the LLM. Resolved tokens are substituted at the MCP transport boundary inside the runtime; agents see credential names, never values. The LLM's view of its credentials map is empty of resolved tokens. Persisted state sees redacted placeholders.
  2. Outbound scrub before the model sees data. The redact plugin in the run-loop chain scrubs secrets from every outbound LLM request - Tier-A: operator-declared env-var values get masked exactly (customizable - add an env var to the operator secrets map, the plugin masks its value everywhere outbound); Tier-B: built-in heuristic patterns catch Authorization headers, sk-… OpenAI keys, ghp_… GitHub tokens, AWS / Slack / generic key=value shapes regardless of operator config.
  3. Value-based redaction at rest. Anything that bypasses (1) and (2) - an agent inlining a token into a Bash command, for example - is caught at persistence time. SQLite/Postgres never store the literal token; the match is value-based, so an operator's typo (assigning the token to a differently-named shell var) is caught anyway.

These guarantees are unconditional - they hold across both postures below. Postures change what tools an agent can call. The secret-isolation guarantees never change. redact plugin writeup → · per-run credentials writeup →

The UNIX shape you already know - operator, caller, agent. Operator config is the floor; callers can narrow per-request but never widen. The bearer token is the authority.

posture A

True managed sandbox

  • Default-deny every tool
  • No FS roots
  • No Bash
  • Caller-authoritative allowed_hosts
  • No outbound by default

Shared-server deployments processing untrusted input. Multi-tenant SaaS. Anywhere the caller isn't the operator.

posture B

Agentic dev environment

  • Bash on, scoped FS roots
  • Broad allowed_hosts
  • Local Ollama for offline work
  • Operator-trusted tooling
  • Iteration speed prioritized

Local development. Internal trusted operators. The single-machine workflow where you are the caller.

§ 07 - providers

Seven inference modes. One interface. No vendor binary in the loop.

Six LLM providers plus code-js - operator-authored JavaScript through goja, at zero LLM tokens. An AgentDef picks its backend via one provider: field; the rest of the substrate (scoping, OTEL, sub-agent composition, trust model) stays identical across all of them. Resolver picks (provider, model) per tier and effort. Cross-provider fallback. Native HTTP-only.

Anthropic
OpenAI
DeepSeek
Gemini
Ollama (cloud)
Ollama (local)
code-js (goja)

// Provider interface

caps:cache_control · reasoning · tools
resolve:(tier, effort) → (provider, model)
fallback:on 429 · strip reasoning_content
pin:v0.8.13 · pin-after-success

→ Pin-after-success ends the transcript-translation bug class. Cache_control where supported. No bundled SDK.

+ OpenAI-compatible front door - POST /v1/chat/completions and POST /v1/embeddings on top of the same resolver / quota / audit layer. Drop loomcycle in front of any LangChain, LlamaIndex, n8n Chat Model, or RAG pipeline that already speaks OpenAI's wire format. Read the writeup →

{ } Code-as-agent (provider: code-js). Operator-authored JavaScript bodies executed in-process via goja - no host filesystem needed, no LLM call. Same AgentDef shape, same scoping rules, same OTEL spans, same sub-agent composition. Code agents can spawn LLM agents and vice versa. Bundled examples ship in the repo at internal/examples/code-agents/. Read the writeup →

⚠ Dev-only: Anthropic MAX subscription OAuth. Sign in with your Claude MAX subscription; local agent runs use subscription-priced inference instead of pay-per-token API. The integration is reverse-engineered (originally by the Pi agent team) - see the full disclaimer and operator setup guide on GitHub → before enabling.

§ 08 - observability

OTEL-native. Three drop-in profiles. Pick your backend.

loomcycle emits OpenTelemetry traces, metrics, and logs out of the box - and now ships three operator-ready profiles so you can land on a working dashboard in one docker compose up, or wire to your existing SaaS in under fifteen minutes. The OTEL Collector turns spans into Prometheus histograms downstream, so label cardinality and bucket boundaries live outside the binary. No vendor SDK in the loop.

Profile A - OSS stack

PR #257 · 2026-05-28

One docker compose up brings up Grafana + Tempo + Prometheus + Loki + OTEL Collector with a ten-panel loomcycle-overview dashboard auto-provisioned. Run latency p50/p95/p99, provider RTT, tool call rate, MCP latency, error rate by provider - plus process and concurrency from /metrics. seed.sh drives synthetic traffic so the panels populate immediately. Self-hosted, no SaaS bill.

Profile B - Honeycomb

PR #258 · 2026-05-28

Set four env vars and you're sending OTLP to your Honeycomb dataset at a production-sensible 10% sampler. Ships eight canonical queries (run rate, latency, provider RTT, tool rate, MCP latency, error rate, token spend, slowest traces), three derived-column definitions, and a ten-minute board-authoring walkthrough against your team's dataset.

Profile C - Datadog APM

PR #259 · 2026-05-28

OTLP to your existing Datadog agent on :4318; agent forwards to the Datadog backend. Same eight canonical queries as Profile B in Datadog APM syntax, plus a DD_SITE knob for non-default regions and a fifteen-minute dashboard-authoring walkthrough against your org's service tags.

+ GET /metrics - Prometheus text-format endpoint exposing seven series live-read from runtime counters: RSS, heap, goroutines, concurrency active+queued, per-user fairness, build info. No DB hop, no sampler dependency, bearer-authed. Cluster mode auto-tags every series with replica_id. profiles + reference on GitHub →

→ Agents can self-discover the surface: Context.help(topic="observability") returns the same profile-picker the operator README serves. Help is a tool, not a website.

§ 09 - changelog highlights

Six waves plus two weeks: v0.12 → v1.0 (substrate), v1.1 → v1.14 (operator surface), v1.15 → v1.23 (teams, history, safe code), v1.24 → v1.53 (memory, documents, users, cloud), v1.54 → v1.100 (retrieval quality and tool-usage), v1.101 → v1.111 (teams-as-one-file, Decision tool, canvas, deployment-shape snapshot), v1.112 → v1.116 (no-trace runs, git-source volumes, queued runs with call lanes, Crypto tool and KMS, bridges), and v1.119 → v1.125 (security re-audit, access control, sign-in gates, files, document import): this week's wave is at the top.

The first wave (v0.12 → v1.0) shipped every major substrate commitment: multi-replica HA, A2A on both sides, signed webhooks, scheduled runs, per-run credentials, the redact plugin, code-as-agent, interactive terminal, context compaction, external MCP fan-out. The second wave (v1.1 → v1.14) shipped the operator surface: Filesystem Volumes, Bashbox in-process shell, Path VFS + chunked-graph Documents, tenant-operator Web UI, vision + thinking on the wire, encrypted per-tenant credentials, per-call cost attribution, per-scope token budgets, a whole-repo security-hardening pass (17 findings closed), and on-demand Skills. The third wave (v1.15 → v1.23) added a first-class search-provider cascade, client-executed tools, a state-machine primitive for multi-agent workflows (agent teams), a History tool for past chats, config-driven LLM providers in YAML, turn-scoped cancellation, and safe code execution via a hardened builder sidecar. The fourth wave (v1.24 → v1.53) shipped agentic memory as a first-class capability (facts, notes, and documents in one search with bi-temporal validity + provenance), the tenant-owned user system with per-user token minting and two access modes, and the public reference deployment at loomcycle.cloud. The fifth wave (v1.54 → v1.100) landed the retrieval-quality arc: subject-document memory identity, the recall_attach_traces runtime grant, a cascade with a verifier, derived search units for documents, and a tool-usage harness that put local models at measured 10/10 success. The sixth wave (v1.101 → v1.111) landed Teams as one file, the Decision tool as a general primitive, the loomboard canvas for state-machine workflows, poll-mode detached sub-agents with idempotency and lifetime caps, and snapshots that carry the whole deployment in one archive. The v1.112 → v1.116 week added no-trace runs, git-source volumes, queued runs with call lanes, the Crypto tool and four chat bridges. All of it below.

v1.112 → v1.116 week: no-trace runs, git-source volumes, queued runs, Crypto tool, bridges.

The Crypto tool

v1.116.0 · Oct 19

An agent names a key; the runtime encrypts, decrypts, signs, verifies, MACs, generates a TOTP or hashes. Only the result comes back. Keys live in loomcycle sealed under LOOMCYCLE_SECRET_KEY, or in Vault Transit, AWS KMS or Google Cloud KMS: in that case the key material never leaves the KMS. JWE and JWS, X25519 and RSA-OAEP/PSS, Argon2id passwords, data by reference so the model never reads it. The same ops are on the operator API (POST /v1/_crypto, gRPC, MCP, TS and Python). writeup →

No-trace runs

v1.112.0 · Oct 15

An agent run that delivers what it says to its caller and stores none of it. The transcript, the tool calls, the model inputs, the sub-agent answers: all pass through the loop and never reach the store. Toggled by the AgentDef flag, authorised through the token restrictions, and fenced from leaking into a parent run. The sibling features in the release: restricted tokens with lifetime, agent list, override lock and run-rate; strict budget enforcement that stops a run in flight; metered llm:gateway; one-call run-tree delete: ship the same posture. writeup →

Git-in-the-core, ephemeral volumes

v1.113.0 · Oct 16

An agent can be given a repository the runtime fetched itself: an ephemeral read-only volume cloned from a git source. The forge token never enters a shell. The agent reads the repo by line range through the Read tool, bounded by diff size and inflated pack size. Works against GitHub, Gitea and GitLab, with sibling features in the release: forge webhooks that can start runs, signed hook deliveries, and the Microsoft Teams bridge that fronts an interactive agent. writeup →

Queued runs + call lanes + run-slot lending

v1.113.0 → v1.114.0 · Oct 16–17

A run that cannot start at once is queued, not refused: it gets its row, its id and its events before it waits, it is cancellable, and it survives a restart. A provider's max_concurrent now counts model calls in a lane per model kind, so a run holds no provider slot while it runs a tool or waits for a child. A run whose model call waits for a saturated local provider lends its run slot to a run bound elsewhere. Queue-aware routing lets a run skip a busy provider for an idle candidate of its tier. writeup →

Bridges on a shared core

v1.113+ · bridge-core, Teams, Slack, Telegram, Discord

The Microsoft Teams bridge that shipped in v1.113 refactored onto @loomcycle/bridge-core, a shared core that handles identity, idempotency, token minting, Markdown defusing and the operator $cred: envelope. Three siblings followed: @loomcycle/bridge-telegram, @loomcycle/bridge-slack (every message inert by construction, no live mentions, every link's real target shown), and @loomcycle/bridge-discord over HTTP interactions. One operator token, one deployment, four chat surfaces. writeup →

v1.101 → v1.111 wave: teams-as-one-file, Decision tool, canvas, snapshots.

Teams as one file

v1.103 → v1.108

A TeamDef now carries its own local agents, skills, channels, schedules and webhooks, plus declared variables a start sets. Template-and-capture between states (${steps.triage.answer}, capture: {as: priority}). TeamDef op=verify returns severity: refused | unrunnable | advisory with JSON paths at fault. Operator view into team-local channels. writeup →

Decision tool

v1.104 reranker · v1.107 general tool

Typed probability outputs for any agent. v1.104 shipped memory.reranker.kind: decision (LoCoMo recall@5 0.588 → 0.740). v1.107 made the primitive general: Decision.ask over HTTP, gRPC, MCP, TS, Python. Three question types (choice, noul, score), 1–64 questions per call. Model aliases now carry kind: chat | decision | embedder. category hub →  ·  writeup →

Loomboard teams canvas

arcs CZ · DV · DX

States as nodes, transitions as edges. Live run visualization (states highlight as a walk progresses; click a running state and the sub-agent's conversation opens streaming live; abort control stops a walk mid-flight). Drag-to-inject channel and variable nodes. Input node starts a walk from a form; End node shows the output chunk. Tri-view (Canvas / JSON / Split) with cursor sync; New / Save / Import / Download; Check button calls TeamDef op=verify. writeup →

Detached sub-agent runs

v1.105 → v1.106

Agent op=spawn with mode: "poll" returns immediately; parent collects with Agent op=poll. Children survive pause, restart, replica move. idempotency_key for safe retries. max_wall_seconds for lifetime caps on detached runs. result: "object" for structured child outcomes. Scheduled runs no longer capped at 10 minutes. writeup →

Deployment-shape snapshot

v1.101 · 127 PRs

Users, budgets, schedules, webhooks, memory peers, document sources, volume mounts, the Path tree, and the consolidation queue: in one archive. HMAC-signed secret references, never literal secrets. Restore re-validates every definition against the current runtime version. Also folded in: a security review that closed cross-tenant and isolated-member gaps in webhooks, triggers, remote peers, the SSRF guard, and volume paths. writeup →

v1.54 → v1.100 wave: retrieval quality and tool usage.

Subject-document memory identity

RFC CV era

A fact used to be stored twice: a key/value row semantic recall searched plus a separate entity-graph chunk that graph walks reached. The two halves could silently land in different scopes. Collapsed into one representation: the subject IS its own Document in the Path tree at /entities/<type>/<name>. Placement is one decision. Both halves land together or neither does. graph_recall seeding rebuilt (30 ms vs 928 ms on a 2,942-row scope). architecture →

recall_attach_traces + cascade verifier

RFC DF era · final 0.74

A runtime-supplied grant that reattaches source turns to a facts recall. Lifted LoCoMo paired-benchmark accuracy to the final 0.74. A cascade routes threshold-clear questions past the expensive gate; a Decision-model verifier reads the retrieved material on ambiguous cases and catches unanswerables at high recall. Two other shapes for delivering the same grant (tool-parameter, imperative-prompt) failed measurably: only the runtime-supplied shape works. writeup →

Derived search units for documents

v1.100 · final 0.966

Each chunk now derives multiple search units: heading path, prose, code block, transclusion each get their own embedding. A query for the code block does not compete with the heading for the same vector. The index returns the whole chunk with the matching unit highlighted. 186 of 3,000 heading-only chunks on the reference store were invisible before. Documents retrieval final 0.966. writeup →

Tool-usage harness for local models

159 help articles · errors carry help · stateful memo

159 per-operation help articles under tools/<Tool>/<op>.md. Every failed tool-call error now carries the operation's schema plus one worked example inlined into the error body. The stateful memo keeps the failing call and the help response together in the next turn's context. On a four-model benchmark against v1.100, both stateful models (cloud deepseek-v4-flash and local ornith-1.5:35b) hit 10 of 10 tasks. writeup →

Context compaction: three retention modes + Recall tool

RFC CR + RFC CT

append (baseline), recap L1 (reasoning kept, log evicted), stateful L2 (Σ carried forward, everything else evicted). Tier-routed context.mode: auto picks by resolved provider. An opt-in Recall tool queries any span the distillation dropped; an opt-in harvest_to_memory bridges those spans into durable memory. Working range: about one-fifth of baseline tokens on a task-shaped run. writeup →

v1.24 → v1.53 wave: memory, documents, users, cloud.

loomcycle.cloud is live

Aug 2026

Three subdomains, three jobs. loomcycle.cloud is the landing plus a browser-local token vault (AES-GCM under a passphrase) that hands the bearer to the runtime through an origin-checked postMessage. app.loomcycle.cloud is the runtime itself: Web UI, HTTP plane, operator console. board.loomcycle.cloud is the hosted loomboard SPA, reverse-proxying /v1 to the runtime on the same tailscale netns so the browser sees same-origin (loomcycle emits no CORS by design). Same Docker image self-hosters run. Nothing hosted-only. writeup →

Agentic memory (RFC BL + BW)

v1.33.0 → v1.49.0

Facts, notes, and documents in one per-scope memory. A background consolidator turns finished chat transcripts into distilled facts with provenance and bi-temporal validity (a fact true last month stays queryable at last month's date, even after the world moves on). Hybrid vector + full-text retrieval with Reciprocal Rank Fusion. Honest source selectors on the search API (Memory op=search sources=[facts]); a backend that drops the selector must say so. 31× faster narrowing to facts on a 3,000-chunk scope (30ms vs 928ms). Every write carries provenance: tenant, session, run, agent, model, compaction generation. writeup →

Tenant users + delegated tokens (RFC BX + BY + CB)

v1.49.1 → v1.53.2

Users are a tenant's own object. Tenants create them, mint their tokens, set the access mode, revoke on the way out. Two access modes: isolated (scope-locked to own data; discovery tier-reads from token scopes) and member (full tenant HTTP plane; RFC CB opens the shared Library, Documents, and Memory to non-isolated tokens). Tenant is server-derived from the bearer, so POST /v1/_users carries no tenant field. A URL-free sign-in handoff (synchronous window.open in the click gesture, then origin-checked postMessage, then same-origin POST /ui/session for an HttpOnly cookie) keeps bearers out of every URL, browser history, and access log.

Documents become a knowledge store (RFC BS + BU)

v1.45.0 → v1.48.0

Chunk bodies embed on write. Prose verbatim, Mermaid extracts labels across 10 dialects, images use captions plus persisted vision descriptions (model call only for the description, not on every re-embed). Inline [[name]] becomes a graph edge; ![[target]] transcludes at export. backlinks / related / unlinked_mentions answer discovery in one call each. Per-chunk history / get_version / diff. Tags and per-document type / status as first-class query axes. JSON Canvas import/export round-trip (Obsidian-compatible).

Document viewer with images + diagrams + colors (RFC BN + BO + BP)

v1.29.0 → v1.31.0

The chunk viewer renders GFM tables and Mermaid diagrams inline; per-document color schemes tint chunk tiles by status and Path-tree rows by type; cross-reference edges get a badge, a clickable list, and a collapsible whole-document relationship graph. Images and Mermaid become first-class chunk types: paste a screenshot into the viewer to create an image chunk; the chunk editor shows a live Mermaid preview. Per-chunk buttons for insert-after, reorder, and delete. writeup →

Warm containers + cloneable agents + resident sub-agents (RFC BI P2 + BJ + BK)

v1.23.2 → v1.28.0

Three interlocking arcs. Sandbox hardening: durable per-principal workspaces so build caches survive container reap; attested run tagging via X-Loom-Root-Run; sandbox_touch + sandbox_close_run; static-MCP re-probe at run start so a sidecar coming up second recovers on the next run. Agent cloning: a Library Clone action derives a new agent whose tool list can widen (only over the operator bearer); POST /v1/sessions/{id}/replay copies a transcript into a new session bound to a different agent. Resident sub-agents: Agent open/send/close keeps a child alive across turns with a warm sandbox container. writeup →

Retention subsystem (RFC BM)

v1.32.0

A config-driven, cluster-gated sweeper ages out data across three families: retired def versions (leaf-first so lineage drains without orphans), aged chat sessions (pruned by session not by run, pinned sessions exempt), and fully-retired-agent memory (across three stores under two tenant-keying schemes). Every family defaults off. Export-then-delete: a JSON archive is written to LOOMCYCLE_RETENTION_EXPORT_DIR before the row leaves the database, so a failed export never deletes anything. writeup →

Ontology curation (RFC BZ + CA)

v1.52.0 → v1.53.0

The tenant ontology gains classes and subclasses: a child chunk is a subclass, and retrieval expands subtypes at query time (event finds incident and outage). A subclass inherits its parent's fields; a redeclaration wins. An agent may propose a type via propose_entity, never decide one: proposals land in place with an inert proposed status the reader ignores; only an operator can accept them. A bundled memory/ontologist agent (code-js, no LLM in the merge step) surveys facts and files suggestions with counts and example titles.

v1.15 → v1.23 wave: teams, history, safe code execution.

Safe code execution: toolbox image + sandbox sidecar (RFC BI P1)

v1.23.0 → v1.23.1

Two opt-in answers to the distroless-runtime-can't-run-code problem. Answer 1: the loomcycle-toolbox image is the SAME loomcycle binary on a Debian base preloaded with Python / Go / Rust / C++ / Node (+ git, gh, curl, jq, rsync, wget, unzip, sqlite3) at the same uid + mount paths. Drop-in image swap for single-tenant / trusted deployments. Answer 2: an isolated builder sidecar spawns each session in a dedicated ephemeral container with --network none, --read-only rootfs, tmpfs /work, --cap-drop=ALL, no-new-privileges, non-root, cpu/mem/pids capped, pluggable --runtime (runc → runsc → kata). loomcycle stays distroless and drives the sidecar over HTTP-MCP; loomcycle never runs a container engine itself. Six tools (sandbox_open / exec / write / read / close / list). One long-lived container per session for a compile → test → fix loop. Constant-time bearer auth. Principal-owned sessions. TTL GC + boot orphan-sweep via a loomcycle.managed=1 label. writeup →

Turn-scoped cancellation (RFC BH) + model_pattern (RFC BG P1)

v1.22.0

An Esc key that does the right thing. Before v1.22.0 the only stop primitive was cancel-the-run, which threw the session away. POST /v1/runs/{run_id}/cancel {reason?} now stops the current turn (the in-flight model generation + the tool calls it started) and parks the run at awaiting_input with the session, transcript, and context intact. The loop synthesizes cancelled by operator tool_results for any in-flight tool_use so history stays valid. Double-guard on ctx.Err() plus the ErrTurnCancelled cause. New turn_cancelled SSE frame. Interruption decline (a Question can be resolved with disposition: "declined"). Cross-replica routing by runs.replica_id. Every transport picked it up: gRPC CancelTurn + ResolveInterrupt, TS cancelTurn() / cancelInterrupt(), Python cancel_turn / resolve_interrupt. RFC BG P1 model_pattern also landed: model_pattern: "claude-haiku-*" auto-tracks a model family against the provider's live catalog. writeup →

Config-driven LLM providers (RFC BF)

v1.21.0

Adding an LLM provider used to be a code change. Providers are now a top-level providers: YAML block backed by a driver registry. Each entry declares a compiled-in driver (anthropic / openai / gemini / deepseek / ollama / mock / code-js), a base_url, an api_key_env (env-var name, resolved server-side, tenant-overridable via CredentialDef, never ${VAR}-interpolated), a max_concurrent, an options map, and a capabilities override. Add a self-hosted vLLM / llama.cpp / groq / together / second-Ollama with a few lines; driver: openai covers any OpenAI-compatible endpoint. Existing configs keep working byte-for-byte via an embedded default-providers layer. Per-provider max_concurrent caps in-flight runs (the local-GPU story); sub-agents gate on their resolved provider with a deadlock carve-out. writeup →

The History tool (RFC BE)

v1.20.0

Past chats become a first-class primitive. A "chat" is a session (session → runs → events); the History tool adds the human and organizational layer on top: title, description, tags, pinned, archived, summary. Ten ops on one tool: list (pinned-first, paginated, per-chat token/cost/run-count aggregates), get (metadata + full transcript, format:markdown renders it), search (case-insensitive title match), rename / annotate / pin / archive, recap (idempotent LLM summary stored on the session row, live-and-parked-chat-safe), resume (continuation handle), related (semantic similar-chats via the configured embedder, cosine ranking in Go, no pgvector). Owner scopes self / user / tenant / global, resolved server-side from run identity, never the wire; cross-scope reads fold to an opaque not-found; global is admin-only + fails closed. Migration 0057 (session metadata) + 0058 (session_embeddings). Supersedes and removes Context op=history. writeup →

Agent teams (RFC AP + RFC BD)

v1.17.0 → v1.19.2

A first-class state-machine primitive for multi-agent workflows. A TeamDef is a graph over your agents: states, transitions (success / pushback:<reason> / conditional:<expr>, bounded by max_iterations), handlers (agent / parallel+consolidator / consolidator / terminal). Content-addressed, tenant-scoped, versioned. Two drivers: a deterministic op=run walk engine (pure Go, right for scheduled + headless) and the bundled LLM team/orchestrator agent (reads the graph as its map, drives transitions, keeps a human in the loop via the Interruption tool). Web UI teams board: two-pane editor with graph JSON + live Mermaid diagram + dry-run render on unsaved edits. v1.19.0 filled the deferrals: parallel fan-out + consolidator execution (3 wait modes), durable Document-backed boards (board_chunk_id, resumable), interrupt-on-cap (cap overflow raises a human decision), gRPC + TS + Python parity, per-tenant Bash creds. writeup →

Client-executed tools (RFC BC)

v1.16.0 → v1.16.1

Tool-execution direction inverted. A client (browser, IDE, mobile app) opens a WebSocket to the runtime and registers its own tools; when the agent calls one, the runtime routes the invoke over the socket to the connected client, which runs the tool locally and returns the result. Four layers: a transport-agnostic registry (invoke↔result correlation, per-principal connection map, per-key connection cap, delegate-and-block Invoke), a bearer-authed GET /v1/client-tools WebSocket endpoint (bearer rides Sec-WebSocket-Protocol because browsers can't set Authorization on a WS handshake), client__-prefixed advertised tools with tools: allowlist globs, and a TypeScript connectClientTools helper that auto-reconnects. LoomBoard's Chrome side-panel extension is the first customer. v1.16.1 fixes the wire-safe name (client: → client__) because Anthropic, OpenAI, and Ollama all reject colons in tool names. writeup →

First-class search providers (RFC BB)

v1.15.0 → v1.15.1

WebSearch becomes a multi-provider fallback circuit. A new internal/search connector package with a Provider interface and five pure-HTTP drivers: Brave (own index), Serper (Google SERP scraper, cheapest at scale), Exa (own neural index, 20K/mo free), Tavily (RAG-purpose-built), SearXNG (self-hosted, aggregates 70+ engines, no API key). Two new config fields: search_providers: map with per-provider settings, search_priority: global fallback order. Per-AgentDef.search_providers overlay narrows an agent's cascade + participates in content_sha256. The fallback circuit walks the resolver's cascade, resolves each provider's key via ResolveKeyOrOperator (RFC AR + AX honored), and on error / empty / un-keyable falls over silently. Routing view (GET /v1/_routing) gains a search block. v1.15.1 adds an opt-in provenance footer via LOOMCYCLE_WEBSEARCH_PROVENANCE=1. writeup →

v1.1 → v1.14 wave: operator surface + hardening.

Tenant-operator Web UI (RFC AS)

v1.6.3 → v1.6.7

A substrate:tenant bearer authenticates in v1.0 but the Web UI showed empty pages or forms that 403'd. Five patch releases close every surface: Library + def-plane reads tenant-scoped, per-surface nav visibility, schedules + Path/Documents + audit log tenant-scoped, sub-agent sessions inherit parent's tenant, Context op=self reports full principal + server URL. Load-bearing shape: admin sees all + optional ?tenant= focus filter; a tenant operator is confined by construction; cross-tenant reads return empty (never 403). writeup →

Vision + thinking on the wire (RFC AT)

v1.7.0 → v1.8.2

Image input across all providers (Anthropic native blocks, OpenAI content-array, Gemini inlineData, Ollama images) and every transport. v1.7.1 closes the fallback-target gate: the initial vision check ran once at the resolved provider; a fallback swap to a text-only provider mid-run leaked the image_url and DeepSeek 400'd. Re-checks capability on the swap target now. v1.8.0 wires the effort hint to Ollama's think flag for local reasoning models. v1.8.2 is a two-line fix: the loop's event switch had no case for EventThinking, so every provider's reasoning trace was silently dropped at the loop for months. writeup →

Whole-repo hardening pass

v1.9.1 · 17 findings closed

A proper security review closed 17 findings across five categories. Tenant isolation: gRPC read + channel RPCs flow through grpcTenantScope (cross-tenant reads return NotFound, not PermissionDenied); A2A moves onto the operator-token substrate; mem9 blocks SSRF + API-key exfil via model-authored base_url; run cancel + interrupt-resolve tenant-gate on every transport. Secret-exposure at write-time for the tool-call transcript, audit-log Authorization headers, Context op=self pepper, and OpenAI Bearer at INFO on retry. Six driver fixes: Anthropic thinking-block replay on tool-use continuations, OpenAI max_completion_tokens, Ollama in-stream error frames, DeepSeek -chat downgrade, grep TOCTOU close, runstate send-on-closed race. And the MCP thin client transparently re-handshakes on 404 / -32001 on HTTP + stdio. writeup →

CredentialDef (RFC AR)

v1.11.0

Encrypted per-tenant secret store. Envelope AES-256-GCM under a per-tenant DEK derived via HKDF-SHA256 from a deployment KEK. GCM AAD binds ciphertext to (key_id, tenant, scope, scope_id, name). Consumers: $cred: substitution in HTTP MCP headers (per-request, scope precedence agent > user > tenant) and tenant + user provider-key override by env-var name (a CredentialDef named ANTHROPIC_API_KEY at tenant scope shadows the operator host key). Backends: inline default + Vault / AWS SM / GCP SM / 1Password stubs. writeup →

Cost attribution ledger (RFC AV)

v1.10.0

A per-call token_usage ledger records one row per LLM call with a credential_source label (operator / tenant / user), four token buckets, priced cost. Per-call granularity is exact across a mid-run provider fallback. GET /v1/_usage returns aggregated reports grouped by any combination of tenant / user / provider / model / source; the operator-vs-tenant split falls out of the group-by. A Web UI Usage page renders it with group-by chips, from/to window, admin tenant focus, and a summary strip (operator bill vs tenant-funded). Retention: rollup-and-prune sweeper into usage_archive + old-run archiver. gRPC + TS + Python adapter parity. writeup →

Per-scope token budgets (RFC AW)

v1.11.0

A budget is {tenant, scope, scope_id, window, soft, hard}. Scope is operator / tenant / user; window is calendar-month UTC. Most-restrictive wins. At admission, limits.Check refuses over-hard runs (429 on HTTP, ResourceExhausted on gRPC). In flight, recordCallUsage emits an EventLimit event on newly-crossed thresholds. It is a new event type carrying LimitInfo, riding the same channel as text / tool-use / thinking events on HTTP SSE + gRPC + MCP + TS + Python adapters + the Web UI's run terminal (amber banner soft, red hard, inline). K/M/G shorthand in the Limits editor. writeup →

Reusable React packages

v1.13.1 · RFC AY + AZ

The Web UI's components are now consumable by external hosts. @loomcycle/[email protected] is the reusable Agents/Skills/MCP Library React component with lineage + Claude Code import; the Web UI's own LibraryView is a thin wrapper (569 → 64 lines). @loomcycle/[email protected] is the reusable Path VFS + chunked-graph Document browser. Both peer @loomcycle/client; the Web UI dogfoods them; LoomBoard (loomcycle's chat app) embeds the Library in its left rail. External React hosts can now embed the same Library + Explorer surfaces without reimplementing.

On-demand Skills (RFC BA)

v1.14.0

SkillDefs are no longer bundled into the system prompt at boot. A new Skill tool with two ops: list enumerates the agent-visible catalog (bundles + inline defs + tenant SkillDefs) filtered by the allowlist + optional /-glob pattern; invoke loads and runs a permitted skill. The agent's skills: field becomes a pattern allowlist (globs like doc/*). Empty = allow-all with the Skill tool auto-added; -* = deny (no Skill tool wired). Breaking: skill_def_scopes removed; authoring is now gated by skills: itself. Bundled document-agent skills group under doc/* as of v1.14.1.

Path VFS (RFC AL) + Chunked-graph Documents (RFC AK)

v1.4.0

Unix-like VFS over Memory + Volumes + Documents, using Linux inode/dirent semantics: resources keep permanent ids, a dirents row maps (parent_path, name) → resource. Six ops on the new Path tool. Documents are chunked-graph: each chunk is a first-class unit with UUID + hierarchy + type + fields + edges + Markdown body + optimistic revision. Content in Memory, structure in SQL Memory (four tables). 13 ops on the Document tool. A Document at /docs/foo lists as a directory AND resolves as one resource (macOS bundle semantics). writeup →

Filesystem Volumes (RFC AH) + Bashbox (RFC AJ)

v1.1.0 + v1.3.0

Per-agent ro/rw filesystem roots as a substrate primitive. Static from yaml plus runtime-mutable VolumeDef (tenant-scoped, runtime-derived path; never caller-supplied). Sub-agent volume set ⊆ parent's; ephemeral=true auto-purges when the top-level run completes. v1.3.0 adds Bashbox (RFC AJ), an in-process shell tool backed by pure-Go gbash. No os/exec, no /bin/sh. Honors ro volumes via an in-RAM write overlay. Same input schema as Bash; opt-in via LOOMCYCLE_BASHBOX_ENABLED=1. Bashbox writeup →

v0.12 → v1.0 wave: the substrate.

Multi-replica HA

v0.12.x → v1.0

Postgres LISTEN/NOTIFY backplane (no Redis dep in v1.0). Cross-replica cancel + cluster-wide pause/resume + bus fanout + advisory-locked singleton sweepers. SQLite refuses cluster mode at boot (clear error, not silent fail). The runtime grows from one replica on a cheap VPS to many machines without changing shape. writeup →

Production stability

continuous

Two months of continuous production operation at JobEmber.ai under real user load with multi-replica HA on Postgres LISTEN/NOTIFY. Every replica can run the scheduler (DB-claimed slots so two replicas never fire the same job twice). Children of a parent agent survive pause, restart, and replica move. The substrate does not drift under sustained load; the deployment stays live across releases.

Multi-tenant authorization (OperatorTokenDef)

v0.17.0 · RFC L

Seventh substrate primitive. Per-principal lct_… bearer tokens bound to an authoritative {tenant_id, subject, scopes} resolved from the token, never from the wire. Per-route + per-RPC scope enforcement (deny-by-default-to-admin on gRPC), tenant-scoped read boundary, role-aware Web UI with super-admin tenant-focus switcher. Adversarial-QA pass found and closed one CRITICAL gRPC bypass plus three HIGH cross-tenant isolation breaks before tag. writeup →

OTel everywhere + 3 profiles

v0.10.0 + v0.10.x

Distributed traces across loop + providers + tools + MCP. Three drop-in profiles ship in the repo: self-hosted Grafana / Tempo / Prometheus / Loki, Honeycomb, Datadog APM. Plus a bearer-authed /metrics Prometheus endpoint live-read from runtime counters. Pick your backend; no vendor SDK in the loop.

Pause / Resume / Snapshot - even mid-run, even across instances

v0.8.17 → v0.30.0

Runtime-wide quiesce + cross-version-portable JSON snapshot. Both phases shipped: cooperative pause parks in-flight sub-runs at iteration boundaries; cross-instance resume re-dispatches paused runs on a fresh box. A paused run can be wiped and restored on a fresh loomcycle instance and finish autonomously. This substrate work later expanded (v1.101) into whole-deployment snapshots that carry users, budgets, schedules, webhooks, peers, document sources, volumes, the Path tree and the consolidation queue: see the snapshots writeup.

A2A on both sides

v0.13.x · RFC G

loomcycle publishes an AgentCard at /.well-known/agent-card.json; three protocol bindings (REST, JSON-RPC, gRPC); signed cards over RFC 8785 JCS canonicalization; multi-tenant routing in three modes; INPUT_REQUIRED↔Interruption bridge. Reachable from Microsoft Agent Framework, Google ADK, LangGraph. Outbound: synthetic a2a__<peer>__<skill> tools. Built against a2a-go v2.3.1. writeup →

Signed input webhooks (WebhookDef)

v0.14.1 · RFC H

External systems sign + POST events; loomcycle either spawns a run (delivery: spawn) or publishes to a channel to wake an agent already waiting (delivery: channel). HMAC-SHA256 over the raw body, three envelopes auto-detected (Stripe, GitHub, bare-hex Linear). Verify-before-parse trust boundary, two-layer idempotency (in-memory + durable runs.idempotency_key), never silently degrade. writeup →

Scheduled autonomous runs (ScheduleDef)

v0.21 · RFC E

Cron in yaml - per-user-tier templates that fork at signup, or operator-owned standalone schedules; sweeper fires real RunInputs; on_complete hooks deliver via channel / memory / MCP. Compound stress test pushed it to 100,000 fires, surfaced a double-fire race at 30,000, closed with a sync.Map in-flight tracker. writeup →

Per-run credentials (RFC F)

v0.20.x

One agentic run, multiple per-user-authorized MCP servers, zero secrets visible to the agent. user_credentials map on the wire across all transports; ${run.credentials.<name>} substitution at the HTTP boundary inside Client.do(); values never reach transcripts, snapshots, or OTEL spans. writeup →

Agent ensembles (Channel.await + Context.time + max_fires)

v0.25.0 · RFC S

Three primitives that make ensemble-shaped pipelines first-class. Channel.await {channels, mode: any/all/at_least, n, wait_ms} is the missing fan-in combinator. Its symmetric twin Channel.broadcast publishes one payload to N channels in one call. Context op=time gives every agent a wall-clock. Schedule max_fires retires a def after N successful fires. These substrate primitives are the floor the TeamDef one-file state machine and the loomboard canvas compose on top of today.

Code-as-agent (provider: code-js)

v0.16.0 · RFC J - shipped & tested

Operator JavaScript via goja as a first-class agent - no host filesystem needed, no LLM call. Same loop, OTEL, scheduler / webhook / A2A reachability, sub-agent composition. Stateless replay execution: each Provider.Call builds a fresh runtime, fast-forwards through the transcript, stops at the first un-recorded tool call. Resumable across restart and replica for free. Bundled examples ship at internal/examples/code-agents/. writeup →

Memory backends + memory layer

v0.15 → v0.16 · RFC I + RFC K

MemoryBackendDef binds AgentDefs to backends; the in-process sqlite-vec + Postgres backend is canonical, external backends plug in. MemoryLayer sits alongside the flat Backend for LLM-extract products (mem0, Mem9). Capability probe routes ops; unsupported call fails closed with typed ErrCapabilityUnsupported. Native ranker + search-time dedup. writeup →

Context plugin chain + redact

contextplugin · v1.0

A run-loop plugin chain that runs every iteration between the agent and the outbound LLM. First built-in is redact - scrubs secrets before the model sees them. The model never receives the literal token in the first place. Plugins live in the loop, not the agent - operator opts in, agents don't have to know. Context compressor plugin is next. writeup →

Interactive Web UI terminal

v0.26 → v0.29

Steer agents mid-run, Claude-Code-style from the browser. Mid-run steering via POST /v1/runs/{run_id}/input + a per-run buffered registry, drained at iteration boundaries (never between tool_use and tool_results). Parked end_turn instead of terminating. Inline interruption answers. View-switch survival via context.WithoutCancel + persistent event tailing. writeup →

Context compaction (manual / auto / self)

v0.32.0

Long-running agentic sessions stay in context budget. Three coordinated triggers around one shared summarizer. Manual: a Compact button. Auto: per-iteration threshold (autocompact_at_pct). Self: an agent can call Context op=compact itself. Pinned task + summary + last-N form, with CompactionSplit snapping the cut to a clean user-turn boundary so a tool_use/tool_results pair is never split. A context-compressor plugin is the next built-in in the contextplugin chain - same logic, operator-customizable surface. writeup →

External MCP fan-out (spawn_runs)

v0.33.0 · RFC Y

spawn_runs(mode: "join", spawns: […]) dispatches N agent runs concurrently from one MCP call and returns an index-aligned envelope when they settle. This substrate call is what the TeamDef one-file state machine compose on top of; a poll-mode sub-agent spawn extends the shape so a parent can keep working and pick up the answer later.

loomcycle import claude-code

v0.31.x · RFC C2

Lift .claude/agents/*.md + .claude/skills/*/SKILL.md into the loomcycle substrate without rewriting. AgentDef + SkillDef synthesized from YAML frontmatter + markdown bodies; tools mapped to allowed_tools; skills bundled into the system prompt at config-load. One command - and your existing Claude Code agents run on loomcycle. Pairs with the claude-code-plugin-loomcycle companion repo for the round-trip. writeup →

Adapters + reusable React packages

TS + Python + Library + Explorer

pip install loomcycle (Python adapter) + @loomcycle/client (TS adapter, v1.13.0). Same surface across HTTP / gRPC / MCP wire shapes. Since v1.13.1, two reusable React components ship as separate packages: @loomcycle/library (Agents / Skills / MCP CRUD + lineage + Claude Code import; RFC AY) and @loomcycle/explorer (Path VFS + chunked-graph Documents; RFC AZ). Both peer @loomcycle/client; the Web UI dogfoods them; LoomBoard embeds the Library in its left rail. External React hosts can now embed the same surfaces without reimplementing.

Anthropic MAX OAuth (dev)

v0.11.10 → v0.11.11

Dev workflow can run against your Claude MAX subscription instead of pay-per-token API. Three subcommands: loomcycle anthropic login / status / logout. Reverse-engineered integration with explicit no-warranty terms - full disclaimer on GitHub →

n8n community package

v1.0 → v3.9

@loomcycle/n8n-nodes-loomcycle on npm - source at github.com/denn-gubsky/n8n-nodes-loomcycle. Two editions. The Slim edition (this one, 20 nodes, zero deps, langchain-free) passes n8n's community-node scanner and runs on n8n Cloud. The Full edition (@loomcycle/n8n-nodes-loomcycle-full, 24 nodes) adds langchain-based AI-Agent Tool sub-nodes, SSE-push triggers, and a Run "wait for completion" op for self-hosted n8n. 16 dedicated action nodes covering Run / Memory / Channel / AgentDef / SkillDef / MCPServer / Schedule / Hook / Webhook / A2A Agent / A2A Server Card / Interruption / LLM / Memory Backend / Operator Token / Snapshot. 3 triggers (Run Completed / Channel Message / Interrupt Pending). 1 AI-Agent Chat Model sub-node routing through loomcycle's gateway. Drop loomcycle in front of an n8n workflow without writing custom HTTP nodes. writeup →

§ 10 - from a loop to a substrate

How loomcycle became what it is.

loomcycle started as the agentic-loop sidecar built for JobEmber.ai - an AI-driven job-search SaaS that needed a shared runtime for many parallel per-user agents. Each user's nightly batch touches three per-user MCP servers (jobs API, Slack, Telegram), runs on a cron schedule, and reaches them with per-user bearers the agent never sees. The shape we wanted: multi-tenancy, scheduled runs, signed webhook ingress, OTEL spans, pause-anytime - in one Go binary you could run on a small VPS, not bolted onto the application that consumes it.

Over the following months that sidecar grew into a complete agentic system. The substrate primitives: Memory with bi-temporal validity and subject-document identity, Documents with per-piece derived search units, TeamDef as a one-file state machine, the Decision tool for typed probabilities, Scheduler, Webhook, A2A, Evaluation, Context, Snapshot, HookDef, OperatorTokenDef: emerged from real JobEmber.ai pain. The trust model came from the day a reviewer agent inlined a Gitea token into a Bash command and the runtime had to catch it. Production stability is proven in production: two months of continuous production operation at JobEmber.ai under real user load with multi-replica HA.

JobEmber.ai is still a primary consumer. loomcycle is Apache-2.0, available to anyone with the same shape of problem: and integrates cleanly when Claude Code is your operator and conversation surface. The runtime is around 80 MB resident; one Go binary that ships with the development toolchain, a headless Chromium, and the memory, documents, teams, canvas, Decision tool, and snapshot machinery all included.

Substrate primitives emerge from production pain, not whiteboards. JobEmber.ai's first; everyone else's next.

Read the architecture →
§ 11 - quickstart

Three install paths. Three commands each. One curl. One Web UI link.

Self-host on a single replica in under three minutes. Pick the install path that matches your environment - Homebrew, Docker, or from source - then drop into the same curl /healthz + Web UI follow-ups.

~/loomcycle · zsh - Homebrew (macOS / Linux)
// install & configure
$ brew install denn-gubsky/loomcycle/loomcycle $ loomcycle init # generates ~/.config/loomcycle/loomcycle.yaml + .env.local $ loomcycle doctor # checks provider keys + config sanity $ loomcycle # serves on 127.0.0.1:8787
~/loomcycle · zsh - Docker (cluster / CI / Kubernetes)
// pull & run; bring your own loomcycle.yaml
$ export LOOMCYCLE_AUTH_TOKEN=$(openssl rand -hex 32) $ docker run --rm -p 8787:8787 \ -e LOOMCYCLE_AUTH_TOKEN \ -e ANTHROPIC_API_KEY \ -v $PWD/loomcycle.yaml:/etc/loomcycle/loomcycle.yaml:ro \ ghcr.io/denn-gubsky/loomcycle:latest
~/loomcycle · zsh - From source (contributors / hackers)
// build & configure
$ git clone https://github.com/denn-gubsky/loomcycle && cd loomcycle $ make build-all $ cp .env.example .env.local # set ANTHROPIC_API_KEY / etc. $ ./bin/loomcycle --config ~/.config/loomcycle/loomcycle.yaml
// any install path - same follow-ups
// health check
$ curl http://127.0.0.1:8787/healthz {"ok":true}
// first real call
$ curl -N http://127.0.0.1:8787/v1/runs \ -H "Authorization: Bearer $LOOMCYCLE_AUTH_TOKEN" ...
// open the Web UI
$ open "http://127.0.0.1:8787/ui?token=$LOOMCYCLE_AUTH_TOKEN"
// optional: dev workflow on MAX subscription (reverse-engineered - see docs/PROVIDERS.md)
$ loomcycle anthropic login # browser OAuth flow $ loomcycle anthropic status # check current session $ loomcycle anthropic logout # revoke when done

Already using Claude Code? Lift your existing .claude/agents/*.md and .claude/skills/*/SKILL.md into the loomcycle substrate with one command - and your agents run on loomcycle without rewriting. The reverse direction is the claude-code-plugin-loomcycle companion repo (Claude Code marketplace plugin, drives loomcycle via its MCP server).

~/your-claude-code-project · zsh
// inventory what's in .claude/
$ ls .claude/ agents/ skills/ commands/
// import - AgentDef + SkillDef synthesized; skills bundled into system prompt at config-load
$ loomcycle import claude-code \ --from=.claude \ --write \ --skills-dest=$PWD/skills imported: 4 agents, 7 skills → loomcycle.yaml updated
// from one Claude Code session: fan 10 reviewers in one MCP call (RFC Y, v0.33.0)
$ # inside Claude Code, call the loomcycle MCP server: $ # spawn_runs(mode: "join", spawns: [{agent: "code-reviewer", prompt: "..."}, ...]) $ # - 10 runs in parallel, AND-barrier returns when all settle
§ 12 - roadmap

v1.0 ships the substrate. v1.x ships distribution.

No "Q3 2026" calendar guessing - versions and triggers. v1.0 is feature-complete: the substrate primitives, the production-grade ops, the trust model, the Claude Code delegation surface. v1.x is distribution polish + enterprise edition for procurement-shaped buyers. Anything further sits in research mode until a trigger lands.

v1.0● this release

The substrate is done. Production-grade ops shipped. Claude Code delegation surface concrete.

Substrate: Memory, Channel, AgentDef, TeamDef, Decision, Scheduler, Webhook, A2A, Evaluation, Context, OperatorTokenDef (multi-tenant authz), MemoryBackendDef, HookDef, Snapshot, code-as-agent (provider: code-js): content-addressed, forkable, lineage-tracked, all reachable from HTTP / gRPC / MCP / TypeScript adapter / Python adapter on PyPi. Production-grade ops: multi-replica HA on Postgres LISTEN/NOTIFY; three drop-in OTEL profiles (Grafana/Tempo/Prom/Loki, Honeycomb, Datadog APM); pause/snapshot/resume mid-run and across instances; whole-deployment snapshots (users, budgets, schedules, webhooks, peers, document sources, volumes, the Path tree, the consolidation queue). Two months of continuous production operation at JobEmber.ai under real user load. Trust: two-layer secret discipline: a redact plugin in the run-loop scrubs secrets before the model sees them, plus value-based redaction at rest. UNIX operator/caller separation, per-run credentials never reach the agent's view of its credentials map. Claude Code surface: loomcycle import claude-code lifts .claude/agents/*.md + .claude/skills/*/SKILL.md into the substrate; one MCP call starts a Team walk whose states fan out across sub-agents in poll mode; children survive pause, restart, replica move. Interactive UX: Web UI terminal with mid-run steering, parked end_turn, cross-replica steer; three context-retention modes (append, recap, stateful) with a Recall tool over evicted spans and an opt-in harvest to durable memory. Adapters: @loomcycle/client on npm (ESM + CJS), pip install loomcycle on PyPi. snapshots writeup → · Teams writeup →

v1.1 → v1.14● shipped

Operator surface + hardening (May 2026 → early July 2026)

Substrate surface: Filesystem Volumes (RFC AH, v1.1.0), Bashbox in-process shell (RFC AJ, v1.3.0), Path VFS + chunked-graph Documents (RFC AL + AK, v1.4.0), per-principal MCP transport + declared static principals (RFC AG + AO + AN, v1.5.0). Tenant-operator Web UI (RFC AS, v1.6.3-v1.6.7) so a substrate:tenant bearer sees only what they can act on. TrueNAS deployment from possible to supported (v1.6.2-v1.6.7). Model reach: vision + thinking on the wire for every provider on every transport (RFC AT, v1.7-v1.8). Trust: a whole-repo security review closed 17 findings under v1.9.1 (tenant isolation across four transports, secret exposure closed at write-time, six driver-correctness bugs, MCP thin-client self-recovery). providers:operator-key scope (RFC AX, v1.12.0) confines a restricted tenant to providers it can key itself. Governance: per-call cost attribution ledger (RFC AV, v1.10.0), encrypted per-tenant credentials (RFC AR, v1.11.0), per-scope token budgets with soft-warn + hard-cap and a new EventLimit on every transport (RFC AW, v1.11.0). Reusable components: @loomcycle/library + @loomcycle/explorer (RFC AY + AZ, v1.13.1) extract the Web UI's Library and Path + Document browser as consumable React packages. On-demand Skills with pattern allowlists (RFC BA, v1.14.0). first digest → · second digest →

v1.15 → v1.23● shipped

Teams, history, safe code execution (early July 2026 → mid July 2026)

Search providers first-class (RFC BB, v1.15.0-v1.15.1). WebSearch becomes a multi-provider fallback circuit across Brave / Serper / Exa / Tavily / SearXNG. Per-AgentDef.search_providers overlay in content_sha256. Opt-in provenance footer. Client-executed tools (RFC BC, v1.16.0-v1.16.1). A browser, IDE, or mobile app opens a WebSocket, registers its own tools, and executes them when the agent calls them. LoomBoard's Chrome side-panel extension is the first customer. Agent teams (RFC AP + RFC BD, v1.17.0-v1.19.2). The multi-agent workflow primitive shipped: TeamDef state-machine graphs with parallel handlers + consolidator, pushback loops, iteration caps, durable Document-backed boards, interrupt-on-cap. Deterministic op=run walker plus the LLM team/orchestrator. Two starter teams in team-examples. History tool (RFC BE, v1.20.0). Past chats as a first-class primitive. Ten ops: list / search / get / rename / annotate / pin / archive / recap / resume / related. Owner scopes resolved server-side, cross-scope reads fold to opaque not-found. Migrations 0057 + 0058. Config-driven providers (RFC BF, v1.21.0). Providers become a top-level YAML block with pluggable drivers. Add self-hosted vLLM / llama.cpp / Groq / Together / second-Ollama with a few lines. Per-provider max_concurrent for the local-GPU story. Deadlock-aware sub-agent gating. Backward-compatible via an embedded default-providers layer. Turn-scoped cancellation (RFC BH, v1.22.0). An Esc key that stops the current turn without ending the session. Synthesized tool_results keep history valid. New turn_cancelled SSE frame. Interruption decline. Cross-replica routing. Model-pattern resolution (RFC BG P1) auto-tracks a model family. Safe code execution (RFC BI P1, v1.23.0-v1.23.1). A loomcycle-toolbox dev-toolchain image (drop-in for trusted deployments) plus an isolated builder sidecar (hardened per-session containers, pluggable runc → runsc → kata, driven over HTTP-MCP; loomcycle never runs a container engine).

v1.24 → v1.53● shipped

Memory, documents, users, cloud (mid July → mid August 2026)

Agentic memory (RFC BL + BS + BU + BV + BW, v1.33.0-v1.49.0). Facts, notes, and documents in one per-scope memory. Background consolidator turns finished transcripts into distilled facts with provenance and bi-temporal validity. Hybrid vector + full-text retrieval with Reciprocal Rank Fusion. Honest source selectors on the search API. Documents become searchable (prose bodies, Mermaid across 10 dialects, images via persisted vision descriptions). Human-facing operator console (@loomcycle/memory-view). GDPR-shaped subject erasure on every transport. Tenant users + delegated tokens (RFC BX + BY + CB, v1.49.1-v1.53.2). Users are a tenant's own object. Two access modes: isolated (scope-locked to own data) and member (full tenant HTTP plane). URL-free sign-in handoff via origin-checked postMessage + same-origin POST /ui/session. TypeScript adapter methods for user + token CRUD. loomcycle.cloud public deployment (Aug 2026). Three subdomains: loomcycle.cloud (landing + token vault), app.loomcycle.cloud (the runtime), board.loomcycle.cloud (hosted loomboard SPA). Same Docker image self-hosters run. Document viewer + editing (RFC BN + BO + BP, v1.29.0-v1.31.0). Chunks render GFM tables + Mermaid; per-document color schemes; cross-reference graph; images and Mermaid as first-class chunk types with paste-a-screenshot authoring; per-chunk +text / ↑↓ / delete controls. Retention subsystem (RFC BM, v1.32.0). Config-driven, cluster-gated sweeper across three families (retired def versions, aged chats, dead-agent memory). Export-then-delete. Every family defaults off. Ontology curation (RFC BZ + CA, v1.52.0-v1.53.0). Tenant ontology gains classes and subclasses; retrieval expands subtypes at query time; an agent may propose types, only an operator can accept. milestone writeup → · memory writeup →

v1.x continuesnext

What's queued for the coming weeks

RFC CC: source-span provenance on every fact. PR #1000 opened on 2026-08-14 with Phase 1: a fact records the source span it came from, derived deterministically from the transcript rather than model-supplied (keeps the extractor prompt byte-identical). Phase 2 adds a deterministic gate that checks structural properties of the derived span before a fact is written; Phase 4 backfills existing facts by re-running the same span matcher against their source transcripts. Programmatic tenant onboarding. Today a tenant is created by an admin bearer. Self-serve tenant signup (email verification, tenant naming, first-user creation, first-token minting) is the natural next step for a public deployment. MCP + gRPC parity for user administration. User CRUD and token minting exist on HTTP and TypeScript; MCP and gRPC twins follow. RFC BI P2/P3: cryptographically-attested per-tenant identity for the sandbox. Today the builder sidecar authenticates on a single shared bearer. P2 verifies caller tenant identity cryptographically. P3 makes the Kata microVM tier first-class. External CredentialDef backends. Vault / AWS Secrets Manager / GCP Secret Manager / 1Password Connect. Interface stubs shipped in v1.11.0; implementations land when a tenant asks. TrueNAS Scale catalog-app manifest. Packages the compose into a one-click install. External code contributions open here.

post-v1.xresearch

Standing research threads

Redis backplane as an alternative to Postgres LISTEN/NOTIFY. The coord.Backplane interface is already in place; Postgres impl ships in v1.0, Redis impl waits for a trigger. Cross-organization federation. Agents subscribing to a collaborator's channels across organizational lines. Research thread only, promoted when a concrete use case lands. Context-compressor plugin. A second built-in plugin in the same contextplugin chain that ships redact in v1.0. Operator-configurable LLMLingua-style content compression at the per-turn boundary; transform a copy of the outbound request, leave the canonical history and persisted transcript untouched. Same seam auto-compaction already uses. Feature triggers. JobEmber.ai's continued production pain plus LoomBoard's chat-app adoption pattern are the primary sources of v1.x feature triggers; if they surface something the substrate doesn't carry, that's what gets built next.

RFCs Z (context-compress), AA (SQL Memory), K (mem0 / MemoryLayer) all shipped inside v1.0-v1.5. They moved from "research" to "landed" and the section above reflects the new pipeline.

past● shipped

Full per-version log

Every release from v0.8 through v1.0 is documented in REVISIONS.md on GitHub. The §09 v1.0 changelog highlights grid above surfaces the load-bearing items; the per-version log carries the long tail.

companion● shipped

Companion projects - separate repos in the loomcycle org

n8n-nodes-loomcycle - the n8n community node package (npm: @loomcycle/n8n-nodes-loomcycle, MIT). Ships in two editions: Slim (20 nodes, zero deps, langchain-free; passes n8n's community-node scanner, runs on n8n Cloud) and Full (@loomcycle/n8n-nodes-loomcycle-full, 24 nodes; adds langchain-based AI-Agent Tool sub-nodes, SSE-push triggers, and a Run "wait for completion" op for self-hosted n8n). Sixteen dedicated action nodes cover Run / Memory / Channel / AgentDef / SkillDef / MCPServer / Schedule / Hook / Webhook / A2A Agent / A2A Server Card / Interruption / LLM / Memory Backend / Operator Token / Snapshot. Three triggers (Run Completed, Channel Message, Interrupt Pending). One AI-Agent Chat Model sub-node routes through loomcycle's gateway. Drop loomcycle in front of an n8n workflow without writing custom HTTP nodes. writeup →

claude-code-plugin-loomcycle - Claude Code marketplace plugin (Apache-2.0). Drop-in install with slash commands, skills, and opt-in hooks; uses loomcycle's MCP server with no loomcycle-side code changes. Pairs with loomcycle import claude-code for the round-trip: your .claude/ artifacts move into loomcycle's substrate; the plugin gives Claude Code a one-keystroke surface to drive them. writeup →

The runtime began where every runtime begins: a smaller plan that outgrew its scope. What ships today is the plan rebuilt from the production pain of its first user. One Go binary. It fits on a laptop, and it runs the thing a tenant is on tonight.

That is the kind of substrate we think the next wave of agent work deserves. Not a framework over somebody else's cloud. An agentic kernel on your own side of the perimeter.

§ 13 - talk to us

Building on loomcycle, or thinking about it?

We'd like to hear what you're building. Production users inform v1.0 design, and integration-shape ideas are the things that get RFCs written. No sales process, no NDA, no waitlist - just a real conversation about whether loomcycle fits your shape.

[email protected]