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

The agentic runtime, in a sidecar.

A self-contained Go binary (~50 MB) that owns the agent loop alongside your application. Memory, channels, scheduler, webhooks, MCP on both sides, A2A on both sides, multi-replica HA on Postgres LISTEN/NOTIFY, OpenTelemetry. Plus a Claude Code delegation surface (spawn_runs MCP fan-out, loomcycle import claude-code): multi-agent work runs in loomcycle, Claude Code stays your operator and conversation surface.

Apache-2.0 · v1.5.0 shipped 2026-07-18 · Per-principal MCP transport + config-declared static (tenant, subject) logins — one bearer authenticates both the Web UI and an MCP thin client (RFC AG + AO + AN) · 8-hour stability soak: 1.27M circuits, 3.8M agent runs, 100% completion across 468 waves, zero leaks - writeup. Seven experiments, every one a self-contained reproducer in loomcycle/examples.

§ 03 - why this exists

Eight things that are uncommon, together.

Most agent platforms pick one of three shapes - a library you embed, a hosted service you rent, or a gateway that doesn't run the loop. loomcycle is something different: a self-hostable runtime that owns the loop, speaks every wire surface (HTTP, gRPC, MCP, TS adapter, Python adapter), and stays out of your application's process.

01

Self-contained Go binary, ~50 MB.

No Node, no Python, no JVM in the model path. Drop it in alongside your application and forget it's there.

02

The runtime runs outside your app process.

Sidecar wire surfaces: HTTP, gRPC, MCP, TypeScript adapter (@loomcycle/client), Python adapter (loomcycle on PyPi). Your application stays in whatever language you wrote it in.

03

MCP client and MCP server, simultaneously.

Agents you host are reachable from outside as MCP tools; tools outside are mountable inside as MCP servers. Most products are one side of the protocol; loomcycle is both.

04

External MCP fan-out - one call, N concurrent runs.

spawn_runs(mode: "join", spawns: […]) dispatches N agent runs concurrently from one MCP call and returns an index-aligned envelope when they settle. The shape exp7 used to drive 10 reviewers from one Claude Code call. exp7 writeup →

05

Security by design - secrets never touch the LLM.

Three guarantees the substrate makes: (a) Per-run credentials are substituted at the MCP transport boundary - agents see credential names, never values; the LLM's view of its credentials map is empty of resolved tokens. (b) The redact run-loop plugin scrubs operator-declared secrets from every outbound LLM request - Tier-A: operator declares env vars whose values get masked exactly (customizable - add more env vars whenever a new secret class appears); 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. (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. writeup →

06

Built for long sessions - auto-compaction + pluggable run-loop transforms.

Context auto-compaction (v0.32.0) keeps long-running agentic sessions in budget - three coordinated triggers around one shared summarizer: manual (operator clicks Compact), auto (per-iteration threshold crosses autocompact_at_pct), self (agent calls Context op=compact itself). Keeps the pinned task + summary + last-N; snaps the cut to a clean user-turn boundary so a tool_use/tool_results pair is never split. The contextplugin chain runs every iteration between agent and LLM - redact (above) is the first built-in; a context-compressor plugin is the next built-in coming, moving compaction logic into the same operator-customizable surface. Plugins live in the loop, not the agent. writeup →

07

Code-as-agent AND LLM-agent in the same loop.

provider: code-js runs operator-authored JavaScript via goja - no host filesystem needed. Same AgentDef shape, same scoping rules, same sub-agent composition. Code agents can spawn LLM agents and vice versa. writeup →

08

Production shape - multi-replica HA, pause/snapshot anytime, 8-hour soak.

Postgres LISTEN/NOTIFY backplane. Pause/snapshot anytime, even mid-run; restore on a different instance - exp6.5 wipes a DB and the paused breeder finishes its work autonomously on the fresh box. 8-hour stability soak: 1.27M circuits, 3.8M agent runs, 100% completion across 468 waves, zero leaks. writeup →

Sidecar - for engineers building agentic SaaS without adopting a framework.

You're shipping a product whose agents need to run at scale, in parallel, under multi-tenant constraints, with audit and observability - and you don't want to make your application become an agent framework to do it. loomcycle is the runtime your services talk to over HTTP / gRPC / MCP; your application stays in whatever language you wrote it.

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's logged in. They need to react to a GitHub PR opening, a Stripe invoice failing, a Linear issue moving to "In Review." 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's the surrounding substrate's problem - and loomcycle ships that substrate.

The substrate primitives - Memory, Channel, AgentDef, Scheduler, Webhook, A2A, Evaluation, Context - emerged from real consumer pain. JobEmber.ai (an AI-driven job-search SaaS) is loomcycle's first consumer: 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 a long night under multi-replica HA. The 8-hour stability soak that gates this release came from asking that production-load question. It survived: 1.27M circuits, 3.8M agent runs, 100% completion, zero leaks.

What you give up: a UI canvas. What you keep: your services in whatever language they were in, plus a runtime that knows how to be agentic for them. Multi-tenant authorization writeup → · 3000 agents in one stress test → · 8-hour soak writeup →

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 fans 10 reviewer agents across a repo; one more call merges their findings; Claude Code never opens a file. exp7 proved the shape end-to-end on loomcycle's own codebase.

