Add complete Rust client for Cycles budget authority protocol#1
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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: RAIIReservationGuardthat holds live reservations and enforces commit-or-release semantics through Rust's type systemsrc/lifecycle.rs: High-levelwith_cycles()wrapper for automatic reserve-execute-commit/release lifecycle (equivalent to Python's@cyclesdecorator)Protocol Models
src/models/: Complete type-safe protocol models including:enums.rs: Decision, Unit, CommitStatus, ReservationStatus, etc. with#[non_exhaustive]for forward compatibilitycommon.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.24Configuration & Error Handling
src/config.rs:CyclesConfigand builder pattern for client setup with sensible defaultssrc/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 periodsBackground Services
src/heartbeat.rs: Automatic TTL extension for long-running operationssrc/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 (behindblockingfeature flag)Testing & Documentation
Comprehensive Test Suite
tests/client_test.rs: 796 lines of integration tests using wiremock covering all endpoints, error cases, and response variantstests/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 spectests/lifecycle_test.rs: Tests forwith_cycles()automatic lifecycletests/config_test.rs,tests/error_test.rs,tests/guard_test.rs,tests/response_test.rs,tests/retry_test.rs: Focused unit testsExamples & 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 examplesAUDIT.md: Protocol conformance audit verifying all 9 endpoints, 16 schemas, and validation constraints match spec v0.1.24Notable Implementation Details
#[serde(other)]Unknown variants so new protocol values don't break deserializationReservationGuardconsumes itself on commit/release, preventing double-commits or accidental leaksboncrate for ergonomic request constructionhttps://claude.ai/code/session_01YEun5gKT59qD5yUqasCaar