Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"displayName": "Agent Stack",
"source": "./plugins/agent-stack",
"description": "Four skills: agent-orchestrator — tool-calling loops, pipelines with checkpoints, provider routing with fallback, memory architecture, plus the wallet side of reselling LLM access; agent-evals — run/trace/thread evals, LLM judges, and fixtures grown from production; agent-interop — MCP servers and clients, A2A agent cards, the MCP Registry, and gateways; agent-harness — system prompts, tool shaping, workflow-vs-agent, and auditing an agent system.",
"version": "0.27.2",
"version": "0.28.1",
"author": {
"name": "ssheleg",
"url": "https://x.com/sshlg93"
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
## 0.28.1 — a limit stop is not a wait

There is no 0.28.0 package. The tag `v0.28.0` was pushed by mistake onto `cb8f699` (the 0.27.1
source) before this change merged. Its release run (38332687325) was cancelled before the
release and publish jobs ran, so nothing was published under that version. The tag ruleset
does not allow deleting the tag, so it stays.

- **agent-orchestrator §4 and `references/runtime.md` → *A limit stop is not a wait*.** A worker
is a workflow lane, a sub-agent or a session. When it stops on a provider usage or session
limit ("resets 5am"), it is restarted at once from where it stopped and is never left until
the stated reset. The same holds when it fails on a rate-limit error after the host's own
retries, or goes silent for 15–20 minutes with its task unfinished and no command of its own
running. How each worker is restarted:
- a lane is resumed with the same run id and the same arguments, and finished agents replay
from the cache;
- a sub-agent gets `resume` at its id;
- a session is re-prompted.

A second immediate stop backs off 2, 5, 10, then every 15 minutes while other work goes on.
Spend, credit and billing limits are a person's gate: they are reported once and never looped.
Every restart is logged.

The reset time in a limit message describes one account at the moment of refusal. An account
rotator or a short rate window usually makes it stale within minutes. A team running parallel
workflow lanes observed this: six stopped on stated resets hours or days away, and each ran
when restarted minutes later.

The references index row for `runtime.md` names the usage-limit stop.

## 0.27.2 — owner board and release ancestry checks

- The repository validator now rejects missing boards, shifted rows, duplicate IDs
Expand Down
2 changes: 1 addition & 1 deletion SKILL-CARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
| Field | Value |
|---|---|
| Pack | `agent-stack` |
| Version | `0.27.2` |
| Version | `0.28.1` |
| Skills | `agent-orchestrator`, `agent-evals`, `agent-interop`, `agent-harness` |
| License | MIT |
| Source | https://github.com/ssheleg/agent-stack |
Expand Down
12 changes: 12 additions & 0 deletions docs/evidence/verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ This file exists because its absence read as zero exposure. `sshlg-skills` board

---

## Release candidate — v0.28.1 (2026-10-13)

The change is doctrine only: no script, validator or installer change. It was measured on the
branch `feat/limit-stop-restart` (rebased on `e2120c2`) before any tag; nothing below is a
published-artifact claim. `v0.28.0` is a mis-pushed tag on `cb8f699`, and its run 38332687325
was cancelled before release and publish (`npm view` → 0.27.2 afterwards); see CHANGELOG 0.28.1.

| REQ | What ships | How it was confirmed | Confirmed |
|---|---|---|---|
| Limit stop | The agent-orchestrator `SKILL.md` §4 bullet *A limit stop is not a wait* routes to `references/runtime.md` → *A limit stop is not a wait*. That section holds the three triggers, the restart table, the backoff, the billing exception and the restart log | `grep -n "A limit stop is not a wait"` on both files; the runtime contents list carries the section | **observed**, local |
| Gate | `npm test` | EXIT=0 on 2026-10-13: `OK: agent-stack structurally valid (17 checks = 13 named + 4 per-skill, 4 skill(s), v0.28.1)`, `PASS: plant_guard — 9 cases`, `PASS: reap-own — 13 cases`, `PASS: installer — 11 case(s)`, all 25 `test/audit_regressions/*.py` exit 0; `claude plugin validate --strict` passed for `plugins/agent-stack` and the marketplace | **observed**, local |

## Released — v0.27.2 (2026-10-13)

Source integration: PR47 merged at `053c0f8725d28e464c98d063e87618c15174849a`.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ssheleg/agent-stack",
"version": "0.27.2",
"version": "0.28.1",
"scripts": {
"test": "python3 test/validate.py && python3 test/plant_guard_test.py && python3 test/member_owner_gates_test.py && python3 test/reap_own_test.py && node test/installer_test.js && npm run test:audit",
"test:audit": "for t in test/audit_regressions/*.py; do python3 \"$t\" || exit 1; done"
Expand Down
2 changes: 1 addition & 1 deletion plugins/agent-stack/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "agent-stack",
"displayName": "Agent Stack",
"description": "Four skills: agent-orchestrator — tool-calling loops, pipelines with checkpoints, provider routing with fallback, memory architecture, plus the wallet side of reselling LLM access; agent-evals — run/trace/thread evals, LLM judges, and fixtures grown from production; agent-interop — MCP servers and clients, A2A agent cards, the MCP Registry, and gateways; agent-harness — system prompts, tool shaping, workflow-vs-agent, and auditing an agent system.",
"version": "0.27.2",
"version": "0.28.1",
"author": {
"name": "ssheleg",
"url": "https://x.com/sshlg93"
Expand Down
7 changes: 6 additions & 1 deletion plugins/agent-stack/skills/agent-orchestrator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ Three decisions the rest follows from:
passes every check that only looks for an exception.
- **Cap the attempts and return the best partial**, because the alternative to a partial
answer is not a better answer, it is no answer and a spent budget.
- **A limit stop is not a wait.** A worker halted by a provider's usage limit
("resets at 9pm"), a rate-limit error, or silence with its task unfinished is restarted
from where it stopped right away, not at the stated reset; back off only when the
restart fails again. Spend and billing limits are the exception — a person's gate.
Mechanics: [`references/runtime.md`](references/runtime.md) → *A limit stop is not a wait*.

The hierarchy, the loop and the per-domain validators:
[`references/patterns.md`](references/patterns.md).
Expand Down Expand Up @@ -346,7 +351,7 @@ there; this table is only an index.
| [`references/memory-landscape.md`](references/memory-landscape.md) | **build or adopt** a memory layer, and what is settled practice |
| [`references/context-engineering.md`](references/context-engineering.md) | the loop is **running out of window** |
| [`references/kv-cache.md`](references/kv-cache.md) | you are deciding **what goes where in a request** — the static prefix against the trajectory, what a miss costs, the 2^N cache populations a runtime condition in front of the boundary creates, the named invalidators, and the four common optimisations that pay cache for nothing |
| [`references/runtime.md`](references/runtime.md) | the agent must **survive a crash, a pause, a second message or a schedule** |
| [`references/runtime.md`](references/runtime.md) | the agent must **survive a crash, a pause, a second message, a schedule or a usage-limit stop** |
| [`references/governance.md`](references/governance.md) | the question is **permission, not cost** — what it may do, and how you prove it |
| [`references/llm-proxy-billing.md`](references/llm-proxy-billing.md) | the product **resells LLM access** |
| [`references/provider-lifecycle.md`](references/provider-lifecycle.md) | the question is the **workforce, not the loop** — provider lifecycle, canary trust, fleet budgets |
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ has only built the first one discovers the second in production.
## Contents

- Durability, and where our own asymmetry was
- A limit stop is not a wait
- The interrupt/resume contract
- Double-texting: four policies
- Streaming that survives a dropped connection
Expand Down Expand Up @@ -42,6 +43,46 @@ Two properties earn their cost:
- **A pause frees the worker.** An agent waiting for a human should hold no process. If
waiting costs a worker, long approvals are quietly expensive and teams stop using them.

## A limit stop is not a wait

A coding-agent host shows a usage stop as *You've hit your session limit · resets 5am*.
The time in that message describes **one account**, read when the request was refused. In
practice an orchestrator that restarts the worker minutes later usually finds it runs. An
account rotator may already have moved the session to an account with room, or the
limit was a short rate window. Waiting hours for the stated reset idles a run that would
have gone on.

**Three triggers** send the orchestrator to restart a worker — a lane of a workflow, a
sub-agent, a whole session:

- it stopped on a usage or session limit, whatever reset time it names;
- it failed on a rate-limit error after the host's own retries;
- it went silent: no transcript or event write for 15–20 minutes, its task unfinished,
**and no command of its own still running**. A build or a test suite that runs for half
an hour is not a stall, and stopping that lane loses the step in flight.

**Restart at once, from where it stopped**, never from scratch:

| Worker | Restart |
|---|---|
| A workflow lane | stop the workflow, then resume it with the same run id and **the same arguments**: finished agents replay from the cache, and only the failed or stalled ones run again |
| A sub-agent | send `resume` to its id, so it keeps its own context |
| A session | re-prompt it: *continue from where you stopped* |

Changed arguments invalidate the cache, so the whole run is paid for again.

**Back off only on a second stop.** If the restart halts again at once, retry at 2, 5,
10 and then every 15 minutes, and keep doing independent work in between. Do not sleep
until the reset time.

**Not every limit is retried.** A spend cap, exhausted credits or a billing error does not
clear on a timer: someone has to pay or raise it. Report it to that person once and do
not loop.

**Log every restart** in the run's journal: which worker stopped, on what, when, and the
attempt number. Ten restarts of one lane in an hour is a finding about that lane, not
noise.

## The interrupt/resume contract

The body has two mechanisms for one idea: `ask_user` raises a clarification error, and a
Expand Down
Loading