Skip to content

docs: add agent-readable documentation and repository metadata - #596

Open
const-cloudinary wants to merge 2 commits into
masterfrom
docs/agent-readable-documentation
Open

docs: add agent-readable documentation and repository metadata#596
const-cloudinary wants to merge 2 commits into
masterfrom
docs/agent-readable-documentation

Conversation

@const-cloudinary

Copy link
Copy Markdown
Member

Goal

Ship version-matched documentation inside the published gem, so an AI coding agent working in a user's project reads docs that match the installed code instead of relying on stale training data. Follows the standard established in cloudinary_npm (#742, #744).

Agent read path, verified against a real install:

ruby -e 'puts Gem::Specification.find_by_name("cloudinary").gem_dir + "/docs"'
# => $(gem env gemdir)/gems/cloudinary-<version>/docs

Added

  • docs/ — 17 Markdown task pages, shipped in the gem. Index carries the agent-rules banner and locator one-liner.
    • Core: platform-capabilities, get-credentials, require-and-call, configure, upload-image, upload-large-video, sign-browser-upload, transform-and-deliver-image, transform-and-deliver-video, search-and-manage-assets, moderate-upload, use-structured-metadata, troubleshoot-errors.
    • Rails (no npm equivalent): use-with-rails, upload-with-activestorage, upload-with-carrierwave.
  • examples/ — 12 runnable files, 1:1 with the task docs, cross-linked.
  • AGENTS.md (6 sections) + CLAUDE.md (@AGENTS.md).
  • LICENSE — MIT, canonical text, at root.
  • SECURITY.md — private vulnerability reporting.
  • context7.json.

Changed

  • README.md — restructured: install, quick start, common tasks, when to use, compatibility, documentation, AI agent read paths, support, security. Dead Travis CI badge replaced with GitHub Actions.
  • cloudinary.gemspec — ship docs/ and examples/ explicitly; add documentation_uri, source_code_uri, bug_tracker_uri.
  • .gitignore — artifacts produced by running the examples.

No changes to lib/ or spec/. No changelog entry (docs-only).

Behaviours corrected by execution

Every snippet was run against a live cloud rather than read from source. Docs were wrong on these until tested:

  • upload_large defaults to resource_type: :raw — a video uploaded without it succeeds silently as an untransformable blob.
  • overwrite: false does not raise; it returns the existing asset with existing => true.
  • folder:examples matches 0 of 61 images on a dynamic-folder environment (the default for new clouds). Docs use public_id:examples/*.
  • Upload response has no moderation_status key; resource() and update() have both it and moderation.
  • Cloudinary::Api and Cloudinary::Search raise bare RuntimeError for missing config; Uploader and Utils raise CloudinaryException. rescue CloudinaryException misses the Admin API path.
  • URLs are HTTPS by default; ?_a= analytics param is appended; /v1/ placeholder appears when the public_id contains a slash and no version is known.
  • CLOUDINARY_CLOUD_NAME causes CLOUDINARY_URL to be ignored entirely, not merged.
  • Undefined structured-metadata keys reject the whole upload. Search rejects leading wildcards and bare *.

Verification

Check Result
Examples run live 12/12 pass (Rails 8.1.1, CarrierWave 3.1.3 installed)
Examples, no credentials 12/12 friendly message, exit 1, no stack trace
Ruby syntax 12/12 examples, 45/45 doc snippets
Internal links and anchors 121/121 resolve
External URLs 52/52 return 200
SDK symbols named in docs all resolve against the real library
Built .gem contents 17 docs + 12 examples, 0 stray artifacts
Existing specs no regression (10 failures on branch = 10 on master)

Notes

  • Badges sit above the H1, matching this gem's previous README and RubyGems convention. cloudinary_npm places them below the one-liner.
  • context7.json carries the account-scoped key from cloudinary_npm. It is inert until the library is submitted at context7.com — still outstanding.
  • GitHub repo metadata (description, homepage, topics) not changed — outward-facing, needs a maintainer decision.
  • #595 adds .cursor/ and copilot files this standard excludes, and is superseded by this PR.
  • samples/ flagged as legacy in AGENTS.md; not modified.

Bring the repository up to the Cloudinary agent-readable documentation
standard established in cloudinary_npm (PRs #742, #744).

- README restructured: install, quick start, common tasks, when to use,
  compatibility, documentation, AI agent read paths, support, security.
  Replaces the dead Travis CI badge with GitHub Actions.
- docs/ — 17 version-matched Markdown task pages shipped inside the gem,
  with the agent-rules banner and a locator one-liner. Includes Rails,
  Active Storage, and CarrierWave pages this gem needs and npm has no
  equivalent for.
- examples/ — 12 runnable files, 1:1 with the task docs, cross-linked.
- AGENTS.md (six sections) + CLAUDE.md; LICENSE (MIT) at root;
  SECURITY.md with private vulnerability reporting; context7.json.
- gemspec: ship docs/ and examples/ explicitly, add metadata URIs.
- gitignore artifacts produced by running the examples.

Every snippet was executed against a live cloud rather than read from the
source. Behaviours corrected as a result include upload_large defaulting
to resource_type :raw, overwrite: false returning `existing` instead of
raising, folder: search returning nothing in dynamic-folder environments,
and the upload response omitting moderation_status.

No library code changed.
Align the shared task docs with the corrections verified in cloudinary_npm
PR #742 and applied in pycloudinary (b6674a1).

Moderation: a pending asset is deliverable by default — the status is
metadata to gate on, not an access control. The previous text had this
inverted, claiming a pending asset's delivery URL 404s until approved,
which would lead an agent to ship a UGC flow that delivers unreviewed
content. Fixes the intro, the delivery section, and the example. Statuses
are queued, pending, approved, rejected, and aborted. Adds the add-on
table, pipe-combination semantics, and design rules.

Exceptions: Cloudinary::Api::Error descends from CloudinaryException, so
`rescue CloudinaryException` does catch NotFound, RateLimited, and the
rest — the doc's "WRONG" example was not wrong. The real gap is narrower:
Api and Search raise a bare RuntimeError for missing configuration.
Restated to match the hierarchy in base_api.rb.

Troubleshooting: document 423 while processing. Unlike pycloudinary, 423
is absent from this SDK's status map, so it hits the unmapped-status
branch and raises Cloudinary::Api::GeneralError carrying the raw response
body rather than the parsed error message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant