Zero Dependencies: Building a Lean Node.js Automation Tool

clawdup's package.json has exactly two dev dependencies: typescript and @types/node. Zero runtime dependencies. This isn't an accident or a constraint — it's a deliberate architectural decision that makes the tool more reliable, more secure, and easier to maintain.

Why Zero Dependencies Matters

Every dependency you add to a project is a liability. It's code you don't control, maintained by people you don't know, with release schedules you can't predict. For an automation tool that runs continuously and handles sensitive operations (API tokens, code commits, PR creation), the attack surface of your dependency tree matters.

Supply chain security

With zero runtime dependencies, clawdup has zero supply chain attack surface. There are no transitive dependencies that could be compromised. No leftpad incidents. No malicious package updates to worry about. The only code that runs is code in this repository and Node.js itself.

Installation reliability

A npm install that downloads zero packages can't fail due to registry outages, version conflicts, or platform-specific native module compilation issues. clawdup installs in seconds and works the same on every platform.

Maintenance burden

No dependencies means no Dependabot PRs, no vulnerability alerts for transitive packages, and no time spent evaluating whether a major version bump in a dependency requires code changes. The only updates that matter are Node.js itself and the external CLI tools.

What Node.js Gives You for Free

Modern Node.js (18+) provides everything clawdup needs as built-in APIs:

HTTP requests: native fetch

Node.js 18 introduced native fetch, eliminating the need for axios, node-fetch, or got. The ClickUp API client uses fetch directly with standard Request and Response objects — the same API you'd use in a browser.

const response = await fetch(url, {
  headers: { Authorization: apiToken },
});
const data = await response.json();

Child processes: child_process

clawdup orchestrates three CLI tools: git, gh (GitHub CLI), and claude (Claude Code). All three are invoked via child_process.spawn or child_process.execFile, which gives full control over stdio streams, exit codes, and timeouts.

Using CLI tools instead of API libraries has a major advantage: authentication is handled by the tools themselves. gh handles GitHub auth. git handles SSH keys and credential helpers. clawdup doesn't need to know about OAuth tokens or SSH key management.

File system: fs/promises

Configuration loading, CLAUDE.md reading, and file existence checks all use fs/promises with async/await. No file system abstraction library needed.

Environment parsing: dotenv replacement

Instead of depending on the dotenv package, clawdup includes a simple 20-line parser for .env files. It handles the common cases (key=value pairs, comments, quoted values) without the 15+ transitive dependencies that dotenv alternatives might bring.

The CLI-First Architecture

One of clawdup's most important design decisions is shelling out to CLI tools instead of using API libraries. Here's why:

Git operations

There are several Node.js Git libraries (simple-git, isomorphic-git, nodegit). Each adds dozens of dependencies and their own abstractions. But Git itself is already installed on every developer machine, battle-tested across millions of repositories, and has a well-documented CLI interface.

clawdup runs git checkout -b, git add, git commit, and git push directly. The output is predictable, the error messages are familiar, and debugging is straightforward — you can run the same commands manually to reproduce any issue.

GitHub operations

Similarly, the GitHub CLI (gh) handles PR creation and merging. It manages authentication, handles pagination, and provides a stable interface. Using it means clawdup doesn't need to implement GitHub API pagination, rate limiting, or token refresh logic.

Claude Code

Claude Code is invoked as a subprocess with JSONL streaming output. This approach gives clawdup real-time visibility into what the AI is doing, the ability to enforce timeouts, and clean process isolation.

TypeScript as the Only Build Step

clawdup uses TypeScript 5.8 in strict mode, targeting ES2022 with NodeNext module resolution. The build step is a single tsc command that produces JavaScript files in the dist/ directory.

There's no bundler, no Babel, no webpack. TypeScript's strict mode serves as the primary correctness check — it catches type errors, null reference issues, and import problems at compile time. The compiled output is standard ESM JavaScript that Node.js runs directly.

Trade-offs

The zero-dependency approach isn't without trade-offs:

These trade-offs are acceptable because clawdup is a focused tool with a narrow scope. It doesn't need a web framework because it doesn't serve HTTP. It doesn't need a CLI framework because it has a handful of flags. The code it needs to write from scratch is minimal compared to the complexity it avoids by not managing a dependency tree.

The Result

clawdup installs in seconds, has zero security advisories, requires zero maintenance for dependency updates, and runs reliably on any platform with Node.js 18+. The entire codebase is auditable by reading a handful of TypeScript files — no node_modules rabbit hole to follow.

The best dependency is the one you don't have.

For an automation tool that runs continuously, handles API tokens, and commits code to your repository, that simplicity isn't just nice to have — it's a feature.