> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/wevm/incur/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build your first incur CLI in 5 minutes

## Overview

This tutorial walks you through creating a simple CLI that greets users. You'll learn:

* How to create a CLI with `Cli.create()`
* How to define arguments and options with Zod schemas
* How to add multiple commands
* How to enable agent discovery
* How to test your CLI with an agent

<Steps>
  <Step title="Create a simple CLI">
    Create a new file `greet.ts` with a basic single-command CLI:

    ```typescript greet.ts theme={null}
    import { Cli, z } from 'incur'

    const cli = Cli.create('greet', {
      description: 'A greeting CLI',
      args: z.object({
        name: z.string().describe('Name to greet'),
      }),
      run(c) {
        return { message: `hello ${c.args.name}` }
      },
    })

    cli.serve()
    ```

    <Note>
      **Key points:** `Cli.create()` takes a name and configuration. The `args` field defines positional arguments with Zod schemas. The `run()` function receives typed context with `c.args.name`, and the return value is automatically wrapped and formatted.
    </Note>
  </Step>

  <Step title="Run your CLI">
    Execute your CLI:

    ```bash theme={null}
    npx tsx greet.ts world
    ```

    You'll see:

    ```
    message: hello world
    ```

    This is **TOON format** (Token-Optimized Object Notation) - more readable than JSON and uses 60% fewer tokens.

    <Tip>
      Try adding `--json` to see JSON output: `npx tsx greet.ts world --json`
    </Tip>

    Check the built-in help:

    ```bash theme={null}
    npx tsx greet.ts --help
    ```

    Output:

    ```
    greet – A greeting CLI

    Usage: greet <name>

    Arguments:
      name  Name to greet

    Built-in Commands:
      completions  Generate shell completion script
      mcp add      Register as an MCP server
      skills add   Sync skill files to your agent

    Global Options:
      --format <toon|json|yaml|md|jsonl>  Output format
      --help                              Show help
      --llms                              Print LLM-readable manifest
      --mcp                               Start as MCP stdio server
      --verbose                           Show full output envelope
      --version                           Show version
    ```
  </Step>

  <Step title="Add options">
    Extend your CLI with options for more control:

    ```typescript greet.ts theme={null}
    import { Cli, z } from 'incur'

    const cli = Cli.create('greet', {
      description: 'A greeting CLI',
      args: z.object({
        name: z.string().describe('Name to greet'),
      }),
      options: z.object({
        loud: z.boolean().optional().describe('Shout the greeting'),
        emoji: z.boolean().optional().describe('Add emoji'),
      }),
      run(c) {
        let message = `hello ${c.args.name}`
        if (c.options.loud) message = message.toUpperCase()
        if (c.options.emoji) message = `👋 ${message}`
        return { message }
      },
    })

    cli.serve()
    ```

    Try it:

    ```bash theme={null}
    npx tsx greet.ts world --loud --emoji
    ```

    Output:

    ```
    message: 👋 HELLO WORLD
    ```
  </Step>

  <Step title="Add multiple commands">
    Convert your CLI to support multiple commands:

    ```typescript greet.ts theme={null}
    import { Cli, z } from 'incur'

    const cli = Cli.create('greet', {
      version: '1.0.0',
      description: 'A greeting CLI',
    })

    cli.command('hello', {
      description: 'Say hello',
      args: z.object({
        name: z.string().describe('Name to greet'),
      }),
      options: z.object({
        loud: z.boolean().optional().describe('Shout the greeting'),
      }),
      run(c) {
        const message = `hello ${c.args.name}`
        return { message: c.options.loud ? message.toUpperCase() : message }
      },
    })

    cli.command('goodbye', {
      description: 'Say goodbye',
      args: z.object({
        name: z.string().describe('Name to say goodbye to'),
      }),
      run(c) {
        return { message: `goodbye ${c.args.name}` }
      },
    })

    cli.serve()

    export default cli
    ```

    Now you can:

    ```bash theme={null}
    npx tsx greet.ts hello alice
    # → message: hello alice

    npx tsx greet.ts goodbye bob
    # → message: goodbye bob

    npx tsx greet.ts --help
    # Shows all available commands
    ```

    <Note>
      The `export default cli` is important for agent discovery and type generation.
    </Note>
  </Step>

  <Step title="Enable agent discovery">
    Make your CLI discoverable by AI agents using Skills:

    ```bash theme={null}
    npx tsx greet.ts skills add
    ```

    This generates skill files and installs them globally so agents can discover your CLI automatically.

    Output:

    ```
      ✓ greet  A greeting CLI

    1 skill synced

    Run `greet --help` to see the full command reference.
    ```

    <Info>
      Skills are lightweight Markdown files that describe your CLI's commands, arguments, and options. They're automatically kept in sync with your code.
    </Info>

    Alternatively, register as an MCP server:

    ```bash theme={null}
    npx tsx greet.ts mcp add
    ```

    This adds your CLI to your agent's MCP configuration.
  </Step>

  <Step title="Test with an agent">
    Now your agent can discover and use your CLI. Try asking:

    <CodeGroup>
      ```text Skills (OpenCode, Cursor, etc.) theme={null}
      "Use the greet CLI to say hello to Alice"
      ```

      ```text MCP (Claude Desktop, etc.) theme={null}
      "Use the greet tool to say hello to Alice"
      ```
    </CodeGroup>

    The agent will automatically:

    1. Discover your CLI via Skills or MCP
    2. Read the available commands and their schemas
    3. Execute `greet hello alice`
    4. Parse the TOON output

    You can also test the machine-readable manifest:

    ```bash theme={null}
    npx tsx greet.ts --llms
    ```

    This outputs Markdown documentation that agents can read:

    ```markdown theme={null}
    # greet hello

    Say hello

    ## Arguments

    | Name   | Type     | Required | Description    |
    | ------ | -------- | -------- | -------------- |
    | `name` | `string` | yes      | Name to greet  |

    ## Options

    | Flag     | Type      | Required | Description         |
    | -------- | --------- | -------- | ------------------- |
    | `--loud` | `boolean` | no       | Shout the greeting  |

    # greet goodbye

    Say goodbye

    ## Arguments

    | Name   | Type     | Required | Description              |
    | ------ | -------- | -------- | ------------------------ |
    | `name` | `string` | yes      | Name to say goodbye to   |
    ```
  </Step>
</Steps>

## What You've Learned

<CardGroup cols={2}>
  <Card title="CLI Creation" icon="plus">
    How to create CLIs with `Cli.create()` and add commands with `.command()`
  </Card>

  <Card title="Type Safety" icon="shield">
    Using Zod schemas for arguments and options with automatic type inference
  </Card>

  <Card title="Output Formats" icon="file-code">
    TOON as the default token-efficient format, with JSON, YAML, and more available
  </Card>

  <Card title="Agent Discovery" icon="radar">
    Enabling automatic discovery via `skills add` and `mcp add`
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="Commands & Arguments" icon="terminal" href="/core-concepts/commands">
    Deep dive into command patterns, schemas, and validation
  </Card>

  <Card title="Output & Formats" icon="file-lines" href="/core-concepts/output">
    Learn about output envelopes, CTAs, and format options
  </Card>

  <Card title="Agent Integration" icon="robot" href="/features/agent-discovery">
    Configure Skills, MCP, and customize agent behavior
  </Card>
</CardGroup>

## Complete Example

Here's the final CLI from this tutorial:

```typescript greet.ts theme={null}
import { Cli, z } from 'incur'

const cli = Cli.create('greet', {
  version: '1.0.0',
  description: 'A greeting CLI',
})

cli.command('hello', {
  description: 'Say hello',
  args: z.object({
    name: z.string().describe('Name to greet'),
  }),
  options: z.object({
    loud: z.boolean().optional().describe('Shout the greeting'),
  }),
  run(c) {
    const message = `hello ${c.args.name}`
    return { message: c.options.loud ? message.toUpperCase() : message }
  },
})

cli.command('goodbye', {
  description: 'Say goodbye',
  args: z.object({
    name: z.string().describe('Name to say goodbye to'),
  }),
  run(c) {
    return { message: `goodbye ${c.args.name}` }
  },
})

cli.serve()

export default cli
```

<Tip>
  Want to see a more complete example? Check out the [npm CLI example](https://github.com/wevm/incur/tree/main/examples/npm) in the incur repository.
</Tip>