The shape: a fresh Claude Code session clones a target repo, synthesizes a reviewer agent + skill from its own .claude/ artifacts, runs loomcycle import claude-code --from=.claude --write --skills-dest=$PWD/skills to lift the AgentDef + SkillDef into loomcycle's substrate, then makes one MCP call: spawn_runs(N=10, mode=join, spawns=[…]). 10 reviewers run concurrently inside loomcycle, each writing findings to a shared Memory ledger. One more spawn_run wakes a consolidator that merges the ledger. Claude Code reads the consolidated report. Its own context never carries the 86 files of the target repo. exp7 writeup →

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, local Mistral, or any other cheaper provider the structured-loop work doesn't need Claude for. Same MCP wire surface; the model swap is one AgentDef field. exp7's 10 reviewers ran on Claude OAuth here, but the topology is provider-neutral - and a code-as-agent (provider: code-js) costs zero LLM tokens at all. The $80 I burned on Claude Code →

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 in v1.0). 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.

The boring-but-load-bearing v1.0 message. Whatever stack you're integrating, the trust boundaries hold: A2A on both sides (RFC G) - 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 deployments call loomcycle agents as remote skills, and loomcycle agents call external A2A peers as synthetic a2a__<peer>__<skill> tools. Signed input webhooks (RFC H) - HMAC-SHA256 over the raw body, two-layer idempotency (in-memory + durable), strict JSONPath payload projection, never silently degrades. Per-run credentials (RFC F) - the substrate substitutes resolved secrets at the MCP transport boundary, not in the agent's view of its credentials map. 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 (no Redis dep in v1.0); 8-hour stability soak: 1.27M circuits, 3.8M agent runs, 100% completion, zero leaks. A2A writeup → · Webhooks writeup → · Per-run credentials 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.

Not a no-code builder. If you want to drag boxes onto a canvas and connect them with arrows, you don't want loomcycle - you want a visual workflow tool. loomcycle plugs into one of those tools as a node provider (the community package is shipped), but loomcycle itself is not the canvas.

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. exp7 proves the shape: one MCP call, 10 reviewer agents, one consolidator, Claude Code never opened a repo file. writeup →

§ 05 - primitives

The seven primitives that make agentic systems learnable.

Memory and Channel are the substrate — Memory now in three facets (key-value, vector, SQL). AgentDef and Evaluation are the self-evolution loop. Context is the introspection primitive that closes it. Scheduler and Webhook are the autonomous triggers that fire agents without an operator watching. Volume is the per-agent filesystem boundary so two ensembles in one runtime each get their own workspace.

Memory

shipped v0.8.0 · SQL facet v1.2.0 · RFC AA

Persistent state per agent or per user. Three facets: key-value (atomic incr, TTL, cross-run continuity), vector (semantic search via sqlite-vec / pgvector with provider-agnostic embedders), and now SQL (RFC AA, v1.2.0 — a per-scope SQL database the runtime hosts; sqlite + postgres tiers, default-deny sql_scopes gate, explicit + nested transactions, vector columns, snapshot integration, durable + ephemeral scopes, read-only shared schemas).

// SQL facet (RFC AA, v1.2.0)
{"tool":"memory",
 "input":{"op":"sql_exec",
         "scope":"user",
         "sql":"CREATE TABLE primes (n INTEGER PRIMARY KEY)"}}

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 · RFC AH

Per-agent ro/rw filesystem roots. {name, path, mode}. 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. Ephemeral run-scoped: ephemeral=true auto-purges when the top-level run completes (clone repo, work, vanish). Sandbox-by-default replaces the global jail. v1.3.0: the new Bashbox tool (RFC AJ, opt-in via LOOMCYCLE_BASHBOX_ENABLED=1) honors ro volumes via an in-RAM write overlay, closing the asymmetry rule #7 left open (the existing Bash tool still refuses ro). v1.4.0: VolumeDef.create mount_at: registers a volume_mount dirent in the new 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 · RFC AK

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. Content/structure split: chunk content lives in Memory keyed by UUID, chunk structure lives in SQL Memory across four tables (documents / chunks / chunk_edges / chunk_types). 13 ops: document lifecycle, chunk CRUD, edges (link_chunks / unlink_chunks), query (structured + under_path Path-join + raw sql: escape hatch through the SQL Memory validator), type defs. Atomic deletes in one SQL Memory transaction; bidirectional edge cleanup; move_chunk cycle guard. A Document at /docs/foo lists as a directory in Path AND resolves as one resource (macOS bundle semantics). On every transport. v1.5.0: per-principal /v1/_mcp dispatch (RFC AG) + declared static (tenant, subject) principals (RFC AO) close the cross-transport identity gap, so an agent's MCP-created documents and the Web UI's /ui/paths share the same per-scope SQLite file by construction.

// query the chunk graph
{"tool":"document",
 "input":{"op":"query_chunks",
         "under_path":"/docs/launches/",
         "type":"publication",
         "status":"draft"}}
§ 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 - v1.0 changelog highlights

