Skip to content

Examples library — .altair/examples/ + MCP tools for idiomatic patterns #76

@tonydspaniard

Description

@tonydspaniard

Goal

Ship a curated, browsable idiomatic-examples library under .altair/examples/ plus MCP tools that let agents discover and read them. Examples are short, runnable, framework-idiomatic snippets covering common scenarios — the "how do you do X here?" reference an agent (or human) reaches for instead of grepping source.

Why

The MCP server + manifests answer "what exists." They don't answer "what's the idiomatic way to do this here." When an agent doesn't know how to wire two packages together — say, an HTTP endpoint that dispatches a queue job after successful persistence — it currently has to read source, infer conventions, and risk producing non-idiomatic code. An examples library closes that loop:

  • Agents browse a known list of canonical patterns
  • Examples are small (~30 lines each), focused, and tested — they're never out of date
  • Each example carries metadata: which packages it uses, what scenario it covers, what gotchas it documents

This is the closest thing to a "stdlib of patterns" the framework can have.

Library layout

.altair/examples/
├── index.json                              # generated index of all examples
├── http/
│   ├── basic-endpoint.md
│   ├── endpoint-with-auth.md
│   ├── endpoint-with-pagination.md
│   ├── endpoint-with-file-upload.md
│   ├── responder-with-multiple-content-types.md
│   └── middleware-custom-pipeline.md
├── persistence/
│   ├── crud-repository.md
│   ├── transactional-write.md
│   ├── batch-insert-with-skip-locked.md
│   └── entity-with-soft-delete.md
├── messaging/
│   ├── dispatch-on-success.md
│   ├── retry-policy.md
│   └── outbox-pattern.md
├── happen/
│   ├── domain-event-on-create.md
│   └── psr14-bridge.md
├── auth/
│   ├── jwt-validation.md
│   └── basic-auth-with-rate-limit.md
└── testing/
    ├── action-integration-test.md
    └── message-handler-test.md

Each example is a Markdown file with a structured header so the index can be generated:

---
title: Endpoint that dispatches a job after successful persistence
scenario: Run an async side effect (welcome email) after a domain operation succeeds.
packages: [http, persistence, messaging]
since: 2.0.0
tested_by: tests/Examples/HttpDispatchJobTest.php
---

# Endpoint that dispatches a job after successful persistence

When the action completes, you want a queue job to fire — but only if persistence
committed. The pattern: dispatch the job *inside* the same UnitOfWork-aware
transaction boundary that persisted the entity.

```php
final readonly class CreateUserAction
{
    public function __construct(
        private CreateUser $createUser,
        private CreateUserResponder $responder,
    ) {}

    public function __invoke(ServerRequestInterface $request): ResponseInterface
    {
        $payload = ($this->createUser)($request->getParsedBody());
        return ($this->responder)($request, new Response(), $payload);
    }
}

final readonly class CreateUser
{
    public function __construct(
        private UserRepository $users,
        private UnitOfWorkInterface $uow,
        private MessageBusInterface $bus,
    ) {}

    public function __invoke(array $input): PayloadInterface
    {
        $user = User::register($input['email'], $input['password']);

        $this->users->save($user);
        $this->bus->dispatch(new SendWelcomeEmail($user->id, $user->email));
        $this->uow->flush(); // commits both DB write + outbox row atomically

        return (new Payload())->withStatus(201)->withOutput(['user' => $user]);
    }
}

Gotchas

  • Dispatch the message before $uow->flush(). The outbox stores it; the flush commits both.
  • Without an outbox-aware transport, "after persistence" is best-effort — the job can run if the DB commit fails on rollback.
  • See .altair/examples/messaging/outbox-pattern.md for the outbox transport setup.

The `tested_by` field is mandatory — every example links to a real test under `tests/Examples/`. The test runs the snippet's code end-to-end, so an example that drifts from working code fails CI.

## MCP tools

| Tool | Description | Inputs |
|---|---|---|
| `framework__list_examples` | All examples, optionally filtered by package or scenario keyword | `package?: string, scenario?: string` |
| `framework__read_example` | Full Markdown content of one example by ID (the file path) | `id: string` |
| `framework__search_examples` | Free-text search across scenario + title + body | `query: string` |

Agents can call `framework__list_examples({ package: "messaging" })` and pick the right pattern instead of inventing one.

## CLI surface

```bash
bin/altair examples list                       # human table
bin/altair examples list --package=http        # filter
bin/altair examples show http/basic-endpoint   # render one to stdout
bin/altair examples search "outbox"
bin/altair examples test                       # run every example's tested_by file
bin/altair examples index                      # regenerate .altair/examples/index.json

Shape

src/Altair/Examples/
├── Cli/
│   ├── ListCommand.php
│   ├── ShowCommand.php
│   ├── SearchCommand.php
│   ├── TestCommand.php
│   └── IndexCommand.php
├── Mcp/
│   ├── ListExamplesTool.php
│   ├── ReadExampleTool.php
│   └── SearchExamplesTool.php
├── Library/
│   ├── Example.php                # value object: id, title, scenario, packages, body, tested_by
│   ├── ExampleParser.php          # YAML frontmatter + Markdown body
│   ├── ExampleRepository.php      # filesystem-backed lookup
│   └── IndexBuilder.php
└── composer.json

.altair/examples/                  # ships with the framework's skeleton
└── (the examples library content above)

Authoring discipline

Every example PR must:

  • Include the YAML frontmatter (validated by CI)
  • Provide a tests/Examples/<Name>Test.php that runs the snippet
  • Be under 80 lines of code (forced concision; longer = it's a feature, not an example)
  • Use only univeros/* packages and standard PSR contracts — no third-party deps that aren't already framework deps

Acceptance criteria

  • At least 30 examples ship in v1 across all framework packages (concrete list to be finalised in PR; ~3 per major package)
  • Every example has a tested_by test that asserts the snippet works
  • bin/altair examples test runs every linked test; CI uses this to keep the library honest
  • framework__list_examples / read_example / search_examples MCP tools work against the library
  • Index is regenerated deterministically (sorted, no timestamps); committed alongside content
  • Skeleton (univeros/skeleton + bin/altair new — zero-to-running project bootstrap #73) bundles the examples directory by default
  • Tests:
    • ExampleParserTest — frontmatter validation, malformed inputs rejected
    • ExampleRepositoryTest — filter by package, by scenario keyword
    • IndexBuilderTest — deterministic output
    • End-to-end MCP integration test

Out of scope

  • A web UI for browsing examples (Markdown renders fine on GitHub and inside agent context)
  • Multi-language translations
  • "Cookbook" long-form recipes (different content type; can land later)
  • Versioning examples per framework version (we tag the framework; examples track the tip)

Dependencies

Why this is the highest-impact gap

Agents are pattern-matchers. Give them 30 canonical patterns to match against and their output quality jumps materially — fewer hallucinated APIs, more idiomatic code, less rework. Low effort, huge return.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions