Skip to content

Surface Spectral's features so AI agents use them - #21

Merged
andreashasse merged 3 commits into
mainfrom
claude/zealous-yonath-1c1be7
Jun 17, 2026
Merged

andreashasse merged 3 commits into
mainfrom
claude/zealous-yonath-1c1be7

Conversation

@andreashasse

@andreashasse andreashasse commented Jun 17, 2026 •

Copy link
Copy Markdown
Owner

Why

AI agents building APIs with PhoenixSpectral consistently underuse Spectral's features — string/length/pattern constraints, field aliases, custom codecs, the built-in date/time codecs. The cause is discoverability, not capability: an agent acts on what's in front of it, and PhoenixSpectral's docs mention Spectral only vaguely, link to its GitHub repo (not hexdocs), never enumerate what's available, and the example demonstrates only a subset. So agents hand-roll validation that Spectral does declaratively.

What changed

1. README — feature reference + hexdocs links

  • New "Going further with Spectral" section: a "Want to… → use Spectral's…" table mapping each capability to a hexdocs link, plus a worked type_parameters constraint example. Puts the menu directly in the agent's context.
  • All Spectral/spectra links re-pointed from github.com/... to hexdocs.pm/... (with section anchors). Agents browsing hexdocs follow same-host links far more readily than jumping to GitHub.

2. Example app — demonstrates declarative validation via type_parameters: %{min_length: 2, max_length: 50} on a named name type (the single most underused feature), with a test proving a too-short name returns 400. The example is the most-copied artifact, so agents imitate it.

3. Moduledocs — pointers on PhoenixSpectral and PhoenixSpectral.Controller (the hexdocs pages agents land on first) noting that schemas are derived from Spectral types, using backticked Spectral.* refs that ExDoc auto-links into Spectral's docs.

4. Packaging — a Spectral cross-link added to the Hex package links. Version bumped to 0.6.1 (docs-only patch release; see CHANGELOG).

Review history

An earlier revision added an AGENTS.md agent entry point and a "Powered by Spectral" admonition in the controller moduledoc. Both were removed during review — the maintainer found the framing leaned too hard on "this is a thin shell, the real power is elsewhere." The remaining changes carry the feature pointers without that delegation framing.

Design note

I deliberately enumerate-and-link rather than duplicate Spectral's docs into PhoenixSpectral — duplication drifts out of sync as Spectral evolves.

Verification

  • make ci (compile, test, credo, dialyzer, format) — passes, 0 dialyzer errors.
  • cd example && mix test — 14 pass, including the new min_length constraint test.

Note: no behavior change to the library itself — this is docs, one example type/test, and packaging metadata.

AI agents building APIs with PhoenixSpectral underuse Spectral's
capabilities because the library's docs never enumerate them, link only
to GitHub rather than hexdocs, and the example demonstrates only a
subset. Agents act on what's in front of them, so the fix is
discoverability, not code.

- README: add a "Going further with Spectral" feature-reference table
  (string constraints, field aliases, only, struct defaults, enums,
  codecs, type docs) with hexdocs links and a worked type_parameters
  example; re-point all Spectral links from GitHub to hexdocs.
- Add AGENTS.md: an agent-facing "I'm tempted to... -> use this instead"
  map, wired into ExDoc extras and the hex :files so it ships; tells
  downstream maintainers to copy it into their own AGENTS.md.
- Example: demonstrate declarative validation via type_parameters
  string constraints on a named type, with a test proving a too-short
  name returns 400.
- Moduledocs: add "Powered by Spectral" callouts with auto-linked
  Spectral.* refs on the pages agents land on first.
Comment thread lib/phoenix_spectral/controller.ex Outdated
Phoenix `(conn, params)`. Request data is decoded and validated against your typespecs,
and responses are encoded automatically.

> #### Powered by Spectral {: .info}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the verbose admonition with one plain sentence pointing at the Spectral docs. Fixed in fa381a5.

Comment thread example/lib/example/types.ex Outdated
Comment on lines +88 to +91
# A named type with `type_parameters` string constraints. No custom codec is
# needed: Spectral enforces min/max length (and `pattern`, `format`) on both
# decode and encode, and emits minLength/maxLength into the OpenAPI schema.
# A name shorter than 2 or longer than 50 characters fails with a 400.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is too long.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimmed to a single line. Fixed in fa381a5.

Comment thread AGENTS.md Outdated
@@ -0,0 +1,38 @@
# AGENTS.md

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe a little bit to much focus on delegating to spectral.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — removed AGENTS.md entirely (and its mix.exs wiring). The README/example/moduledoc changes carry the feature pointers without the heavy delegation framing. Fixed in fa381a5.

Comment thread README.md Outdated
| Accept an enum from a path/query param (e.g. `?role=admin`) | an atom-union type `:: :admin \| :user`, decoded via the `binary_string` format | [Data Serialization API](https://hexdocs.pm/spectral/readme.html#data-serialization-api) |
| Serialize `DateTime`, `Date`, or `MapSet` | the built-in codecs (registered automatically) | [Built-in Codecs](https://hexdocs.pm/spectral/readme.html#built-in-codecs) |
| Encode/decode a domain type with custom rules (prefixed IDs, money, etc.) | `use Spectral.Codec` | [Custom Codecs](https://hexdocs.pm/spectral/readme.html#custom-codecs) |
| Reuse one codec across types with different config | `spectral type_parameters: …` read as the codec's `params` argument | [Codec-specific configuration](https://hexdocs.pm/spectral/readme.html#codec-specific-configuration) |

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to highlight this specific feature as I think it was a misstake.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the codec-specific-configuration row from the table. The string-constraints use of type_parameters stays, since that wasn't flagged — let me know if you'd rather drop that too. Fixed in fa381a5.

- Remove AGENTS.md and its mix.exs wiring — too much focus on
  delegating to Spectral (reviewer feedback).
- Simplify the Controller moduledoc note from a verbose admonition
  to one clear sentence.
- Trim the overlong type_parameters comment in the example to one line.
- Drop the "codec-specific configuration" row from the README feature
  table — maintainer considers type_parameters-as-codec-params a
  mistake and doesn't want it highlighted.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves discoverability of Spectral features within PhoenixSpectral by expanding documentation, updating links to Spectral’s HexDocs, and updating the example app to demonstrate type_parameters string constraints (with a test).

Changes:

  • Expanded README with a “Going further with Spectral” capability→link reference table and updated Spectral/spectra links to HexDocs.
  • Added “powered by Spectral” pointers in key moduledocs to steer readers toward Spectral’s type-level features.
  • Updated the example app to use a named name() type with type_parameters min/max length constraints, plus a test asserting a too-short name returns 400.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Adds Spectral feature reference section + HexDocs links and example constraint snippet.
mix.exs Bumps version to 0.6.1 and adds a Hex package link to Spectral docs.
lib/phoenix_spectral/controller.ex Moduledoc callout pointing readers to Spectral docs for type shaping features.
lib/phoenix_spectral.ex Moduledoc callout emphasizing schemas are derived from Spectral types.
example/lib/example/types.ex Introduces name() type with type_parameters constraints and uses it in UserInput.
example/test/example_test.exs Adds regression test asserting min-length constraint yields HTTP 400.
CHANGELOG.md Documents the 0.6.1 documentation + example updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mix.exs
@andreashasse
andreashasse merged commit 95ea976 into main Jun 17, 2026
4 checks passed
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.

2 participants