All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog 1.1.0.
TENANT_CLOSEDerror-code support per runtime spec v0.1.25.13 ofcycles-protocol-v0.yaml(runcycles/cycles-protocol#125): servers return HTTP 409error=TENANT_CLOSEDon reservation create/commit/release/extend when the owning tenant is CLOSED (mirrors governance spec Rule 2). NewErrorCode.TENANT_CLOSEDenum member,TenantClosedErrorclass (thrown at reservation time bywithCycles/ lifecycle /reserveForStreamviabuildProtocolException; commit-time client errors are handled/released internally bywithCycles, andStreamReservation.commit()throws genericCyclesError— neither commit path throws typed protocol exceptions), andCyclesProtocolError.isTenantClosed()helper. Purely additive — before this change the unrecognized code produced a genericCyclesProtocolErrorwith the rawerrorCode: "TENANT_CLOSED"preserved andisRetryable()alreadyfalse(409 < 500);errorCodeFromStringmapped it toErrorCode.UNKNOWN, whichisRetryableErrorCodereports as retryable — now it maps to the typed, non-retryable member. The vendored spec fixture (pinned pre-v0.1.25.13) is intentionally untouched until the spec PR merges.LIMIT_EXCEEDEDerror-code support per runtime spec v0.1.25.12 (revision 2026-07-04): HTTP 429 rate-limit responses (public evidence/JWKS endpoints) carryerror=LIMIT_EXCEEDEDplusRetry-After/X-RateLimit-Resetheaders. NewErrorCode.LIMIT_EXCEEDEDenum member in spec declaration order (afterMAX_EXTENSIONS_EXCEEDED;TENANT_CLOSEDrelocated after it so the enum mirrors the spec exactly). Classified retryable by bothisRetryableErrorCodeandCyclesProtocolError.isRetryable()— 429 is transient and the spec instructs retry after the indicated delay; the status-based rule only covers ≥500, so the code-based classification carries it (this also preserves the priorerrorCodeFromString → UNKNOWN → retryablefallback behavior). Enum-only by design, matching theBUDGET_FROZEN/BUDGET_CLOSEDpattern: not a reservation-lifecycle denial, so no exception class orbuildProtocolExceptionmapping.Retry-Afterheader exposure: the client now captures the HTTPRetry-Afterheader (how 429 rate-limit responses carry the delay per the spec) and exposes it asCyclesResponse.retryAfterMsHeader(seconds → ms; non-integer forms ignored gracefully).buildProtocolExceptionfalls back to it forretryAfterMswhen the body carries noretry_after_msfield (body wins when both are present). No auto-retry behavior change — the delay is surfaced, not consumed.
- README error-handling docs no longer describe
CyclesTransportErroras thrown on network failure — the SDK never constructs it. Reservation-time transport failures surface asCyclesProtocolErrorwithstatus: -1(withCycles/reserveForStream) or asCyclesResponsewithisTransportError/status: -1(programmatic client); commit-time failures are retried in the background bywithCycles, whileStreamReservation.commit()throws and resetsfinalizedfor caller retry or release. The class remains exported for use in user code; a new "Transport failures (status -1)" README subsection documents the actual behavior. examples/vercel-ai-sdkchat route no longer mixes AI SDK v4 and v5 APIs (it compiled under neither whilepackage.jsonpins"ai": "^4.0.0"): now pure v4 —Messagetype andconvertToCoreMessagesreplace v5'sUIMessage/convertToModelMessages.runcyclesusage unchanged.
- The Fixed items are docs + example only; the Added item is a small additive library change (no wire-format change).
Wire-passthrough verification for expires_from/expires_to and finalized_from/finalized_to query params on listReservations. Implements cycles-protocol-v0.yaml revision 2026-05-22 (runcycles/cycles-protocol#98) on the client side; runcycles/cycles-server#163 ships the server impl. Closes the TypeScript-client side of runcycles/cycles-server#162.
- Regression test on
client.listReservationsconfirming the four new ISO-8601 window params are URL-encoded and forwarded to the query string. The existingparams?: Record<string, string>signature already accepted them — the test locks the contract so future tightening cannot drop them silently. Colons URL-encoded to%3Aper native fetch + URLSearchParams behavior.
- No protocol or wire-format change. Servers older than v0.1.25.21 silently ignore the new params per the additive-parameter guarantee in
cycles-protocol-v0.yaml. - 317 tests pass; coverage 98.4% statements / 99.62% lines (gate ≥95% per
CLAUDE.md).
Wire-passthrough verification for the new from / to query params on listReservations. Implements cycles-protocol-v0.yaml revision 2026-05-21 (runcycles/cycles-protocol#97) on the client side; runcycles/cycles-server#160 ships the server impl.
- Regression test on
client.listReservationsconfirming thatfrom/toISO-8601 date-time params are URL-encoded and forwarded to the query string. The client'sparams?: Record<string, string>signature already accepted these — the test locks the contract so future tightening cannot drop them silently. Both colons are URL-encoded (from=2026-05-21T00%3A00%3A00Z).
- No protocol or wire-format change. Servers older than v0.1.25.20 silently ignore the new params per the additive-parameter guarantee in
cycles-protocol-v0.yaml. - 316 tests pass; coverage 98.4% statements / 99.62% lines (gate ≥95% per
CLAUDE.md).
npm metadata refresh for category-search discovery. No code changes — bundle and runtime behavior are identical to 0.3.0.
package.json: rewrotedescriptionto lead with the cost / action / audit pillars ("TypeScript AI agent runtime control — enforce LLM cost limits, action permissions, and audit trails for agents before execution.") and expandedkeywordsfrom 15 to 26. Drops legacy keywords (billing,metering,api-client,ai,llm,agents,token-budget,spend-limit) in favor of category-search variants (ai-agent,agent-budget,budget-control,cost-enforcement,spending-limit,llm-cost,runtime-authority,action-control,action-authority,audit-trail,audit,compliance,multi-tenant) plus framework targeting (langchain,langgraph,openai-agents,vercel-ai-sdk,mcp).
Java parity: dynamic subject and action fields on withCycles.
- Dynamic subject + action fields on
withCyclesconfig —tenant,workspace,app,workflow,agent,toolset,actionKind, andactionNamenow accept(...args: TArgs) => string | undefinedin addition to a static string. Callables are resolved against the wrapped function's per-call args; returningundefinedfalls through to the client-config default (subject) or"unknown"(action). Static strings unchanged. Java parity withcycles-spring-boot-starter#50. (#72)
Bug fixes, support 0.1.24 spec.
- Add badges to README for npm, CI, and license (#24)
- Add documentation links section to README (#25)
- Add budget and extension error codes, charged amount to event response (#29)
- Document nested withCycles behavior and recommended patterns (#26)
- Claude/analyze spring issue 29 v biy9 (#27)
- Change default overage policy from REJECT to ALLOW_IF_AVAILABLE (#28)
- chore: bump version to 0.2.0 for protocol v0.1.24 (#30)
Fix type safety in WithCyclesConfig generics.
- Add AUDIT.md documenting protocol conformance (#19)
- Add AWS Bedrock and Google Gemini budget governance examples (#20)
- Add parent README for examples directory (#21)
- Add API key creation guide to documentation and examples (#22)
- Fix type safety in WithCyclesConfig generics and add compile-time type tests (#23)
Updates and bug and stability fixes, more SDK examples.
- Add manual workflow_dispatch trigger to CI publish (#4)
- Add comprehensive test coverage for lifecycle, streaming, and error handling (#7)
- Add comprehensive examples for Cycles budget governance (#9)
- Claude/expand ai examples zj dwy (#10)
- Add ESLint with typescript-eslint/recommended and coverage thresholds (#12)
- Add lint and coverage enforcement to CI (#13)
- Add test for commit retry exhaustion warning (#18)
- Comprehensive README rewrite for npm publication (#5)
- Optimize initialization and add async disposal support (#6)
- Update TEST_COVERAGE_ANALYSIS.md with final coverage results (#8)
- Document withCycles client caching behavior in default client section (#11)
- Document commit rollback behavior for failed commits in streaming sec… (#14)
- Warn on commit retry exhaustion in CommitRetryEngine (#15)
- Remove dead code: unused constants, validateReservationId, makeClient (#16)
- Remove CyclesTransportError from public exports (#17)
Initial release.