Examples

Every snippet here is lifted from real, maintained sources — synthetic recipe fixtures under recipes/, component READMEs, or conformance tests — and cites where it lives. An example that was never executed is documentation that lies.

Full composition recipes are synthetic on purpose (fictional product shapes). Machine-readable metadata lives in catalog.json. Agents should fetch the catalog rather than inventing package sets — these examples assume your agent has the assembly skill and catalog installed; the get-started page covers that setup.

Recipe index

Recipes with green fixtures are CI-tested and safe to quote. Pending intents stay metadata-only until a fixture lands.

Pending / deferred recipe intents
  • durable-auth-rate-limits — pending
  • health-public-liveness — pending
  • logger-tee-composition — pending
  • inbound-webhook-receipts — none (awaits package publication)
  • support-queue-slice — none (awaits package publication)

Accounts on a Cloudflare-shaped host

Northshelf Branch (synthetic): first-party Identity with passkeys and email codes, Sessions, durable rate limits, and Authorization claims projection. Production hosts inject @pegma/storage-cloudflare-d1; the fixture tests with memory.

export function createNorthshelfComposition(
  options: NorthshelfCompositionOptions,
): NorthshelfComposition {
  const store = options.store;
  // Live clock by default so production-shaped hosts expire challenges/sessions.
  // Tests inject fixedClock when they need deterministic timestamps.
  const clock = options.clock ?? systemClock;
  const emailCodeProtector = createHmacEmailCodeProtector(
    decodeEmailCodeSecret(options.emailCodeSecretBase64),
  );

  const registrationLimiter = durableLimiter(
    store,
    'northshelf-passkey-registration',
    10,
    5 * 60_000,
  );
  const authenticationLimiter = durableLimiter(
    store,
    'northshelf-passkey-authentication',
    30,
    5 * 60_000,
  );
  const emailCodeRequestLimiter = durableLimiter(
    store,
    'northshelf-email-code-request',
    5,
    10 * 60_000,
  );
  const emailCodeVerificationLimiter = durableLimiter(
    store,
    'northshelf-email-code-verification',
    10,
    10 * 60_000,
  );

  const identity = createIdentity({
    store,
    issuer: NORTHSHELF_RP.issuer,
    rpName: NORTHSHELF_RP.rpName,
    rpID: NORTHSHELF_RP.rpID,
    origins: [...NORTHSHELF_RP.origins],
    registrationLimiter,
    authenticationLimiter,
    emailCodeProtector,
    emailCodeRequestLimiter,
    emailCodeVerificationLimiter,
    clock,
  });

  const sessions = createSessionStore(store, {
    clock,
    ...(options.logger === undefined ? {} : { logger: options.logger }),
  });

  const mailWorker = identity.createMailWorker({
    workerId: options.mailDelivery.workerId ?? 'northshelf-identity-mail',
    provider: options.mailDelivery.provider,
    reconciliation: options.mailDelivery.reconciliation,
    renderer: options.mailDelivery.renderer,
    leaseMilliseconds: 30_000,
    acceptedCallbackMilliseconds: 5 * 60_000,
  });

  return Object.freeze({
    store,
    identity,
    sessions,
    mailWorker,
    registrationLimiter,
    authenticationLimiter,
    emailCodeRequestLimiter,
    emailCodeVerificationLimiter,
    emailCodeProtector,
    clock,
    identityLinkFromClaims: identityLinkKeyFromVerifiedIdentityClaims,
  });
}

Source: recipes/cf-passkey-accounts/composition.ts

Storage + audit + mail outbox in one transaction

Yard Loan (synthetic): inventory mutation, audit row, and mail job commit together in a single-partition transact. Audit and Mail own no store — the host collection is the atomic boundary.

export async function checkoutEquipment(
  composition: YardLoanComposition,
  input: CheckoutInput,
): Promise<CheckoutResult> {
  const { deskId, partition, records, audit, mail } = composition;

  const outcome = await records.transact(partition, [
    {
      action: 'insert',
      value: {
        kind: 'loan',
        deskId,
        itemId: input.itemId,
        borrowerPrincipalId: input.borrowerPrincipalId,
        status: 'checked_out',
      },
    },
    audit.action({
      id: input.auditEventId,
      occurredAt: input.occurredAt,
      actor: {
        kind: 'principal',
        principalId: input.actorPrincipalId,
      },
      action: 'yard_loan.item.checked_out',
      subject: input.itemId,
      details: {
        borrower: input.borrowerPrincipalId,
      },
    }),
    mail.action({
      partition,
      id: input.mailJobId,
      recipientRef: input.borrowerPrincipalId,
      contentRef: `yard_loan.checkout:${input.itemId}`,
      createdAt: input.occurredAt,
    }),
  ]);

  if (!outcome.committed) {
    return { committed: false, reason: outcome.reason };
  }
  return { committed: true };
}

Source: recipes/storage-audit-mail-outbox/composition.ts

Declare what you keep

A component declares a collection — name, key, codec — and never learns what the database is. The codec is where your types meet flat storage; the same declaration runs over the in-memory store in tests and the Azure Tables adapter in production.

import { defineCollection, createMemoryStore } from "@pegma/storage-core";

interface Session {
  readonly id: string;
  readonly principalId: string;
  readonly expiresAt: string;
}

const sessions = defineCollection<Session>({
  name: "sessions",
  key: (session) => ({ partition: "session", id: session.id }),
  codec: {
    encode: (session) => ({ ...session }),
    decode: (record) => ({
      id: String(record["id"]),
      principalId: String(record["principalId"]),
      expiresAt: String(record["expiresAt"]),
    }),
  },
});

const store = createMemoryStore();
const collection = store.collection(sessions);

Source: storage-core README

Change a record safely

update reads, asks your decider what to write, and writes — re-running the decider against freshly read state whenever someone else got there first. A staleness check inside the decider is re-evaluated on every conflict; a check performed before the call is a check against state that may no longer be true.

const result = await collection.update(key, (current) => {
  if (current === null) return { action: "keep" };
  if (current.version >= incoming.version) return { action: "keep" };
  return { action: "write", value: applyEvent(current, incoming) };
});

Source: storage-core README

Notify without pretending durability

Spine's in-process bus is the lossy tier on purpose — cache invalidation and metrics, never anything that must survive a crash. Durable events belong in a storage-backed outbox, and the choice between tiers is visible in the code rather than left to memory.

import { createEventBus, defineEvent, type PrincipalId } from "@pegma/spine";

interface AccountCreated {
  readonly principalId: PrincipalId;
  readonly email: string;
}

// Declared in a component's contracts package and exported as a constant, so
// publishers and subscribers are checked against the same type.
const AccountCreated = defineEvent<AccountCreated>("account.created");

// Wired once at the host's composition root.
const bus = createEventBus();

bus.subscribe(AccountCreated, (envelope) => {
  welcomeCache.invalidate(envelope.payload.principalId);
});

Source: spine README