Skip to content

Add complete Rust client for Cycles budget authority protocol#1

Merged
amavashev merged 9 commits into
mainfrom
claude/rust-client-evaluation-350x3
Mar 31, 2026
Merged

Add complete Rust client for Cycles budget authority protocol#1
amavashev merged 9 commits into
mainfrom
claude/rust-client-evaluation-350x3

Conversation

@amavashev
Copy link
Copy Markdown
Contributor

Summary

This PR introduces a complete, production-ready Rust client for the Cycles budget authority protocol. The client provides an idiomatic Rust API built around RAII guards and ownership semantics for managing budget reservations, commits, and releases in autonomous agent runtimes.

Key Changes

Core Client Implementation

  • src/client.rs: Async HTTP client with all 9 protocol endpoints (reserve, commit, release, extend, decide, balance, events, list, and heartbeat)
  • src/guard.rs: RAII ReservationGuard that holds live reservations and enforces commit-or-release semantics through Rust's type system
  • src/lifecycle.rs: High-level with_cycles() wrapper for automatic reserve-execute-commit/release lifecycle (equivalent to Python's @cycles decorator)

Protocol Models

  • src/models/: Complete type-safe protocol models including:
    • enums.rs: Decision, Unit, CommitStatus, ReservationStatus, etc. with #[non_exhaustive] for forward compatibility
    • common.rs: Value objects (Amount, Subject, Action, Caps, Balance, CyclesMetrics)
    • ids.rs: Strongly-typed newtype wrappers (ReservationId, EventId, IdempotencyKey)
    • request.rs & response.rs: All request/response types matching OpenAPI spec v0.1.24

Configuration & Error Handling

  • src/config.rs: CyclesConfig and builder pattern for client setup with sensible defaults
  • src/error.rs: Comprehensive error type with methods for checking error categories (budget exceeded, retryable, etc.)
  • src/validation.rs: Input validation for subjects, TTLs, and grace periods

Background Services

  • src/heartbeat.rs: Automatic TTL extension for long-running operations
  • src/retry.rs: Exponential backoff retry engine for failed commits (wired for future use)
  • src/response.rs: Response wrapper capturing HTTP metadata (request IDs, rate limits)

Optional Features

  • src/blocking.rs: Synchronous wrapper with internal tokio runtime (behind blocking feature flag)

Testing & Documentation

Comprehensive Test Suite

  • tests/client_test.rs: 796 lines of integration tests using wiremock covering all endpoints, error cases, and response variants
  • tests/live_server_test.rs: Live integration tests against a real Cycles server (marked #[ignore])
  • tests/models_test.rs: Wire format compliance tests verifying serialization matches OpenAPI spec
  • tests/lifecycle_test.rs: Tests for with_cycles() automatic lifecycle
  • tests/config_test.rs, tests/error_test.rs, tests/guard_test.rs, tests/response_test.rs, tests/retry_test.rs: Focused unit tests

Examples & Documentation

  • examples/: Four runnable examples (basic_usage, guard_usage, with_cycles_usage, streaming_usage, error_handling)
  • README.md: Quick start guide with automatic and manual lifecycle examples
  • AUDIT.md: Protocol conformance audit verifying all 9 endpoints, 16 schemas, and validation constraints match spec v0.1.24

Notable Implementation Details

  • Type Safety: Strongly-typed IDs and enums prevent common mistakes (e.g., can't accidentally use EventId where ReservationId is expected)
  • Forward Compatibility: All enums use #[serde(other)] Unknown variants so new protocol values don't break deserialization
  • Ownership-Based Lifecycle: ReservationGuard consumes itself on commit/release, preventing double-commits or accidental leaks
  • Builder Pattern: Fluent API using bon crate for ergonomic request construction
  • Idempotency: Auto-generated idempotency keys

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar

claude added 9 commits March 31, 2026 10:05
Rust-native client for the Cycles budget authority protocol, designed
around ownership semantics rather than ported from other languages.

Key design decisions:
- ReservationGuard with commit(self)/release(self) for compile-time
  double-commit prevention
- #[must_use] warns on forgotten reservations, Drop does best-effort release
- Newtype IDs (ReservationId, IdempotencyKey) prevent mixups
- #[non_exhaustive] enums for forward compatibility
- serde handles wire format natively (zero mapper code)
- bon::Builder for compile-time required field enforcement
- Automatic heartbeat via CancellationToken + tokio::spawn
- Commit retry engine with exponential backoff

Includes:
- CyclesClient with all 9 protocol endpoints
- Full model types (request, response, enums, value objects)
- CyclesConfig with env var loading and builder
- ApiResponse<T> wrapper for rate limit metadata
- Input validation (subject, TTL, grace period, amounts)
- Blocking client behind feature flag
- 4 examples (basic, guard, streaming, error handling)
- 20 unit tests + 4 doc tests, all passing

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Changes:
- Add #[serde(other)] to all response enums for forward compatibility
  (unknown protocol values deserialize to Unknown instead of failing)
- Add Debug impl for ReservationGuard
- Fix error response parsing to prefer body request_id over header
- Classify OverdraftLimitExceeded and DebtOutstanding as budget errors
- Fix clippy warnings

Test suite (112 tests):
- 26 wiremock integration tests for all 9 client endpoints
- 18 wire format compliance tests matching OpenAPI spec
- 10 error type method tests
- 10 config/builder tests
- 4 guard lifecycle tests (commit, release, extend, drop)
- 2 ApiResponse wrapper tests
- 37 unit tests (models, enums, ids, validation, retry)
- 4 doc-tests
- 1 retry engine test

Coverage: 94.41% (405/429 lines)

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Tests the full Rust client against a real Cycles server (Redis + Spring Boot)
running on localhost:7878. Covers the complete protocol lifecycle:

- Reserve → commit with metrics (actual < estimate, delta released)
- Reserve → release with reason
- Reserve → extend (heartbeat) → commit
- Guard auto-release on drop (verified via get_reservation status)
- Low-level create_reservation → commit_reservation
- Decide preflight check
- Direct-debit event creation
- Balance query
- List reservations
- Response metadata (x-request-id header)
- Dry run (decision without reservation)
- Auth failure (401 with bad API key)

All 12 live tests + 112 unit/wiremock tests = 124 total, all passing.

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
- Add AUDIT.md: full protocol conformance audit matching the format used
  by Python, TypeScript, Spring Boot, and Server repos. Documents all 9
  endpoints, 6 request schemas, 10 response schemas, 7 nested objects,
  5 enums — all PASS against cycles-protocol-v0.yaml v0.1.24.

- Add CLAUDE.md: project conventions (git rules, build/test commands,
  95%+ coverage mandate, YAML spec authority).

- Fix module visibility: change `pub mod` to `pub(crate) mod` for
  internal modules (constants, heartbeat, retry) — removes dead code
  warnings and stops exposing implementation details.

- Always serialize ttl_ms explicitly (remove skip_serializing_if for
  default value) — matches TypeScript client behavior of always sending
  the field to the server.

- Add #[ignore] to all 12 live server tests — cargo test now passes
  without a running server. Run with `cargo test -- --ignored`.

- Remove unused DEFAULT_TTL_MS constant.

Results: 112 tests pass + 12 ignored + 4 doc-tests. 0 clippy warnings.
95% line coverage.

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Adds the Rust equivalent of Python's @cycles decorator and TypeScript's
withCycles higher-order function. Developers now have three integration
levels:

1. with_cycles() — automatic reserve/execute/commit. Simplest. One-liner.
   Auto-releases on error. Like @cycles in Python.

2. ReservationGuard (RAII) — manual control. For streaming, multi-step
   workflows, or when you need caps/decision mid-operation. Compile-time
   double-commit prevention via ownership.

3. Low-level client API — direct HTTP methods for full control. Build
   custom lifecycles, cross-process reservations, etc.

The with_cycles closure receives a GuardContext (owned snapshot of
decision, caps, reservation_id, affected_scopes) to avoid lifetime
issues with async closures.

Includes 5 new tests, updated README with both APIs, new example.
121 tests + 12 ignored + 8 doc-tests. 0 clippy warnings.

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Adds CI matching the pattern used by TypeScript, Python, and Spring Boot
clients:

- Calls shared reusable ci-rust.yml from runcycles/.github
- Tests on stable + MSRV 1.75
- cargo fmt --check, cargo clippy -D warnings, cargo test
- Coverage via cargo-tarpaulin
- Publish to crates.io on version tags (v*)

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Fixes for CI readiness (cargo clippy --all-targets -- -D warnings):
- Replace #[cfg(test)] compile-time assertions with const fn pattern
  (eliminates dead_code warnings in CI mode)
- Fix needless borrows (&server.uri() → server.uri()) across all tests
- Run cargo fmt on all files

Documentation accuracy fixes:
- AUDIT.md: update test count (141) and coverage table to include
  lifecycle.rs at 100%, overall 95.3%
- CHANGELOG.md: add with_cycles(), GuardContext, CI workflow, three
  integration levels
- All doc-tests compile and pass (8 total)

Final state:
- 121 tests pass + 12 ignored + 8 doc-tests = 141 total
- cargo clippy --all-targets -- -D warnings: 0 errors
- cargo fmt --check: clean
- cargo tarpaulin: 95.30% coverage (466/489 lines)

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Align with Python/TypeScript client metadata patterns:
- Bump version to 0.2.0 (matches other clients)
- Add homepage (runcycles.io), documentation (docs.rs), readme
- Expand description for search relevance
- Add third category: web-programming::http-client
- Add docs.rs metadata (all-features, rustdoc cfg)
- Add maintenance badge (actively-developed)
- Keywords aligned with Python/TS: cycles, budget, llm, ai-agents,
  cost-control (crates.io max 5)

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
Adds shields.io badges consistent with Python/TypeScript/Spring Boot
clients: crates.io version, docs.rs, CI status, license, coverage.

https://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar
@amavashev amavashev merged commit 3b8a8fd into main Mar 31, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants