Skip to content

v1.77.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 18:53
· 11 commits to main since this release
5014665

loomcycle v1.77.0 — the TeamDef workflow substrate (RFC CY), and facts get one home (RFC CV)

Two lines land in this release.

A team is no longer just a state machine you invoke. It reads its own work,
fans it out, publishes results onward, and can be watched and stepped while it
runs.

The starter primitive. The dispatcher the design was missing: it reads
ONE channel, fans out a wave (one run per message, dynamic N), and the RUNTIME
publishes each result to a declared sink. One subscriber means one cursor, so
a fan-out is correct by construction, and agents in a wave need no channel
grant in either direction — the team is the ACL subject. Every spawned run
emits exactly one sink message on a guaranteed path, so a downstream fan-in is
unblocked by failure rather than hanging on it.

A walk is a run. TeamDef op=run now opens a session and a runs row
filed under team:<name>, and mode: "detach" returns {run_id, status}
immediately with the walk continuing behind it. That run_id is also the walk's
correlation id, stamped on the parent_context of every agent the walk
spawns — one handle for the response, the run row, the event stream and the
debugger.

Debug a workflow while it runs. Breakpoints on a Starter pause before
dispatch (every prompt composed, nothing spawned) or after collection (the
wave done, nothing published). Answer continue / release:<n> / abort
through the existing Interruption machinery. The armed set is read at every
pause, not captured at dispatch, so a state can be armed AFTER a run
started — the case you are actually in when you watch a wave go wrong.

PUT /v1/runs/{run_id}/breakpoints   {"breakpoints": ["review"]}
GET /v1/users/{user_id}/agents/stream?walk_id=<run_id>

Authoring catches what used to fail at run time. create/fork preflight a
definition's channel references and refuse an unrunnable one with the exact
block to paste; op=verify reports runnable plus the issues a stored def has
accumulated (a channel deleted, an ACL gap, a member retired).

Armed subscriptions (LOOMCYCLE_TEAM_SUBSCRIPTIONS=1, default off) drive a
promoted team when its source has work, one replica at a time via a per-team
Postgres advisory lock. This is the only part of the runtime that starts agent
runs unprompted — turning it on is a spend commitment, and it is off until you
say otherwise.

system-channels bundle (LOOMCYCLE_PRESETS=base,system-channels)
declares the runtime's own channels a workflow can read — three heartbeats and
the interruption pair. A bundle rather than a default because a ticker writes a
row every period on every deployment, forever.

TypeScript adapter 1.77.0 carries the whole surface: runTeam({mode: "detach", breakpoints}), getRunBreakpoints, setRunBreakpoints.

The memory line moves facts onto the chunk plane: a subject is its own
document and its facts are its children, a fact is reachable from every
subject it is about, and it can be traced back to the turn it came from. The
tenant entity registry is curator-gated.

  • The wave correlation was being dropped on write. ParentContext.IsZero()
    did not list the wave fields, so every run a Starter spawned stored a NULL
    parent_context. The guard is now derived from the struct.
  • An "open" channel ACL granted nothing. Three def-authoring planes
    declared Publish: ["*"], which the matcher never matches — so no Starter
    team was authorable-and-runnable over MCP, gRPC or the admin HTTP surface.
  • Channel hold is honoured by every writer, not only the two that
    resolved the definition.
  • A resolved {{document:}} ref is re-checked against its charset, closing
    a path where an untrusted variable could escape the frame into a system
    prompt.

Nothing is required. Every new behaviour is opt-in: a team without a starter
runs exactly as before, breakpoints and mode are absent unless passed,
armed subscriptions and the system-channels bundle are off until selected.