docs: add agent-readable documentation and repository metadata - #428
Open
const-cloudinary wants to merge 3 commits into
Open
docs: add agent-readable documentation and repository metadata#428const-cloudinary wants to merge 3 commits into
const-cloudinary wants to merge 3 commits into
Conversation
Bring the repository up to the Cloudinary agent-readable documentation standard, following the structure shipped in cloudinary_npm (PRs #742 and #744). Documentation, shipped inside the Composer package so it is always version-matched to the installed code: - docs/ — 13 task pages with an index carrying the agent-rules banner. Every snippet was executed against a live cloud before being committed. - examples/ — 12 runnable files, one per task page, all verified green. Repository files: - README.md restructured: quick start, common tasks, when to use this SDK, compatibility, and a read path for coding agents. - AGENTS.md (six sections) plus CLAUDE.md; SECURITY.md with private vulnerability reporting; context7.json. Packaging: - .gitattributes decides what ships. docs/ and examples/ reach users at vendor/cloudinary/cloudinary_php/; tests/, tools/, samples/, apidocs/, and the lint/test configs no longer do. - The Sami API-doc tooling moves from docs/ to apidocs/ so that docs/ can hold the Markdown task docs, which is the path agents look for. tools/update_version.sh is updated to match. Corrections found by executing the documented calls rather than reading the source: - The API accessors are methods. The previous README documented $cloudinary->uploadApi->upload(...), which is a fatal error; it is $cloudinary->uploadApi()->upload(...). - ApiUtils is Cloudinary\Api\ApiUtils, although the file sits in src/Api/Utils/. - There is no uploadLarge(); upload() chunks automatically above chunk_size. - A partial configuration array replaces rather than merges, so passing only 'logging' discards credentials from CLOUDINARY_URL.
const-cloudinary
force-pushed
the
docs/agent-readable-documentation
branch
from
August 24, 2026 22:24
c752ffa to
9bfbbdd
Compare
Three integration tests asserted the exact shape of API responses and broke when the API added fields: - testListFacebookImages and testFacebookImagesWidthHeight asserted that Facebook assets carry no width or height. They now do. Raw assets still legitimately have none, so the two cases are split: raw asserts absence, Facebook asserts the values are integers when present. - testCreateDateMetadataField asserted that `restrictions` equals exactly ['readonly_ui' => true]. The API now also returns `hidden_ui` and `excluded_from_search`. The metadata fix is in the shared assertion loop, so every metadata test now checks that the expected keys are present and correct rather than that they are the only keys. Added fields no longer read as regressions.
Fixes found by executing the snippets, plus the review comments from the reference PRs (cloudinary_npm#742, pycloudinary#449) that still applied here. Corrections caught by running the code: - transform-and-deliver-video.md showed a /v1/ segment on a non-nested public_id in four places. The image page documents the rule correctly — /v1/ appears only when the public_id contains a slash — so the two pages contradicted each other. All four now match generated output exactly. - getenv() returns false when unset and fromCloudinaryUrl() requires a string, so the no-credentials path raised a TypeError instead of the SDK's ConfigurationException. troubleshoot-errors.php leaked a PHP signature dump; it now matches the other eleven examples. - Documented URLs omitted the ?_a= analytics parameter the SDK adds by default, so actual output did not match the page. Documented what it is and how to disable it. Review feedback applied: - Exception structure: ApiError is a bare Exception, so getCode() is 0 and there is no structured error body. Added the HTTP status column and a section stating that the exception class is the only machine-readable signal. - 423 (Processing) is unmapped in BaseApiClient and surfaces as GeneralError carrying the raw response body, so it cannot be caught by type. Documented with a message-matching retry. - Moderation is not access control: whether pending, approved, or rejected assets are deliverable is product-environment configurable, and the Media Library and CDN are separate surfaces. - Moderation add-ons need account enablement and sometimes provider terms acceptance — neither of which an agent can do. - Upload size limits are per product environment; raising chunk_size does not raise the ceiling. Added mitigations and an upgrade path. - Prefer asset_id for stored references; links to the search expression and transformation references; concrete one-hour signature lifetime; signed parameters must match what the client posts. Also tagged two illustrative blocks as plain rather than php: conflicting use statements and a bare class name are not runnable snippets and would otherwise be false positives for a snippet parser. Verified: 56 php blocks across docs/ parse clean, examples lint with zero phpcs errors, all twelve exit 1 with a readable message when credentials are absent, unit suite 375/375, all internal links and anchors resolve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Adds task-oriented documentation that ships inside the Composer package, so it always matches the installed version.
docs/— index plus 13 task pages: imports, configuration, a complete runnable flow, result fields, failure modes.examples/— 12 runnable files, one per task page.AGENTS.md,SECURITY.md..gitattributescontrols what ships. Installed path:vendor/cloudinary/cloudinary_php/docs/. It also excludestests/,tools/,samples/,apidocs/,.github/, and the lint/test configs — anything referencingvendor/cloudinary/cloudinary_php/tests/would break on upgrade.docs/toapidocs/;tools/update_version.shupdated to match.Corrections
Every snippet was executed against a live cloud, which caught real errors:
$cloudinary->uploadApi->upload(...), which is a fatal error. It is$cloudinary->uploadApi()->upload(...).ApiUtilsisCloudinary\Api\ApiUtils, though the file sits atsrc/Api/Utils/ApiUtils.php.uploadLarge()—upload()chunks automatically abovechunk_size.new Cloudinary(['logging' => ...])throws by discarding credentials.ConfigurationExceptiondoes not extendApiErrorand is in a different namespace, socatch (ApiError)alone misses it.Also documented:
resource_typedefaults toimageand fails loudly on video;update()returnscontextnested undercustom; redeclaring a metadata field throwsBadRequest.Integration test fix (
ddf6548)Three integration tests asserted the exact shape of API responses and broke when the API added fields. Pre-existing on
master, which last ran CI in April 2026 — unrelated to the documentation work, but fixed here so CI can go green.testListFacebookImages,testFacebookImagesWidthHeightasserted Facebook assets carry nowidth/height. They now do. Raw assets still legitimately have none, so the cases are split: raw asserts absence, Facebook asserts integers when present.testCreateDateMetadataFieldassertedrestrictionsequals exactly['readonly_ui' => true]; the API now also returnshidden_uiandexcluded_from_search. Fixed in the shared assertion loop, so every metadata test checks that expected keys are present and correct rather than that they are the only keys.