From 3fa5b27a5ae07f7b76ecde3b6444f627bcc1e221 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Sat, 22 Aug 2026 16:50:29 -0500 Subject: [PATCH 01/10] skills: Add pdfRest client API guidance - Add a skill for forward-compatible typed client API changes. - Require documented API contracts, model-first serialization, and sync/async unit and live coverage. Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 128 ++++++++++++++++++ .../pdfrest-client-api/agents/openai.yaml | 4 + 2 files changed, 132 insertions(+) create mode 100644 .agents/skills/pdfrest-client-api/SKILL.md create mode 100644 .agents/skills/pdfrest-client-api/agents/openai.yaml diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md new file mode 100644 index 00000000..0ef8ded9 --- /dev/null +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -0,0 +1,128 @@ +--- +name: pdfrest-client-api +description: Add or compatibly evolve typed PdfRestClient and AsyncPdfRestClient API helpers from a documented PDFCloud-API operation. Use for new endpoints or added endpoint parameters; do not use for unrelated client maintenance. +--- + +# pdfRest Client API + +Implement a documented pdfRest capability as a coherent, forward-compatible +Python SDK API. This skill covers a new helper and a compatible enhancement to +an existing helper, such as an added server parameter. + +## Discover the contract first + +- Require the PDFCloud-API checkout. Locate it relative to this checkout; do not + assume a user-specific path. +- Read this repository's `AGENTS.md` and `TESTING_GUIDELINES.md`, then read + `PDFCloud-API/docs/openapi/openapi-spec.yaml` before editing. +- Treat the OpenAPI operation, schemas, media types, documented errors, and + async/polling behavior as the public contract. Inspect API source only to + clarify behavior absent from, or apparently inconsistent with, that contract. +- Do not edit PDFCloud-API unless the user explicitly requests an API-contract + change. +- Stop and ask the user for direction if the checkout or documented operation is + missing, a required fixture cannot be obtained, or a compatible SDK adaptation + cannot be made. + +## Public API design + +Name a helper for the user outcome, not the path or OpenAPI operation ID. + +- Use `snake_case` and lead with a precise action: `convert_`, `add_`, + `remove_`, `change_`, `flatten_`, `extract_`, `query_`, `preview_`, `apply_`, + `merge_`, `split_`, `zip_`, or `unzip_`. +- Name the material source/result or effect: `convert_html_to_pdf`, + `add_text_to_pdf`, and `merge_pdfs`. Include both sides of a conversion. +- Split kitchen-sink routes into distinct helpers when source type, output, + validation, or user workflow differs. `/pdf` correctly maps to helpers such as + `convert_office_to_pdf`, `convert_html_to_pdf`, and `convert_url_to_pdf`, not + one mode-driven endpoint wrapper. +- Use a qualifier only when it changes the contract or workflow, such as + `preview_redactions` then `apply_redactions`, or text versus image + watermarking. +- Preserve all existing public method names. Do not rename a method merely to + fit this standard. + +Keep the upload lifecycle separate from execution: + +- Upload with `client.files.create*` first. Processing helpers accept uploaded + `PdfRestFile` resources (or typed sequences/compound inputs containing them), + never local paths, bytes, multipart values, or exposed raw `PdfRestFileID`s. +- Apply the same rule to optional assets such as profiles, attachments, + certificates, and merge sources. +- Add matching methods with the same name and contract to `PdfRestClient` and + `AsyncPdfRestClient`; async behavior differs only by awaiting the operation. + +## Compatibility for existing helpers + +Before modifying an existing method, compare its signature, defaults, accepted +input shapes, validation behavior, return model, documentation, and serialized +body to the current API contract. + +- Preserve existing caller behavior. Additive parameters must be optional, have + a safe backward-compatible default, and be supported by both transports. +- Do not change positional meaning, narrow accepted types, alter established + defaults, remove arguments, or change response shapes as part of an API + adaptation. +- If the server requires a breaking SDK change and no faithful compatible + translation/default exists, stop and ask the user for a migration decision + before editing. + +## Model-first validation and transformation + +Public methods provide Python-friendly inputs; a Pydantic payload model owns +validation and turns them into the exact pdfRest wire contract. + +- Create or extend one payload model in `src/pdfrest/models/_internal.py` that + mirrors the server request field-for-field. Keep reusable public type aliases + in `src/pdfrest/types/`. +- Keep client methods thin: assemble a payload dict and call + `_post_file_operation(..., payload_model=...)`. Do not duplicate payload + validation in the client. +- Use native annotated constraints, literals, and length bounds first. Use + `BeforeValidator` to adapt friendly input shapes, `AfterValidator` for MIME + and relational validation, and small field serializers for server formatting. +- Use `validation_alias` for accepted SDK input names and `serialization_alias` + for the server field name. Serialize uploaded `PdfRestFile` values to the + required ID field with the existing serializers. +- Validate MIME types and resource cardinality before a request. For payload + validation failures, raise Pydantic `ValidationError` via `ValueError` or + `AssertionError`, not `TypeError`. +- Use `model_validator(mode="before")` only to map a friendlier compound input + onto existing API fields. Do not introduce a payload `@model_serializer`; use + field serializers and declarative nested models instead. +- Serialize through Pydantic with + `model_dump(mode="json", by_alias=True, exclude_none=True, exclude_unset=True)`, + not ad hoc JSON encoding. +- Validate the raw response, resolve output IDs to `PdfRestFile` metadata, and + return the appropriate typed response model. + +## Tests and documentation + +Follow `TESTING_GUIDELINES.md` and the live-test requirements in `AGENTS.md`. + +- Add or extend the endpoint's focused unit module under `tests/` and a matching + endpoint module under `tests/live/`. Do not put endpoint coverage into a + generic catch-all file. +- Write distinct sync and async tests for each important path; do not conceal + transport parity behind parametrization. +- Unit tests use `httpx.MockTransport` to assert method, path, headers, exact + Pydantic-produced request body, response mapping, request customization, and + timeout propagation. For local-invalid input, configure the transport to fail + if called. +- Test payload models directly as well as client methods: accepted ergonomic + shapes and the exact alias-based serialization must both be covered. +- Cover default and non-default options, accepted literals, numeric bounds, + MIME/cardinality/dependency rules, and every meaningful response attribute. + Extend a shared validation suite when a rule applies to a model family. +- Live tests upload deterministic fixtures first, execute with the returned + `PdfRestFile` resources, and assert IDs, filenames, MIME types, output count, + warnings, and endpoint-specific behavior. Use `extra_body` or `extra_query` to + reach and assert server-side negative validation. +- Update the API guide, public exports, and user-facing examples when the new + capability or parameter changes discoverability or usage. + +Run targeted unit and live tests first, then the relevant Ruff and type checks. +Run the full pytest suite and `uvx nox -s tests` when practical. Report the +OpenAPI operation inspected, files changed, checks run, checks skipped, and any +live-validation limitation. diff --git a/.agents/skills/pdfrest-client-api/agents/openai.yaml b/.agents/skills/pdfrest-client-api/agents/openai.yaml new file mode 100644 index 00000000..fe27768b --- /dev/null +++ b/.agents/skills/pdfrest-client-api/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "pdfRest Client API" + short_description: "Add or evolve typed pdfRest client API helpers." + default_prompt: "Use $pdfrest-client-api to add or modify a forward-compatible API helper on PdfRestClient and AsyncPdfRestClient, using PDFCloud-API as the contract source and complete unit/live coverage." From a53dc07ce753c366320ccf1b49ce5f090626dd18 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Sat, 22 Aug 2026 19:36:57 -0500 Subject: [PATCH 02/10] pdfrest-client-api: Document API payload test coverage - Specify discriminator, boundary, and resource validation coverage - Require timeout and metadata-dependency checks per transport Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 11 +++++++++++ AGENTS.md | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md index 0ef8ded9..4274692d 100644 --- a/.agents/skills/pdfrest-client-api/SKILL.md +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -115,6 +115,17 @@ Follow `TESTING_GUIDELINES.md` and the live-test requirements in `AGENTS.md`. - Cover default and non-default options, accepted literals, numeric bounds, MIME/cardinality/dependency rules, and every meaningful response attribute. Extend a shared validation suite when a rule applies to a model family. +- For a payload containing a discriminated JSON-object union, add a direct + serialization assertion for every discriminator and distinct sync/async client + tests that send each form. Parameterize all `ge`/`gt`/`le`/`lt` constraints at + their legal boundaries and immediately-invalid neighbors. Test MIME and + one-resource cardinality failures through both clients with a transport that + fails if a request is attempted. In both timeout-customization tests, capture + `request.extensions["timeout"]` and assert every component. +- When optional per-object metadata requires a request-level flag, cover both + the valid dependency combination and the locally rejected missing/false flag; + use `extra_body` in live tests to verify an invalid combination reaches the + server and raises the expected API exception. - Live tests upload deterministic fixtures first, execute with the returned `PdfRestFile` resources, and assert IDs, filenames, MIME types, output count, warnings, and endpoint-specific behavior. Use `extra_body` or `extra_query` to diff --git a/AGENTS.md b/AGENTS.md index 47b632d9..a153393c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -229,6 +229,15 @@ assertion through `PdfRestClient` and `AsyncPdfRestClient` so sync/async behaviour stays independently verifiable. +- For endpoints that accept discriminated JSON objects, test every discriminator + through both client transports and assert the model's exact JSON-ready + serialization directly. Parameterize each constrained field at its accepted + boundaries and immediately outside them; test MIME and single-resource + cardinality failures through both transports with a transport that fails if + local validation does not short-circuit. When a helper accepts `timeout`, + capture `request.extensions["timeout"]` in both customization tests and assert + every timeout component. + - When endpoints may raise `PdfRestErrorGroup` (or any future pdfRest-specific exception groups), assert them with `pytest.RaisesGroup`/`pytest.RaisesExc`, and use the `check=` hook to confirm the outer group is the expected class so From 014a6b7b5747609ed686ee272aeebd062bb3600e Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Sun, 23 Aug 2026 08:37:11 -0500 Subject: [PATCH 03/10] pdfrest-client-api: Document unified PDF color inputs - Define the public color input and internal wire-field routing pattern - Require RGB, CMYK, and invalid-channel coverage Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 9 +++++++++ AGENTS.md | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md index 4274692d..d0737ed1 100644 --- a/.agents/skills/pdfrest-client-api/SKILL.md +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -85,6 +85,12 @@ validation and turns them into the exact pdfRest wire contract. - Use `validation_alias` for accepted SDK input names and `serialization_alias` for the server field name. Serialize uploaded `PdfRestFile` values to the required ID field with the existing serializers. +- When one semantic color is represented by separate RGB/CMYK wire fields, + expose a single public `_color: PdfColor` input. Route it by tuple + channel count with a `BeforeValidator` on internal RGB/CMYK fields that share + the public `validation_alias` but have distinct serialization aliases. Do not + expose the server's `*_rgb` or `*_cmyk` field names in public methods or + TypedDicts. - Validate MIME types and resource cardinality before a request. For payload validation failures, raise Pydantic `ValidationError` via `ValueError` or `AssertionError`, not `TypeError`. @@ -112,6 +118,9 @@ Follow `TESTING_GUIDELINES.md` and the live-test requirements in `AGENTS.md`. if called. - Test payload models directly as well as client methods: accepted ergonomic shapes and the exact alias-based serialization must both be covered. +- For unified color inputs, assert RGB and CMYK tuples each serialize to only + their corresponding wire field, and reject unsupported channel counts before a + request is sent. - Cover default and non-default options, accepted literals, numeric bounds, MIME/cardinality/dependency rules, and every meaningful response attribute. Extend a shared validation suite when a rule applies to a model family. diff --git a/AGENTS.md b/AGENTS.md index a153393c..d39eb6b5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -168,6 +168,12 @@ remain the default approach. Add custom validators only when they provide behavior native constraints cannot (for example, parsing alternate wire formats or enforcing cross-field dependencies). +- When pdfRest exposes separate RGB/CMYK wire fields for one semantic color, + expose one public `_color: PdfColor` input instead of separate + `_color_rgb`/`_color_cmyk` inputs. Use a channel-count + `BeforeValidator` with shared `validation_alias` and distinct serialization + aliases to route three channels to RGB and four to CMYK; keep those wire-field + names internal to the payload model. - Keep `BeforeValidator`/`AfterValidator` helpers and field serializers short and shape-focused. They should primarily adapt nonconforming inputs or handle pdfRest wire quirks (for example, splitting comma-separated values or From a0b23245fa4f39d0c468d8c2e1fcc3f660288485 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Tue, 25 Aug 2026 14:36:29 -0500 Subject: [PATCH 04/10] pdfrest-client-api: Document uv version bumps - Require minor releases for new public SDK APIs - Use uv version commands instead of manual version edits Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 20 ++++++++++++++++++++ AGENTS.md | 2 ++ 2 files changed, 22 insertions(+) diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md index d0737ed1..1e77c5f8 100644 --- a/.agents/skills/pdfrest-client-api/SKILL.md +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -28,18 +28,38 @@ an existing helper, such as an added server parameter. Name a helper for the user outcome, not the path or OpenAPI operation ID. +## Versioning new APIs + +Adding a public API is a feature release and requires a minor-version bump. +Before editing, compare `pyproject.toml` with the current branch's base and +commits: + +- If this branch has not changed the project version, increment the minor + version and reset the patch component to `0` with `uv version --bump minor`. + +- If this branch includes only a patch-version change, replace that patch bump + with the appropriate next minor version and reset the patch component to `0` + with `uv version --bump minor`. + +- If the branch already includes the required minor-version bump, retain it. Do + not make a major-version change unless the user explicitly requests one. + - Use `snake_case` and lead with a precise action: `convert_`, `add_`, `remove_`, `change_`, `flatten_`, `extract_`, `query_`, `preview_`, `apply_`, `merge_`, `split_`, `zip_`, or `unzip_`. + - Name the material source/result or effect: `convert_html_to_pdf`, `add_text_to_pdf`, and `merge_pdfs`. Include both sides of a conversion. + - Split kitchen-sink routes into distinct helpers when source type, output, validation, or user workflow differs. `/pdf` correctly maps to helpers such as `convert_office_to_pdf`, `convert_html_to_pdf`, and `convert_url_to_pdf`, not one mode-driven endpoint wrapper. + - Use a qualifier only when it changes the contract or workflow, such as `preview_redactions` then `apply_redactions`, or text versus image watermarking. + - Preserve all existing public method names. Do not rename a method merely to fit this standard. diff --git a/AGENTS.md b/AGENTS.md index d39eb6b5..44572315 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,8 @@ pushing. - `uv run pytest` — execute the suite with the active interpreter. - `uv build` — produce wheels and sdists identical to the release workflow. +- `uv version --bump ` — update the project version; use this + command instead of editing the version manually in `pyproject.toml`. - `uvx nox -s tests` — create matrix virtualenvs via nox and execute the pytest session. - `nox` executes pytest sessions with built-in parallelism; when invoking pytest From 34b5aa69e5312571f8aa990aad874aefbb66239e Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Tue, 25 Aug 2026 15:31:53 -0500 Subject: [PATCH 05/10] pdfrest-client-api: Define Jira branch setup - Normalize Jira-based feature branch names - Define upstream tracking and detached-HEAD behavior Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md index 1e77c5f8..3eff8854 100644 --- a/.agents/skills/pdfrest-client-api/SKILL.md +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -24,6 +24,25 @@ an existing helper, such as an added server parameter. missing, a required fixture cannot be obtained, or a compatible SDK adaptation cannot be made. +## Jira branch setup + +When the prompt handed to this skill mentions a Jira work item, create a branch +before making substantive edits. + +- Derive the name as `pdfcloud--`, using the Jira key + lowercased and a concise lowercase, hyphen-separated description. For example, + `PDFCLOUD-6233 Add PDF outlines` becomes `pdfcloud-6233-add-pdf-outlines`. +- Use `upstream/main` as the branch's upstream when an `upstream` remote exists. + If `origin` is the only remote, use `origin/main` instead. Do not silently + select a fork remote when another remote configuration is ambiguous. +- When HEAD is attached, create the branch from the current commit, then set its + upstream explicitly with `git branch --set-upstream-to=/main`. +- When HEAD is detached, first fetch the selected remote's `main` branch, then + create the branch from `/main` and set that same ref as its upstream. +- Do not overwrite an existing branch or discard local changes. Stop and ask the + user for direction if the derived name already exists or the remote/main ref + cannot be resolved. + ## Public API design Name a helper for the user outcome, not the path or OpenAPI operation ID. From a800ecfbed132ff8e2cbff639f46fa4e0a1edcc4 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Tue, 25 Aug 2026 17:15:40 -0500 Subject: [PATCH 06/10] CONTRIBUTING.md: Document client API skill usage - Show the required skill invocation and Jira key - Describe the PDFCloud-API checkout prerequisite Assisted-by: Codex --- CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ece320d9..98d8c17d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,6 +22,26 @@ uv run pre-commit install uv run python -c "import pdfrest; print(pdfrest.__version__)" ``` +## Adding or evolving a client API + +When asking Codex to add a documented pdfRest endpoint or a compatible parameter +to an existing endpoint, begin the prompt with the repository-local +`$pdfrest-client-api` skill. Include the Jira work item key when one exists. The +PDFCloud-API checkout and its documented OpenAPI operation must be available +before using the skill. Prefer adding the neighboring PDFCloud-API directory to +the Codex project so the skill can read the contract directly. For example: + +```text +$pdfrest-client-api PDFCLOUD-6233: Add the documented PDFCloud-API operation +for ... +``` + +The skill uses the PDFCloud-API OpenAPI specification as the contract; keeps the +sync and async clients aligned; puts wire serialization and validation in +Pydantic payload models; preserves existing caller behavior; and requires +focused unit coverage plus matching live endpoint tests. It also handles the +versioning required for a newly added public API. + ## Code quality checks Run these before opening a PR: From 4b863c2a5e4ba6fc44dee17b2cade02cd89060bd Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Tue, 25 Aug 2026 17:46:42 -0500 Subject: [PATCH 07/10] pdfrest-client-api: Improve generated API reference guidance - Require source docstrings for public structured input contracts - Verify generated union references and rendered field details Assisted-by: Codex --- .agents/skills/pdfrest-client-api/SKILL.md | 34 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/.agents/skills/pdfrest-client-api/SKILL.md b/.agents/skills/pdfrest-client-api/SKILL.md index 3eff8854..bea4c5ca 100644 --- a/.agents/skills/pdfrest-client-api/SKILL.md +++ b/.agents/skills/pdfrest-client-api/SKILL.md @@ -181,7 +181,35 @@ Follow `TESTING_GUIDELINES.md` and the live-test requirements in `AGENTS.md`. - Update the API guide, public exports, and user-facing examples when the new capability or parameter changes discoverability or usage. +### Generated API-reference contracts + +The API reference is generated from the public source. Keep request-shape +documentation with its types; do not hand-copy a shape schema into Markdown. + +- For every public `TypedDict` accepted by a client helper, write a Google-style + `Attributes:` docstring that explains every field: required versus optional + status, accepted values, units or coordinate origin where relevant, declared + bounds, and any request-level dependency. Derive those details from the + Pydantic payload model and OpenAPI contract; do not guess missing behavior. +- For a public union alias, declare it as `Name: TypeAlias = ...` and add its + PEP 258 attribute docstring immediately after the assignment. The docstring + must identify the union members and link to the consuming client helper. +- Public types are re-exported through `pdfrest.types`. Verify that the rendered + reference resolves the re-export to its source union and member types. A + self-reference such as `PdfAddShapeObject = PdfAddShapeObject` is a rendering + defect, not acceptable documentation. +- Do not enable broad rendering of undocumented module attributes merely to + expose a public alias. That also exposes convenience constants such as + `ALL_*`, which are not API-reference contracts. Document the alias at its + source instead. +- Build the docs with `uv run mkdocs build --strict`. For a newly documented + union or structured input, inspect the generated API-reference HTML (or make + an equivalent focused assertion) to confirm the union members, its docstring, + and field-level descriptions render; links from the client method signature + must target that entry. + Run targeted unit and live tests first, then the relevant Ruff and type checks. -Run the full pytest suite and `uvx nox -s tests` when practical. Report the -OpenAPI operation inspected, files changed, checks run, checks skipped, and any -live-validation limitation. +Run the full pytest suite and `uvx nox -s tests` when practical. For API +reference changes, also run the strict docs build. Report the OpenAPI operation +inspected, files changed, checks run, checks skipped, and any live-validation +limitation. From e7bfc49b52ac95dba4eca228a1ae58c916dbb314 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 26 Aug 2026 17:04:35 -0500 Subject: [PATCH 08/10] AGENTS.md: Add runnable example guidance - Define PEP 723 metadata, layout, resource, and docstring conventions - Document local and matrix validation for live examples Assisted-by: Codex --- AGENTS.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 44572315..ab83f062 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -326,6 +326,65 @@ to `.env`) in temporary scripts to drive the in-flight client against live endpoints and capture responses for test data and assertions. +## Example Guidelines + +- Every new public endpoint/helper must include a runnable example under + `examples/`. Group examples by capability in an endpoint-oriented directory + such as `examples/extract_text/`, and use a descriptive `*_example.py` + filename. Add the script to the inventory in `examples/README.md` and update + relevant docs links or usage guidance when the new capability changes + discoverability. + +- Make each example a standalone uv script. Its first lines must be a PEP 723 + metadata block in the single-line form understood by the Nox example discovery + code: + + ```python + # /// script + # requires-python = ">=3.10" + # dependencies = ["pdfrest", "python-dotenv"] + # /// + ``` + + Set `requires-python` to the widest supported range the example actually + supports and list every third-party import in `dependencies`. Keep the block + first (do not put a shebang above it), because `noxfile.py` reads metadata + starting at line one. PEP 723 metadata gives `uv run` an isolated environment; + do not rely on undeclared project or development dependencies. + +- Follow the metadata with a module docstring that states the user outcome, + lists the important upload/API/output steps, and gives the exact command to + run from the repository root, for example + `uv run examples/extract_text/extract_pdf_text_example.py`. Name required + environment variables, input files, and any expected setup in that docstring. + +- Prefer deterministic, redistributable inputs under `examples/resources/` and + resolve them relative to `Path(__file__)`, never the caller's working + directory. Reuse a suitable checked-in resource when possible. Before adding a + new binary or specialized input, confirm its provenance, redistribution + suitability, and expected API behavior; ask the contributor for the required + asset when those cannot be established. + +- Examples exercise the real service, load `PDFREST_API_KEY` from the + environment (optionally through `python-dotenv`), upload local inputs through + `client.files.create_from_paths`, and use client context managers. Keep the + flow short and instructional while printing enough typed response data for a + user and CI to confirm success. + +- Put interpreter-specific alternatives beside the base script as + `python-X.Y/.py`, with a local `ruff.toml` extending the parent + configuration, only when syntax or compatibility requires a distinct script. + The base script remains the default for newer supported interpreters. + +- Validate a new or changed example directly with `uv run