Skip to content
Published alpha · next channelRead as Markdown

Mimlet for coding agents ​

Mimlet gives coding agents concrete building blocks for test data: typed patches, explicit validation, supported deterministic generation, coherent scenarios and checked replay. These capabilities can reduce the need to invent fixture structures and debugging workflows; no measured productivity or model-preference claim is implied.

Release status: published alpha, @mimlet/*@0.1.0-alpha.2 and hey-api-builders@3.0.0-alpha.2, available on npm's next channel. Follow Getting started for matching install commands or source development. Check the project's installed versions before applying an example.

Pick the smallest useful combination ​

  1. Read the project's existing schema and test framework; retain those choices.
  2. Use @mimlet/core for typed factory builders. For native creation/codecs or automatic generation, select the appropriate adapter.
  3. Decide whether the test needs encoded input or validated/decoded output.
  4. Set explicit session identities and seeds where supported. Capture a snapshot before the operation to reproduce it, or after it to resume from that point.
  5. Run the test and preserve its failure evidence. Inspect documented capabilities before substituting a factory or changing a schema.

An optional Mimlet skill packages this workflow. Install it only when the user requests it; it does not change project dependencies or install global tools automatically.

The alpha includes dedicated Zod and ArkType recipes. Use their typed factory helpers when input cannot be generated from JSON metadata; choose the explicit Zod async helpers for async refinements.

Build a fixture with native validation ​

ts
import Type from 'typebox';
import { fluent } from '@mimlet/core';
import { fromTypeBox } from '@mimlet/typebox';

const User = Type.Object({
  id: Type.String({ default: 'user-1' }),
  role: Type.Union([
    Type.Literal('reader'),
    Type.Literal('admin'),
  ]),
});

const users = fluent(fromTypeBox(User), ['id', 'role']);
export const admin = users.withRole('admin').buildValidated();

The override remains input-typed. With transforms/codecs, build() produces input and buildValidated() returns output. Use buildValidatedAsync() when the schema or factory requires asynchronous work. Don't hide failures by casting away types.

Preserve relationships ​

ts
import { createScenario, createSession } from '@mimlet/core';

export const checkout = createScenario({ name: 'checkout' })
  .node('customer', [], (_, session) => ({ id: `user-${session.sequence('id', 1)}` }))
  .node('lines', [], () => [{ quantity: 2, priceCents: 1500 }])
  .node('order', ['customer', 'lines'], ({ customer, lines }) => ({
    customerId: customer.id,
    totalCents: lines.reduce((sum, line) => sum + line.quantity * line.priceCents, 0),
  }));

export const shop = checkout.build(
  createSession({ seed: 42, fingerprint: 'checkout/v1', provider: 'my-test@1' })
);
// shop.order.customerId === shop.customer.id; shop.order.totalCents === 3000.

Change an upstream node or input parameter and let dependent nodes recalculate. Avoid independently replacing a foreign key or total that should follow another value.

Reproduce the failing operation ​

ts
import { createBuilder, createSession, restoreSession } from '@mimlet/core';
import type { GenerationSession } from '@mimlet/core';

const identity = { fingerprint: 'users/v1', provider: 'my-factory@1' };
const session = createSession({ ...identity, seed: 42 });
const users = createBuilder((run: GenerationSession) => ({ id: run.integer(1, 1000) }));

// Save before the failing operation to reproduce that operation.
export const before = session.snapshot();
export const first = users.build(session);
export const again = users.build(restoreSession(before, identity));
// first and again have the same id. Restoring checks the supplied identity.

Persist the snapshot as JSON when necessary. Preserve schema/configuration and provider identity; a mismatch is an error to investigate, not a reason to bypass replay validation. Arbitrary external I/O, clocks and factory side effects do not become deterministic merely because a session is seeded.

Shrink inputs while keeping the scenario coherent ​

ts
import * as fc from 'fast-check';
import { createScenario } from '@mimlet/core';
import { scenarioArbitrary, checkFixtureProperty } from '@mimlet/fast-check';

const identity = { fingerprint: 'basket/v1', provider: 'my-test@1' };
const cart = createScenario()
  .node('prices', [], () => [] as number[])
  .node('total', ['prices'], ({ prices }) => prices.reduce((sum, n) => sum + n, 0));
const baskets = scenarioArbitrary(
  fc.array(fc.integer({ min: 1, max: 100 }), { minLength: 1, maxLength: 10 }),
  (prices) => cart.override('prices', () => prices),
  { ...identity, seed: 42 }
);

// Deliberately false property: inspect its report without making the example fail CI.
export const report = checkFixtureProperty(baskets, (basket) => basket.total < 5, {
  identity,
  seed: 12345,
  numRuns: 100,
});
// Shrinking recomputes total from prices; the minimal counterexample is { prices: [5], total: 5 }.
// In a real test, use assertFixtureProperty so a failed property fails the test.

Use the report's replay record with replayFixtureProperty and the same property, arbitrary, engine and identity. Use assertFixtureProperty in tests that must fail on a counterexample. Review the fast-check contract before combining native arbitraries with custom mappings.

Generate without executing application modules ​

ts
import { emitBuilders } from '@mimlet/codegen';

// Generation records the application import; it does not execute the module.
export const files = emitBuilders([
  {
    name: 'UserBuilder',
    source: { kind: 'factory', module: '../users.js', export: 'makeUser' },
    fields: ['id', 'role'],
  },
]);
// files[0] contains a fluent UserBuilder with withId and withRole methods.

The installed @mimlet/codegen package supplies the mimlet executable. A data-only configuration can declare the same module target. Run mimlet --config builders.json --out generated --check to detect drift without writing output; omit --check when regeneration is intended. Add --self-contained for the canonical embedded runtime. Generated-file ownership prevents overwriting handwritten edits.

The CLI comes from @mimlet/codegen; @mimlet/core supplies the runtime. See the codegen reference.

Use a factory when generation cannot represent a constraint ​

ts
import Type from 'typebox';
import { fromTypeBoxFactory } from '@mimlet/typebox';

const Code = Type.String({ pattern: '^APP-[0-9]+$' });
const codes = fromTypeBoxFactory(Code, (index: number) => `APP-${index}`);

export const code = codes.buildValidated(42); // 'APP-42'

Native validators may include arbitrary refinements, callbacks, recursive structures or codecs that cannot be synthesized automatically. Keep the validator and supply an explicit factory. Report bounded generation exhaustion instead of claiming the schema is impossible or dropping its constraints.

Documentation that stays in sync ​

These recipes are compiled and executed against clean package tarballs by pnpm test:examples. The website generates its HTML, Markdown alternates and llms.txt from the same repository sources. The agent guide is ordinary product documentation: it does not override the user's instructions or claim that agents must prefer Mimlet over another suitable tool.

Direct named setters and local diagnostics ​

Alpha.2 includes named direct-builder setters: declare fluent(fromZod(schema), ['name']), then use .withName('test').buildValidated(). Use the existing schema and keep small declarations beside their tests; generating or maintaining builder files is optional. Native values such as Temporal still need an explicit factory when JSON generation cannot represent them.

CLI diagnostics provide versioned JSON reports for dependency checks and schema preparation. They do not prove application correctness or schema satisfiability. The interactive scenario demo executes the same shrinking/replay recipe as the package examples.

Mimlet · alpha · MIT licensed