What landed in the v0.12 → v1.0 wave.

Twenty-plus releases. Every major v1.0 commitment shipped - 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 shape exp7 used), and an 8-hour stability soak with zero leaks. What's left for v1.x is distribution polish (Helm chart, enterprise edition) - the substrate is done.

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 →

8-hour stability soak

v1.0 gate

1.27M circuits. 3.8M agent runs. 100% completion across 468 waves. Per-replica load split to 0.14%. Zero leaks (RSS, goroutines, connections, quotas). The substrate doesn't drift under sustained load. The number gate v1.0 had to clear. writeup →

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. RFC X both phases shipped: F41 cooperative pause parks in-flight sub-runs at iteration boundaries; F42 cross-instance resume re-dispatches paused runs on a fresh box. exp6.5 wipes a DB, restores on a fresh loomcycle instance, and the paused breeder finishes its work autonomously. 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. Validated by exp5 (5 RSS collectors → consolidator → Telegram digest). writeup →

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. The shape exp7 used to drive 10 reviewers across the loomcycle repo from one Claude Code call. exp7 writeup →

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 →

Python adapter on PyPi

v1.0 release

pip install loomcycle. Full client paired with @loomcycle/client on npm - same surface across HTTP / gRPC / MCP wire shapes. Python apps don't have to write a custom REST client to drive loomcycle.

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 generally-useful agentic runtime. The substrate primitives - Memory, Channel, AgentDef, Scheduler, Webhook, A2A, Evaluation, Context - 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. The 8-hour stability soak came from a production-load question: would this thing survive a long night? It did - 1.27M circuits, 3.8M agent runs, 100% completion across 468 waves, zero leaks.

JobEmber.ai is still its first consumer. loomcycle is now Apache-2.0, available to anyone with the same shape of problem - and a sidecar shape that integrates cleanly when Claude Code is your operator and conversation surface. The runtime is around 50 MB resident; one Go binary, no subprocess in the hot path.

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, Scheduler, Webhook, A2A, Evaluation, Context, OperatorTokenDef (multi-tenant authz), MemoryBackendDef, 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 (no Redis dep); three drop-in OTEL profiles (Grafana/Tempo/Prom/Loki, Honeycomb, Datadog APM); pause/snapshot/resume even mid-run and across instances (RFC X both phases); 8-hour stability soak - 1.27M circuits, 3.8M agent runs, 100% completion across 468 waves, zero leaks. 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; spawn_runs(mode: "join", N=…) (RFC Y) fans N agent runs from one MCP call - the shape exp7 used to drive 10 reviewers across the loomcycle repo from one Claude Code call. Interactive UX: Web UI terminal with mid-run steering, parked end_turn, cross-replica steer; context compaction (manual + auto + self). Adapters: @loomcycle/client on npm (ESM + CJS), pip install loomcycle on PyPi. 8-hour soak writeup → · exp7 writeup →

v1.xnext

Distribution polish + enterprise edition for procurement-shaped buyers

Helm chart for Kubernetes deployments. Operator cookbook covering the canonical postures and scaling patterns. Settings UI completion. n8n cloud verified-list submission (community-node install works today; icon refinement is the cloud-listing blocker). External code contributions open here. Enterprise edition for organizations whose procurement teams require it: SSO / RBAC / SCIM, signed audit logs, compliance evidence, automated key rotation. OSS edition stays feature-complete for individuals, small teams, and small-to-medium VPS deployments - multi-tenancy is in OSS, not paywalled. Next plugin in the contextplugin chain: a context-compressor plugin (the redact plugin's sibling - operator-extensible run-loop transforms become a real ecosystem).

post-v1.xresearch

Three named design RFCs beyond v1.0 - plus standing research threads

In preparation: context-compress plugin (RFC Z Phase 2). 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: tokenizer + content compressor compose with redact, transform a copy of the outbound request, leave the canonical history and the persisted transcript untouched. Same seam auto-compaction already uses; the new dependency is a tokenizer.

SQL Memory (RFC AA). A second facet of the Memory primitive: per-scope SQL databases the runtime owns, isolated from the main loomcycle store, that sandboxed agents query with arbitrary SQL. Two new Memory ops (sql_query, sql_exec), durable per-(tenant, scope, scope_id) plus an ephemeral per-run scratch DB, default-deny sql_scopes ACL, statement timeouts, byte quotas, full audit. Closes the "agents that need structured tables today need Bash + sqlite3" gap. sqlite tier first (one file per scope, hardened authorizer + statement allowlist), postgres tier (one schema per scope in a separate aux DB) follows.

Capability-based memory interface + mem0 backend (RFC K). Generalize the v0.15.0 memory.Backend contract with an optional MemoryLayer capability so LLM-extract memory products work natively (add(messages) → recall(query)) rather than degraded into a KV store. mem0 lands as the first MemoryLayer backend (Apache-2.0, 57k★, daily commits). The flat Backend stays canonical; an external memory-layer backend declines Backend and serves MemoryLayer only.

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. JobEmber.ai's continued production pain remains the primary source of v1.x feature triggers; if it surfaces something the substrate doesn't carry, that's what gets built next.

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 →

§ 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]