CLI tool
wevm/incur avatar
wevm/incur

incur builds a CLI that agents can call without a manifest

CLI framework for agents and humans

639 stars40 forksTypeScriptMIT

At a glance

What is it?
incur is a TypeScript framework for building command line tools, with a light API of Cli.create, .command, .fs and .serve, Zod schemas for arguments and options, and a default output format chosen to be cheap for a language model to read. The interesting part is the discovery layer, skills add and mcp add, which is how an agent finds your tool at all.
Who is it for?
Adopt incur if you are building a command line tool that a coding agent will call, since the schema-driven output, the manifest flags and the discovery commands are aimed squarely at that case. Skip it if you only need a conventional CLI with a hand written help parser, because the API surface and the output envelope are designed around machine consumers.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A CLI framework whose output is written for a model

incur is described as a CLI framework for agents and humans, and the unusual thing about it is that it treats the agent as the primary reader. The default output format is TOON, described as a token-efficient format that agents parse easily, with JSON, YAML, Markdown and JSONL as alternatives. The feature list quantifies the intent with a claim of up to three times fewer tokens per session than MCP or skill alternatives, and the mechanism behind that claim is visible in the option list: there is a --token-count flag that prints the token count of the output instead of the output itself, a --token-limit that truncates, and a --token-offset that skips a prefix for pagination. So the tool does not merely produce compact output, it lets the caller measure the output before deciding how to read it, and it can page through a large result without resending what has already been seen. For a human at a terminal this is invisible, because the friendly rendering is what you get by default. For an agent, the difference is the number of tokens in the context window.

The API is five names, and the schemas carry the types

The feature list advertises a light API surface of Cli.create(), Cli.command(), .command(), .fs() and .serve(), and the usage examples show how little ceremony that takes. A single command CLI is created by passing run straight to Cli.create, with the arguments described as a Zod object.

ts
import { Cli, z } from 'incur'

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}` }
  },
}).serve()

The inferred types feature says the generic type flows from the schemas to the run callbacks with zero manual annotations, so c.args.name is a string because the schema says it is, not because you declared it. The well formed I/O item covers the same ground from the other side, with schemas for arguments, options, environment variables and output, which means the help text, the JSON Schema and the runtime validation all come from one source. The describe calls on each field are what make the generated help readable, and they are also what an agent reads when it inspects the tool. Multi command CLIs chain .command() calls, and a separate Cli can be mounted with .command(cli) to nest command groups, which is how a sub-command tree is assembled without a second framework.

Global options arrive free on every command

The global options item is the one that most changes what a CLI looks like to a caller, because the options are not something you add per command. The list is --format, --full-output, --help, --json, --update and --version, on every CLI, and the generated help output shows the whole set with their descriptions, including --filter-output for filtering output by key paths, --llms for printing a manifest, --mcp for starting as an MCP stdio server, and --schema for showing the JSON Schema of a command. There is a small tension in that list worth noticing, since --json and --format can be read as overlapping ways of asking for structured output. In practice --format selects the representation and --json is the shorthand for it, and the help text is what settles the question for a reader. The bigger point for an adopter is that an agent that has learned the convention once, from any CLI built with incur, already knows how to ask for JSON, how to ask for a schema and how to ask for a machine readable manifest, without the tool author having to document it. The built-in commands list in the help output also shows completions for generating a shell completion script, mcp add for registering as an MCP server, and skills add for syncing skill files to agents.

skills add and mcp add are how an agent finds the tool

The first feature in the list is agent discovery, described as built-in skills and MCP sync so agents find your CLI automatically, with the commands skills add and mcp add. The quickprompt section makes the intended workflow explicit, with two ready made prompts to send to an agent, one that runs npx incur skills add and one that runs npx incur mcp add, each followed by a request to show how to build CLIs with incur. The distinction the documentation draws is token cost, with skills recommended as the lighter option on tokens. That recommendation is a design statement rather than a benchmark, and the three times fewer tokens figure in the feature list is likewise a claim the project makes about itself. What is concrete is the mechanism. A skill is a file the agent reads, an MCP server is a running process the agent talks to, and the project supports both, with the built-in --mcp flag able to start the CLI as an MCP stdio server from the same binary, and --llms able to print a manifest in Markdown or JSON schema form. So the same codebase can be published three ways, as a normal CLI, as an MCP server, and as a skill, and the tool author picks the one that suits the consumer.

File-based commands and standalone binaries

Two features concern distribution rather than interface. File-based commands load commands and nested sub-commands from sibling files and folders, so a large CLI does not have to live in one file, and the file structure becomes the command structure. Standalone binaries are the other one, with the ability to build macOS, Linux and Windows executables with verified updates and initial installers. The middleware feature is separate again, with composable before and after hooks and typed dependency injection through cli.use(), which is the seam you need if you want logging, tracing or auth to apply to every command without touching each one. The package manifest shows the shape of the toolchain around this. The runtime dependencies are small and specific: zod for the schemas, yaml, the TOON formatter package, a token counting package, an MCP server package pinned at a 2.0.0 alpha, an OpenAPI types package and a JSON schema package. The build itself runs through a tool called zile, the test script is vitest, and the type check is tsc across the src and test projects. The engines field requires Node 22 or newer, and the package is published as a pure ESM module with a bin entry for incur and one for running the source directly.

Where incur is the wrong tool

Three cases. The first is a small script with two flags, where the framework is more than the problem needs, because the whole point of a small CLI is that it is easy to write with a parser you already understand and output you print yourself. The second is a team that wants its output to look like every other tool in the company, since incur imposes a default TOON rendering and an output envelope, and the --full-output option exists precisely because sometimes you want the envelope and sometimes you do not. The third is the alpha dependency. The MCP server package is pinned at a 2.0.0 alpha version, and the whole discovery story leans on it, so the tool is building on a moving target. There is also a scope limit worth stating. The framework gives you schemas, options, output formats, discovery and middleware; it does not give you a test harness for your own commands beyond the fact that the project uses vitest, nor does it promise anything about how an agent will actually call your tool. The two useful flags for that question are --llms and --schema, and the honest way to use incur is to build the CLI, then point an agent at it and watch what it does, rather than to assume the discovery commands are sufficient.

Editorial conclusion

Adopt incur if you are building a command line tool that a coding agent will call, since the schema-driven output, the manifest flags and the discovery commands are aimed squarely at that case. Skip it if you only need a conventional CLI with a hand written help parser, because the API surface and the output envelope are designed around machine consumers. Before you publish, run npx incur skills add and npx incur mcp add on the agents your team uses and look at what they end up loading, and pin Node 22 or newer, since that is the engine requirement in the package manifest.

Frequently asked questions

How do I install incur?

The package is published on npm and installs with npm i incur, pnpm i incur or bun i incur. The manifest requires Node 22 or newer, and the package is published as a pure ESM module with the incur binary exposed under dist.

What is the TOON output format in incur and why is it the default?

TOON is the token-efficient default format that agents parse easily, with JSON, YAML, Markdown and JSONL as alternatives selected through the --format global option. The project also offers --token-count, --token-limit and --token-offset so a caller can measure, truncate or page through output.

How do I make an agent discover a CLI built with incur?

Use the built-in commands. Running npx incur skills add syncs skill files to agents, and npx incur mcp add registers the tool as an MCP server, with the documentation recommending skills as the lighter option on tokens. The same binary can also start as an MCP stdio server through the --mcp flag.

How do I add subcommands and options in incur?

Chain .command() calls to register subcommands, each with its own description, args and options as Zod objects, and mount a separate Cli with .command(cli) to nest command groups. Generic types flow from those schemas into the run callbacks with no manual annotations, and the same schemas drive help text, JSON Schema and runtime validation.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. wevm/incur on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wevm-incur.svg)](https://hysenlabs.com/projects/wevm-incur)

Was this useful?