autohand "Build a Node.js CLI tool called 'deploy-check' that validates deployment readiness. It should check git status, run tests, verify environment variables, and show a progress bar for each check."

What you'll learn

  • How to design and scaffold a CLI tool with argument parsing and subcommands
  • How to add colored output, spinners, and progress indicators
  • How to test the tool locally with npm link before publishing
  • How to package and distribute the tool via npm or a private registry

Before you start

  • Autohand Code installed. Run autohand --version to confirm. See Your First Autohand Session if you need to install it.
  • Node.js 18 or newer. Run node --version to check.
  • An empty project directory. Create a new folder and run npm init -y inside it.

Design the CLI

Before writing the prompt, sketch out what your tool should do. The more specific you are, the less back-and-forth you need after generation.

For a deployment readiness checker, think through:

  • What checks should it run? Git status (no uncommitted changes), test suite passes, required environment variables are set.
  • What is the command name and entry point? The binary will be called deploy-check.
  • What should the output look like? A progress bar or spinner per check, green checkmark on pass, red X on fail, summary at the end.
  • What flags does it need? Maybe --env staging to check a specific environment file, or --skip-tests to run faster.
  • What happens on failure? Exit with a non-zero code so CI pipelines can catch it.

Writing out this list takes two minutes and saves you multiple follow-up prompts.

Generate the tool

Run Autohand from your empty project directory with the prompt.

bash

cd deploy-check
autohand "Build a Node.js CLI tool called 'deploy-check' that validates deployment readiness. It should check git status, run tests, verify environment variables, and show a progress bar for each check."

The agent scaffolds the project and installs dependencies. A typical run produces output like this:

bash

# Agent output (abbreviated)
Planning structure...
Creating src/index.js
Creating src/checks/gitStatus.js
Creating src/checks/runTests.js
Creating src/checks/envVars.js
Creating src/utils/output.js
Creating package.json
Installing dependencies: commander, chalk, ora, execa
Done. Run "npm link" to install the binary locally.

The agent picks appropriate libraries. commander handles argument parsing, chalk handles colors, ora handles spinners, and execa runs subprocesses cleanly.

The generated structure

Here is what the generated project looks like.

bash

deploy-check/
├── src/
│   ├── index.js              # Entry point, Commander program definition
│   ├── checks/
│   │   ├── gitStatus.js      # Runs: git status --porcelain
│   │   ├── runTests.js       # Runs: npm test, captures exit code
│   │   └── envVars.js        # Reads required vars from config, checks process.env
│   └── utils/
│       └── output.js         # Spinner, success/fail symbols, summary formatter
└── package.json              # Includes "bin": { "deploy-check": "./src/index.js" }

The package.json bin field is what makes the tool installable as a global command. The entry point uses a Node.js shebang so it runs directly.

javascript

// src/index.js
#!/usr/bin/env node
import { program } from 'commander';
import { runChecks } from './checks/index.js';

program
  .name('deploy-check')
  .description('Validates deployment readiness before pushing')
  .option('--skip-tests', 'Skip the test suite check')
  .option('--env <file>', 'Path to environment file to validate', '.env')
  .action((options) => runChecks(options));

program.parse();

Each check is isolated in its own module. A check is a function that returns { passed: boolean, message: string }. This makes them easy to test and easy to add or remove.

javascript

// src/checks/gitStatus.js
import { execa } from 'execa';

export async function checkGitStatus() {
  const { stdout } = await execa('git', ['status', '--porcelain']);
  const passed = stdout.trim() === '';
  return {
    passed,
    message: passed
      ? 'Working directory is clean'
      : `Uncommitted changes:
${stdout}`,
  };
}

Test it locally

Use npm link to install the tool as a global binary without publishing to npm.

bash

npm link

# Now run it from any directory
deploy-check

# Expected output
Checking deployment readiness...
  Checking git status...    OK  Working directory is clean
  Running test suite...     OK  All tests passed (42 tests)
  Checking env variables... OK  All required variables are set

All checks passed. Ready to deploy.

Test the failure paths too. Introduce an uncommitted change and run the tool again to confirm the error output looks right.

bash

touch dirty-file.txt
deploy-check

# Expected output
  Checking git status...    FAIL  Uncommitted changes:
                                  ?? dirty-file.txt

1 check failed. Fix the issues above before deploying.
# Process exits with code 1

Add more commands

Once the base tool works, extend it with subcommands. The agent keeps new commands consistent with the pattern it already generated.

bash

# Add a lint subcommand
autohand "Add a 'deploy-check lint' subcommand that runs ESLint and shows the output inline. Use the same spinner pattern as the existing checks."

# Add a dry-run mode
autohand "Add a --dry-run flag that shows what would be checked without actually running any checks."

# Add a config file
autohand "Add support for a .deploy-check.json config file that lets teams specify which env variables are required and which checks to skip."

Commander makes adding subcommands straightforward. The agent adds a .command('lint') block in src/index.js and creates a corresponding module in src/checks/.

Package and distribute

Once the tool is working the way you want, you have a few options for distribution.

Publish to npm so anyone can install it globally.

bash

# Log in to npm
npm login

# Publish
npm publish

Add it as a dev dependency to a specific project so your team always has it available.

bash

# In the target project
npm install --save-dev deploy-check

# Add to package.json scripts
{
  "scripts": {
    "predeploy": "deploy-check"
  }
}

Install from a private registry or GitHub for internal tools that should not be public.

bash

# Install directly from GitHub
npm install -g github:your-org/deploy-check

Tip: Ask Autohand to add a GitHub Actions workflow that tests the CLI on pull requests before you publish a new version.

What you learned

  • Designed and generated a complete CLI tool with Commander, Chalk, and Ora
  • Structured the project with isolated check modules and a clean entry point
  • Tested the tool locally using npm link and verified both success and failure paths
  • Extended the tool with subcommands, config files, and distribution options

Try next

autohand "Add a 'deploy-check report' subcommand that outputs the results as a JSON file and posts a summary to a Slack webhook"