Usage

ACTIVE
PACKAGE: @mbsi/mkcmd-agent
COMMANDS: init, add, describe

Install

mkcmd-agent is not on npm yet. Clone it and run it from source with Bun 1.2 or later:

git clone https://github.com/mackenziebowes/mkcmd-agent ~/mkcmd-agent
cd ~/mkcmd-agent && bun install
bun src/index.ts --help

Any directory works; these docs use ~/mkcmd-agent, and the examples below call it as mkcmd-agent, which from source means bun ~/mkcmd-agent/src/index.ts.

Agents: run the full bun ~/mkcmd-agent/src/index.ts ... command each time. Most agent tools start a fresh shell per command, so an alias set in one call is gone in the next. People: add alias mkcmd-agent="bun ~/mkcmd-agent/src/index.ts" to your shell profile.

Quick start

mkcmd-agent init --name my-cli --description "Does one thing well"
cd my-cli && bun install
bun run src/index.ts hello --name Ada --json
> {"ok":true,"command":"hello","result":{"greeting":"Hello, Ada!"}}

Every command takes --json. Start an agent session with bun run src/index.ts describe: it prints every command, flag and example as JSON.

init

Create a new project. Writes into ./<name> unless you pass --dir, and refuses a non-empty directory unless you pass --force.

FlagTypeDescription
--namestring, requiredPackage name: lowercase letters, digits, - . _ and an optional @scope/ prefix. The command name is the part after the scope.
--descriptionstringOne line on what the CLI does. Default: "A command-line tool."
--dirstringWhere to create it, relative or absolute. Default: ./<name without scope>
--forcebooleanWrite into a non-empty directory, overwriting files with the same names.
--dry-runbooleanList the files that would be written. Writes nothing.
--installbooleanRun bun install in the new project.
mkcmd-agent init --name @acme/tool --dir ./tools/tool --dry-run --json
> {"ok":true,"command":"init","result":{"name":"@acme/tool","bin":"tool","dir":"/abs/path/tools/tool","dryRun":true,"files":[...],"next":[...]}}

Errors you can get: usage (exit 2) for a missing or invalid flag, and target_not_empty (exit 1) when the directory already has files.

add

Add a command to a project made by init: it writes src/commands/<name>.ts from a template and adds it to the list in src/commands/index.ts. The new command throws not_implemented until you write its run.

FlagTypeDescription
--namestring, requiredCommand name: lowercase letters, digits and dashes, starting with a letter. describe and help are reserved.
--summarystringOne line shown in help and describe.
--dirstringProject root. Default: the current directory.
--forcebooleanOverwrite the command file if it exists.
--dry-runbooleanShow what would change. Writes nothing.
mkcmd-agent add --name sync-users --summary "Sync users from the API" --dir ./my-cli --json
> {"ok":true,"command":"add","result":{"command":"sync-users","dryRun":false,"files":["src/commands/sync-users.ts","src/commands/index.ts"],"next":[...]}}

Dashed names become camelCase identifiers: sync-users is exported as syncUsers. Errors: not_a_project when there is no src/commands/index.ts, command_exists when the file is already there.

The generated project

PROJECT STRUCTURE
my-cli/
├── AGENTS.md            the contract and how to add commands
├── README.md
├── package.json         bin: my-cli -> src/index.ts
├── tsconfig.json
├── src/
│   ├── index.ts         entry point: runCLI({ name, about, commands })
│   ├── core/cli.ts      the framework, one file, no dependencies
│   └── commands/
│       ├── index.ts     export const commands = [hello]
│       └── hello.ts     an example command
└── test/cli.test.ts     subprocess tests of the contract

Scripts: bun run start, bun test, bun run typecheck, and bun run build for a single compiled binary in dist/; after bun install the project passes its own tests and tsc --noEmit.

Next: the output contract, then writing commands.