> ## Documentation Index
> Fetch the complete documentation index at: https://puzzlet-9ba7bb98.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Type safety

> Generate TypeScript types from your prompt schemas for compile-time validation and autocomplete.

AgentMark provides type safety through JSON Schema definitions in your prompt files. `agentmark generate-types` compiles those schemas to TypeScript types you can pass to `createAgentMark<T>()` for compile-time validation and IDE autocomplete.

## Defining types

Define input and output types in your prompt files using JSON Schema:

```jsx math/addition.prompt.mdx theme={null}
---
name: math/addition
object_config:
  model_name: openai/gpt-5
  schema:
    type: object
    properties:
      answer:
        type: number
        description: "The sum of the two numbers"
    required: [answer]
input_schema:
  type: object
  properties:
    a:
      type: number
      description: "First number to add"
    b:
      type: number
      description: "Second number to add"
  required: [a, b]
---

<System>You compute sums.</System>
<User>What is {props.a} + {props.b}?</User>
```

## Generating types

Generate TS types with the CLI:

```bash theme={null}
agentmark generate-types --root-dir ./agentmark > agentmark.types.ts
```

For the prompt above, the generator emits:

```typescript agentmark.types.ts theme={null}
// Auto-generated types from AgentMark
// Do not edit this file directly

interface Math$AdditionIn {
  a: number;
  b: number;
}

interface Math$AdditionOut {
  answer: number;
}

type Math$Addition = {
  kind: 'object';
  input:  Math$AdditionIn;
  output: Math$AdditionOut;
};

export default interface AgentmarkTypes {
  "math/addition.prompt.mdx": Math$Addition,
  "math/addition.prompt": Math$Addition,
  "math/addition": Math$Addition
}
```

Note two things:

1. The wrapper (`Math$Addition`) is a `type` alias, while `Math$AdditionIn` / `Math$AdditionOut` are `interface`s.
2. Each prompt gets **three** key aliases: the full path with `.prompt.mdx`, the path ending in `.prompt`, and the bare name. Any of the three resolves to the same type when you call `loadTextPrompt` / `loadObjectPrompt`.

## Using generated types

Pass the generated `AgentmarkTypes` interface as the generic parameter to `createAgentMark<AgentmarkTypes>({ loader })`. TypeScript then type-checks prompt names, props, and outputs on the neutral render. The client returns AgentMark's neutral shape (`{ messages, object_config }` for object prompts); you pass that to your own model call or an [executor](/getting-started/client-setup#connect-your-sdk).

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import type AgentmarkTypes from "./agentmark.types";
    import { createAgentMark } from "@agentmark-ai/prompt-core";

    // `loader` from your client setup — see Client config.
    const client = createAgentMark<AgentmarkTypes>({ loader });

    // TypeScript enforces correct types from the prompt's input_schema
    const prompt = await client.loadObjectPrompt("math/addition.prompt.mdx");
    const { messages, object_config } = await prompt.format({
      props: {
        a: 5,   // must be number per input_schema
        b: 3,
      },
    });

    // You own the model call — e.g. with the Vercel AI SDK:
    import { generateObject, jsonSchema } from "ai";
    import { openai } from "@ai-sdk/openai";

    const result = await generateObject({
      model: openai(object_config.model_name.replace(/^openai\//, "")),
      messages,
      schema: jsonSchema(object_config.schema),
    });
    const answer: number = result.object.answer;  // typed as Math$AdditionOut.answer
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from agentmark.prompt_core import create_agentmark

    # `loader` from your client setup — see Client config.
    client = create_agentmark(loader=loader)

    # Load and format to the neutral render
    prompt = await client.load_object_prompt("math/addition.prompt.mdx")
    formatted = await prompt.format(props={"a": 5, "b": 3})

    # You own the model call. `formatted` is a Pydantic model (attribute access,
    # not subscripts): formatted.messages and formatted.object_config.schema_
    # drive your SDK or executor.
    ```

    <Note>
      In Python there's no generated-types step or stubs package. Runtime validation applies to the rendered output, not your input props: `format()` parses the result into Pydantic models (`TextConfigSchema` / `ObjectConfigSchema`), so a malformed prompt fails at render time, but props aren't checked against `input_schema`. `format()` exposes the structured-output schema as `object_config.schema_` (trailing underscore) because `schema` collides with a Pydantic built-in.
    </Note>
  </Tab>
</Tabs>

## Benefits

1. **Compile-time safety:** TypeScript flags prop-shape mismatches before runtime.
2. **IDE support:** autocomplete and inline descriptions on `props` and outputs.
3. **Consistent interfaces:** the same `AgentmarkTypes` drives both the loader and the caller.
4. **Documentation:** JSON Schema descriptions flow through to TS JSDoc comments.

## Best practices

1. Define both `input_schema` and `object_config.schema` (when the prompt is an object prompt) in your prompt files.
2. Use descriptive property names and add `description` fields; they become JSDoc comments.
3. Mark required properties using `required`.
4. Regenerate types after any schema edit: `agentmark generate-types --root-dir ./agentmark > agentmark.types.ts`.
5. Commit `agentmark.types.ts` to version control so CI type-checks the contract.

<div className="mt-8 rounded-lg bg-blue-50 p-6 dark:bg-blue-900/30">
  <h3 className="font-semibold mb-3">Have questions?</h3>
  <p className="mb-4">Reach out any time:</p>

  <ul>
    <li>
      Email the team at <a href="mailto:hello@agentmark.co" className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-200">[hello@agentmark.co](mailto:hello@agentmark.co)</a> for support
    </li>

    <li>
      Schedule an <a href="https://cal.com/ryan-randall/enterprise" className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-200">Enterprise Demo</a> to learn about AgentMark's business solutions
    </li>
  </ul>
</div>
