Release candidate — 1.0.0-rc.6
StitchAPI
Concepts

Principles

Progressive disclosure, atomic stitches, composition over configuration, and the other ideas that shape the API.

A handful of design principles explain why the API looks the way it does — why the smallest stitch is a bare string, why there is no central config object, and why the same definition answers to an agent. This page is the synthesis; each principle links to the surface that embodies it.

Why it's shaped this way

Progressive disclosure

Complexity is opt-in. A bare URL string is a working stitch; reach for more and the same call grows into a config object with extends for composition. Every capability (validation, auth, retries, observability) has a sane default and reveals its knobs only when you ask, so simple things stay one line and the depth is there when you need it.

import {  } from 'stitchapi';

// A string is a whole stitch.
const  = ('https://api.example.com/users');

// Grow into a config object when you want more than the default.
const  = ({
    : 'https://api.example.com',
    : '/users/{id}',
    : { : 3 },
});

Atomic stitches

A stitch is one endpoint at a time and nothing else — self-contained, with no spec to author, no client to generate, no config file to load, and no server to run. It needs only a URL and (optionally) an example response, which is why it reaches the spec-less long tail of internal and undocumented APIs that codegen never covers. The declaration is the runtime; there is nothing to commit, diff, and regenerate.

Composition over configuration

Cross-cutting concerns — baseUrl, auth, pick, retry, throttle, timeout — are named, shareable values you compose, not a central config object far from the call site. Nothing is inherited implicitly: no config file, no ambient defaults, no global a stitch silently reads. Everything that shapes a call was composed into it explicitly, so you can read one stitch and know exactly what it does. extends folds fragments into a stitch. You share a plain fragment instead of re-typing config, and a stitch is itself a composable value others can extend. (For a whole shared surface — shared runtime plus a trusted principal boundary — a seam owns the fragment instead.)

import {  } from 'stitchapi';

// A reusable fragment is just a plain object — no helper required.
const  = {
    : 'https://demo.stitchapi.dev',
    : { : 3, : [429, 503] },
};

// Fold the shared fragment into each stitch; it inherits baseUrl + retry.
const  = ({ : [], : '/users/{id}', : 'data' });

One source of truth

The product sells anti-drift discipline; the API holds itself to the same rule. Responses are validated on every live call, and differences from a committed contract surface as a leveled drift signal — error, warn, or info — instead of a silent undefined three layers downstream. The docs apply the principle to themselves: a fact lives in exactly one place — full type tables only in Reference, error remediation only in Errors & pitfalls — and everywhere else links to it rather than restating (and risking drift from) it.

Agent-native

An agent is a first-class caller, not an afterthought bolted on with a server. Three things follow. A stitch hands the caller a capability, not a credential: the secret resolves at call time and never reaches the caller, human or agent. Every call yields a typed event stream — start → progress → drift → result → done — so an agent gets structured, validated, traceable results instead of opaque bytes. And the agent surface is one code-mode tool the agent drives, not one tool per endpoint, which keeps its context frugal.

Browser-first

A stitch runs wherever fetch does — browser, edge, or Node. The call path leans on web-platform primitives only; capabilities that genuinely need a server — the file trace sink, the CLI, serve, MCP — are explicitly server-side surfaces rather than silent assumptions inside the core. Every feature is judged in the browser first: if it cannot work there, it ships beside the core, not inside it.

Pay only for what you import

Bundle size is part of the API contract, because the frontend pays for every byte. import { stitch } brings the engine and nothing else; adapters, stores, trace sinks, and the server-side surfaces are separate imports you reach for explicitly. A new capability either earns its place in the core entry or lives behind its own import — so an app never ships bytes for a CLI it will not run. The same frugality the event stream practices with an agent's context, the package practices with your bundle.

Concretely, the whole stitch entry is ~25 kB minified + gzipped (≈61 kB raw), and because every surface beyond http is a separate subpath import, a typical import { stitch } tree-shakes to ~20 kB. With zero runtime dependencies, that figure is the entire cost — not the tip of a transitive tree.

Contract, not dependency

Redis is not the only KV store, fetch is not the only transport, and Zod is not the only validator — so the package commits to none of them. Every integration point is a small contract — the HTTP adapter, the state store, trace sinks, auth strategies, Standard Schema validation — and core ships only the platform defaults: fetch, an in-memory store, console and file sinks. Anything vendor-shaped lives in its own package, built against the contract and proven by a conformance kit from stitchapi/testing, so swapping a vendor is a one-line import change, never a migration.

No side effects by default

Making the call is the only thing a stitch does to the world. The state a stitch keeps to do its job — throttle buckets, the cookie jar, cached tokens, the circuit-breaker counter — lives in memory, scoped to the process, and is gone when the process exits; nothing is persisted or shared across workers, and no trace is written to disk, unless you ask for it. State turns durable and shared the moment you hand a stitch a store: the same throttle becomes a distributed rate limit and the same session survives restarts and is shared across processes. Observability is the same opt-in — a stitch traces nothing until you pass trace: 'console', a fileSink, or your own sink. Persistence and sharing are config you reach for, never a default you inherit, which is what keeps a stitch safe to import and call anywhere. It is progressive disclosure applied to durability: ephemeral and isolated until you opt into more.

Declarative spelling

Every capability has a spelling that round-trips as plain JSON. Functions in config — hooks, transform, custom predicates — are sugar for the common cases, never the only way in. This is the agent-native principle applied to authoring: an agent cannot emit a closure over MCP, but it can emit data, and a stitch that is data can be stored, diffed, inferred from one example, and exported as a spec.

How it relates

  • Progressive disclosure runs from the stitch primitive through the full config object — the string and the config object are two altitudes of one call.
  • Atomic stitches are the stitch itself: one endpoint, no spec, no codegen, no server.
  • Composition over configuration is what extends expresses — a plain fragment is what it composes (a seam owns one for a whole shared surface).
  • One source of truth shows up at runtime as leveled drift, the same anti-drift rule this documentation follows.
  • Agent-native is spelled out across capability, not credential, the event stream, and the agent surfaces.
  • Browser-first is what installation promises — the package runs anywhere fetch does, with server-side capabilities kept to the CLI, HTTP serve, and MCP surfaces.
  • Pay only for what you import governs how those surfaces and the pluggable seams (adapters, stores, trace sinks) are packaged: explicit imports beside the core, never bytes inside it.
  • Contract, not dependency is visible at every seam — the pluggable adapters, stores, and Standard Schema validation — and made enforceable by the conformance kits.
  • No side effects by default is the in-memory store behind every stitch and the silent trace sink: opt into a shared store and the same throttle turns distributed and the same session is shared across workers; opt into a sink and the event stream lands on the console or disk.
  • Declarative spelling keeps every stitch agent-authorable: the config object is the canonical form.

See also

On this page