Skip to content

Repository files navigation

hydra

One API definition, many surfaces. Hydra projects a single, explicit api/operations.yaml onto three committed surfaces — CLI (clap), HTTP (axum), and MCP (tool schemas + stdio runtime) — so the same Rust operation implementation powers every interface without drift.

Extracted from iris's iris-codegen, generalized for reuse across TechGodHQ Rust projects. Born from a spike that evaluated (and rejected) macro-based inference layers; see iris's docs/spikes/server-less.md for the rationale. Hydra's rule: no name-based inference — everything is declared.

               api/operations.yaml          (single source of truth)
                        |
              cargo run -p hydra-codegen -- write
                        |
        +---------------+----------------+
        |               |                |
   generated/cli.rs  generated/http.rs  generated/mcp.json
        |               |                |
   clap structs     axum routes      tool schemas
        |               |                |
        +---------------+----------------+
                        |
            your operation dispatch (one function)

Crates

  • hydra-core — the API definition model (operations, parameters, locations, surface allowlists) and validation. No generation, no I/O.
  • hydra-codegen — the generator + hydra CLI (write / check). Per-project knobs live in hydra.yaml.
  • hydra-mcp-stdio — a minimal reusable MCP stdio server (JSON-RPC 2.0, newline-delimited) you hand your generated tool schemas and one dispatch closure.
  • examples/notes — a complete three-surface project. Copy it as a template.

Usage

  1. Describe operations in api/operations.yaml:
operations:
  - name: get_note
    description: Get a single note by ID.
    method: GET
    path: /notes/{note_id}
    read: true
    output_type: Note
    parameters:
      - name: note_id
        description: Note ID to fetch.
        type: string
        required: true
        location: path
  1. Add a hydra.yaml pointing generated handlers at your dispatch and state:
http_dispatch_fn: "crate::execute_operation_http"
http_state_type: "crate::AppState"
# Only needed if the definition has raw_request operations:
# http_raw_dispatch_fn: "crate::execute_operation_raw_http"
  1. Generate and commit:
cargo run -p hydra-codegen -- write   # writes generated/{cli.rs,http.rs,mcp.json}
cargo run -p hydra-codegen -- check   # CI guard: fails if artifacts are stale
  1. include! the generated files, implement one dispatch function, and wire your binaries. See examples/notes/src/lib.rs.

JSON batch operations

Hydra v0.2.0 can project a declared json body parameter to HTTP, MCP, and CLI. Declare the JSON Schema explicitly; Hydra embeds it in the MCP input schema and generates the HTTP route from the same operation. For a batch that needs a shell-friendly CLI representation, declare the representation rather than inferring one:

- name: ingest_batch
  description: Apply an ordered, replayable source batch.
  method: POST
  path: /ingest/batches
  read: false
  output_type: IngestReceipt
  parameters:
    - name: replay_key
      description: Stable idempotency key.
      type: string
      required: true
      location: body
    - name: events
      description: Ordered source events.
      type: json
      required: true
      location: body
      schema:
        type: array
        minItems: 1
        items: { type: object }
      cli:
        flag: event
        multiple: true

HTTP and MCP callers pass events as the declared JSON array. The generated CLI accepts repeated --event '<json object>' flags; the consumer's single dispatch function parses that explicit CLI representation before typed validation and persistence. Hydra does not own source-specific event models, batch hashing, idempotency, or transactions. examples/notes contains a tested ingest_batch reference operation and is the pattern Iris should use.

Security-scanner consumer boundary

examples/security-scan is a deliberately small, fixture-backed consumer reference. Its explicit run_security_scan operation projects to CLI, HTTP, and MCP, while the consumer—not Hydra—owns a typed SecurityScanner trait and the single dispatch function. The checked-in fixture only accepts fixture:demo-repo and the optional baseline profile. It never treats input as a command, filesystem path, or URL.

The fixture needs no configuration. A future live adapter must read only DEEPSEC_ENDPOINT (an absolute HTTPS URL) and DEEPSEC_TOKEN (a non-empty credential) from its environment. Neither belongs in source, generated output, logs, requests, or public errors. Consumer adapters must map private failures to the fixed public invalid_request, scanner_unavailable, or scan_failed error codes without serializing vendor details, credentials, headers, endpoints, or raw scanner output.

Raw-request (webhook) operations

Operations that must see the exact wire representation — signature-verified webhooks, for example — opt in with raw_request: true. The generated HTTP handler receives the raw body bytes and a header map instead of typed extraction, and dispatches to http_raw_dispatch_fn:

- name: receive_webhook
  description: Receive a signed webhook payload.
  method: POST
  path: /hooks/github
  read: false
  output_type: Value
  parameters: []
  surfaces: [http]
  raw_request: true

Rules: http must be the only listed surface, the operation is unary (no SSE), and body-location parameters are rejected — the raw bytes replace JSON body extraction. The header map lowercases names, drops non-UTF-8 values, and collapses repeated headers to the last value. Definitions without raw operations generate byte-identical output to before the flag existed.

Design rules

  • No inference. Method, path, parameter locations, and surface allowlists are declared. The generated router, schemas, and docs cannot disagree because none of them guess.
  • Validation is the product. hydra-core rejects path placeholders without parameters, duplicate names, read/POST mismatches, empty or duplicate surface lists, and reserved identifiers at generation time — not at runtime.
  • Generated code is committed and deterministic; check gates CI.
  • One dispatch function per project routes every surface to the same operation implementation. Business logic never duplicates per surface.
  • Selective projection via surfaces: [http, mcp] allowlists, with CLI command renames (cli_command:) when the public name should differ.

License

MIT.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages