Quick Start
Build your first CLI tool with Seed CLI in under 5 minutes.
Create a CLI in 5 Minutes
Scaffold a project
npm create seedcli my-cli
cd my-clipnpm create seedcli my-cli
cd my-cliyarn create seedcli my-cli
cd my-clibun create seedcli my-cli
cd my-cliDependencies are installed automatically. If you used --no-install, run your package manager's install command now.
Explore the scaffolded command
The Full template includes an example command at src/commands/hello.ts:
import { command, arg, flag } from "@seedcli/core";
export default command({
name: "hello",
description: "Say hello",
args: {
name: arg({ type: "string", description: "Who to greet" }),
},
flags: {
loud: flag({ type: "boolean", default: false, alias: "l", description: "SHOUT the greeting" }),
timed: flag({ type: "boolean", default: false, alias: "t", description: "Show execution time" }),
},
run: async ({ args, flags, print, timer }) => {
if (flags.timed) timer.start();
const name = args.name ?? "World";
const greeting = `Hello, ${name}!`;
print.info(flags.loud ? greeting.toUpperCase() : greeting);
if (flags.timed) print.muted(`Done in ${timer.stop()}`);
},
});Arguments and flags are fully typed — args.name is string | undefined, flags.loud is boolean. The timer context module provides simple profiling.
Review the entry point
The scaffolded entry point at src/index.ts uses the builder pattern with auto-discovery:
#!/usr/bin/env node
import { build } from "@seedcli/core";
const cli = build("my-cli")
.src(import.meta.dirname) // Auto-discovers commands/ and extensions/
.help()
.version("0.1.0")
.create();
await cli.run();You can add .debug() to enable --debug and --verbose global flags for development.
Run it
npm run dev -- hello World
# => Hello, World!
npm run dev -- hello --loud
# => HELLO, WORLD!
npm run dev -- --help
# => Shows help with all commandsThe run() Shortcut
For simple CLIs without the builder pattern, use run():
#!/usr/bin/env node
import { run, command, arg } from "@seedcli/core";
await run({
name: "my-cli",
version: "1.0.0",
commands: [
command({
name: "greet",
args: {
name: arg({ type: "string", required: true }),
},
run: ({ args, print }) => {
print.info(`Hello, ${args.name}!`);
},
}),
],
});Using the Seed Context
Every command's run function receives the seed context with access to all built-in modules — no extra installs needed:
import { command, flag } from "@seedcli/core";
import { join } from "node:path";
export default command({
name: "init",
description: "Initialize a new project",
flags: {
name: flag({ type: "string", required: true, description: "Project name" }),
},
run: async ({ flags, print, prompt, filesystem, template, packageManager }) => {
print.info("Initializing project...");
const useTs = await prompt.confirm({ message: "Use TypeScript?" });
// Create project directory and write package.json
const dir = join(process.cwd(), flags.name);
await filesystem.ensureDir(dir);
await filesystem.writeJson(join(dir, "package.json"), {
name: flags.name,
version: "0.0.1",
});
// Render a template file into the project
await template.generate({
template: join(import.meta.dirname, "../templates/readme.md.eta"),
target: join(dir, "README.md"),
props: { name: flags.name, useTs },
});
// Install dependencies in the new project
await packageManager.install([], { cwd: dir });
print.success(`Project "${flags.name}" created!`);
},
});Subcommands
Nest commands for complex CLIs:
import { command } from "@seedcli/core";
import migrate from "./db/migrate";
import seed from "./db/seed";
import reset from "./db/reset";
export default command({
name: "db",
description: "Database operations",
subcommands: [migrate, seed, reset],
});my-cli db migrate --up
my-cli db seed
my-cli db reset --forceDev Mode
During development, use the dev script for automatic restart on file changes:
npm run devThis runs seed dev under the hood, which watches for file changes and restarts automatically.
Scaffolded projects include dev, build, compile, and test scripts. Run them with your preferred package manager: npm run dev, pnpm dev, yarn dev, etc.