Skip to content

Architecture ​

A deep dive into how rubygems-skills is structured end to end — the package layout, the request pipeline, the auth model, and the concurrency design. Read this once and you'll know where every feature lives.

Package layout ​

Four packages, one responsibility each: repository is the HTTP client, models holds typed JSON structs, cache is the pluggable TTL store, install is the cross-platform Ruby provisioner. The CLI and examples are thin callers over repository (and install).

The request pipeline ​

Every read call flows through the same five stages. Write calls add auth and form/multipart encoding but otherwise share the pipeline.

Two things to notice: (1) URL encoding is centralized — every path segment goes through url.PathEscape, every query value through url.QueryEscape, so special characters never break a request. (2) Retry is opt-in per client, configured once via Options.SetRetryOptions and applied to every request that client makes (GET, POST, DELETE, form, multipart).

Authentication model ​

The SDK uses two auth strategies, chosen by endpoint. Read endpoints take an optional token to raise the rate-limit quota; write endpoints split between a bearer token and HTTP Basic.

Why two strategies? RubyGems.org exposes API-key management and the full authenticated profile behind HTTP Basic Auth (username + password), while gem publishing, yanking, owner, and webhook operations accept a bearer API token. The SDK mirrors this exactly: WriteRepository carries the bearer token in its options, and the *APIKey* / GetMyProfile methods take username, password arguments and apply Basic Auth per-request.

Cache decorator ​

CachedRepository wraps any Repository and short-circuits repeat reads. Same interface, drop-in.

The cache is keyed by method + arguments, with a per-entry TTL and a background cleanup goroutine. Pass any cache.Cache implementation — MemoryCache is the in-process default; you can back it with Redis, filesystem, or anything else by implementing the interface.

Retry & backoff ​

When RetryOptions is set, transient failures retry with exponential backoff before surfacing.

Defaults: 3 attempts, 1s initial wait, exponential backoff (waitTime * 2^(attempt-1), capped at 30s), retry on any error. Tune with NewDefaultRetryOptions().WithMaxAttempts(n).WithWaitTime(d). The same retry layer covers GET, POST, DELETE, form, and multipart requests — so PushGem retries too.

Bulk concurrency ​

BulkGet* methods fan out over a fixed-size worker pool. Each worker owns a distinct result slot, so the pool is lock-free on the result slice.

Because the dispatcher hands out indices (not names) and each worker writes only to its own results[i], there's no data race on the result slice — no mutex, no copy. ContinueOnError(false) stops dispatching after the first failure; the default true runs every item and collects per-slot errors. See Bulk Operations.

End-to-end from an AI agent's view ​

The agent never touches HTTP, JSON, or URL encoding — it calls typed methods and reasons over typed results. When it needs the actual gem/ruby binaries (e.g. to build a .gem before PushGem), the installer provisions them first.


← Back: How it works · Next: Installation

Released under the MIT License.