# Minimal Emitter

This guide shows the smallest useful emitter shape in oagen.

Use it when you want to understand the minimum contract quickly. If you need the full interface details, overlay behavior, and versioning rules, read the [Emitter Contract](../architecture/emitter-contract.md).

## Goal

A minimal emitter should:

- declare a `language`
- return files from at least one generator method
- return `[]` from methods the language does not use yet

That is enough to prove the parser, runtime, and file-writing loop are working.

## Smallest Practical Skeleton

```ts
import type {
  ApiSpec,
  Emitter,
  Enum,
  GeneratedFile,
  Model,
  Service,
} from "@workos/oagen";

function namesFile(path: string, values: string[]): GeneratedFile[] {
  if (values.length === 0) return [];
  return [{ path, content: values.join("\n") }];
}

export const demoEmitter: Emitter = {
  language: "demo",

  generateModels(models: Model[]): GeneratedFile[] {
    return namesFile(
      "models.txt",
      models.map((model) => model.name),
    );
  },

  generateEnums(enums: Enum[]): GeneratedFile[] {
    return namesFile(
      "enums.txt",
      enums.map((entry) => entry.name),
    );
  },

  generateResources(services: Service[]): GeneratedFile[] {
    return namesFile(
      "services.txt",
      services.map((service) => service.name),
    );
  },

  generateClient(spec: ApiSpec): GeneratedFile[] {
    return [
      {
        path: "summary.txt",
        content: [
          `name: ${spec.name}`,
          `services: ${spec.services.length}`,
        ].join("\n"),
      },
    ];
  },

  generateErrors(): GeneratedFile[] {
    return [];
  },

  generateTypeSignatures(): GeneratedFile[] {
    return [];
  },

  generateTests(): GeneratedFile[] {
    return [];
  },

  fileHeader(): string {
    return "# Generated by oagen";
  },
};
```

## What This Proves

With just this emitter, you can verify:

- the spec parses into IR
- the emitter is registered correctly
- the generation runtime calls each method in the expected order
- output files are written to disk

## What It Does Not Cover Yet

This is intentionally incomplete. It does not try to solve:

- language-specific naming conventions
- request/response rendering
- operation planning
- compatibility overlays
- smoke verification
- integration into an existing SDK

## The First Real Upgrade

After the minimal emitter works, the next step is usually to make `generateResources()` and `generateClient()` understand operations rather than only names.

That is when `planOperation()` becomes useful:

```ts
import { planOperation } from "@workos/oagen";

for (const service of services) {
  for (const operation of service.operations) {
    const plan = planOperation(operation);
    // render using plan.hasBody, plan.isPaginated, plan.responseModelName, ...
  }
}
```

## Recommended Path

1. Start with this minimal emitter.
2. Make generation deterministic and add golden tests.
3. Add real model and operation rendering.
4. Only then add advanced features like compat overlays or smoke verification.
