@lumpcode/cli
v0.0.4
Published
CLI for Lumpcode — automate batched coding work with CLI coding agents over contexts using git for tracking
Readme
Lumpcode CLI
Lumpcode is a tool to automate batched coding work — large refactors, codemods, ticket queues, doc sweeps — by running your CLI coding agent (Claude Code, Aider, Codex, …) over many similar units of work in your repo, one git branch per batch for normal review.
Named after the lumpfish: a small cleaner fish that salmon farmers add to their pens to quietly pick parasites off the salmon. Lumpcode plays the same role in your codebase — steadily working through the long tail of repetitive coding chores (codemods, doc updates, missing tests) one batch at a time, not overflowing you with PRs, while you stay focused on you code.
A lump is one such campaign (e.g. "migrate every component to Vue"). It contains many contexts — Lumpcode's word for units of work: one component, one ticket, or a group of related files each — plus a prompt (or list of prompts) and an agent command. Each finished context is recorded with a fixed marker commit subject LUMP: <lumpName> - <contextName>, so repeated runs are resumable from remote git history after merges and reviews.
Use Lumpcode when you have many similar edits (migrations, tests, docs), an ordered ticket queue, or a long-running refactor you want to tick forward on a schedule. However, Lumpcode is highly configurable and you can shape it easily to your custom needs.
New here? Read DOCS/concepts.md (two minutes), then DOCS/get-started.md.
Install
Pick the option that fits your setup (see lumpcode.com for current installers):
- macOS (Homebrew):
brew install lumpcode - Linux / macOS (curl): follow the one-liner on the website
- Windows: download the installer or binary from the website
- npm (Node 22+):
npm install -g @lumpcode/cli
The npm package installs a lumpcode command that uses a native binary for your OS when one is available from the matching release; otherwise it runs the bundled CLI with Node. No extra steps are required.
Operators can set LUMPCODE_SKIP_BINARY=1 to skip the native download, LUMPCODE_INSTALL_VERBOSE=1 for install diagnostics, or LUMPCODE_INSTALL_REPO to override the GitHub release source when configuring downloads.
Before you run anything
You will need:
- A project on your machine with git push access to
originfor the repository you want to automate. ThebaseBranchyou pick (e.g.main) must already exist on the remote — Lumpcode reads it viaorigin/<baseBranch>. - A CLI coding agent on your
PATH— verify with e.g.copilot --versionorcursor-agent --version. Lumpcode invokes the agent through a command module registered by name (e.g.copilot,cursor) under.lumpcode/commands/<name>.jsor~/.lumpcode/commands/<name>.js. See DOCS/advanced-config.md. - An understanding that
lumpcode runcalls your agent, which usually means real LLM cost. Start with one context, review the resulting branch, then scale up.
60-second tour
From the root of a git repository:
lumpcode project-setup
lumpcode lump-create myFirstLumpEdit .lumpcode/lumps/myFirstLump/config.json (see the React-component example below), then:
lumpcode run myFirstLumpThis runs your agent on one context, commits a LUMP: myFirstLump - … marker, and pushes a lump/myFirstLump/… branch to origin for review.
Step-by-step: DOCS/get-started.md.
Run continuously as a deamon
Once a one-off run works end to end, have a background daemon tick every lump on a cron (default: every 5 minutes):
lumpcode start # detached background daemon
lumpcode daemon-status # is it running?
lumpcode stop # SIGTERM + cleanupBecause the daemon keeps invoking your agent on every tick, cap parallel work with maximumNumberOfConcurrentBranches (per lump or in project.json) and set "disabled": true on a lump to take it out of the rotation without stopping the scheduler.
Sporadic run vs sustained start: DOCS/concepts.md#when-to-use-run-vs-start-daemon.
How one run fits together
flowchart LR
start["lumpcode run myFirstLump"]
discover["Discover contexts"]
checkout["Work branch<br/>lump/myFirstLump/..."]
agent["Run agent"]
commit["Commit LUMP: myFirstLump - ..."]
push["Push origin"]
refresh["Update context status cache"]
start --> discover --> checkout --> agent --> commit --> push --> refreshconfig.json example: one branch per React component
Suppose your repo has one folder per React component, each with the same three related files:
src/components/
├── Button/
│ ├── Button.tsx
│ ├── Button.types.ts
│ └── Button.test.tsx
├── Card/
│ ├── Card.tsx
│ ├── Card.types.ts
│ └── Card.test.tsx
└── Modal/
├── Modal.tsx
├── Modal.types.ts
└── Modal.test.tsx.lumpcode/lumps/myFirstLump/config.json:
{
"$schema": "https://lumpcode.com/schemas/lumpConfig.schema.json",
"baseBranch": "main",
"contextListJson": {
"COMPONENT": "src/components/{COMPONENT_NAME}/{COMPONENT_NAME}.tsx",
"TYPES": "src/components/{COMPONENT_NAME}/{COMPONENT_NAME}.types.ts",
"TEST": "src/components/{COMPONENT_NAME}/{COMPONENT_NAME}.test.tsx"
},
"prompt": {
"promptTemplate": "Tighten the prop types in @{COMPONENT} (declared in @{TYPES}) and add any missing assertions to @{TEST}.",
"command": "copilot"
}
}Lumpcode scans the tree and finds every value {COMPONENT_NAME} can take such that all three rows resolve to a real file. With the tree above, that's three contexts — one per component:
| Context name | {COMPONENT} | {TYPES} | {TEST} |
| ------------ | ---------------------------------- | --------------------------------------- | --------------------------------------- |
| Button | src/components/Button/Button.tsx | src/components/Button/Button.types.ts | src/components/Button/Button.test.tsx |
| Card | src/components/Card/Card.tsx | src/components/Card/Card.types.ts | src/components/Card/Card.test.tsx |
| Modal | src/components/Modal/Modal.tsx | src/components/Modal/Modal.types.ts | src/components/Modal/Modal.test.tsx |
Each context becomes one work branch (lump/myFirstLump/Button, …) and one marker commit (LUMP: myFirstLump - Button, …) on origin. A component missing any of the three files is silently skipped — that row would fail to match.
contextListJson— Each value is a path template with{PLACEHOLDER}captures; each key (hereCOMPONENT,TYPES,TEST) becomes a variable usable in the prompt as{COMPONENT},{TYPES},{TEST}. See DOCS/lump-config.md#contextlistjson.promptTemplate—{VAR}substitutes the literal value; e.g you can safely use@{VAR}to have the same value with a leading@for agents that treat@pathas file context. See DOCS/lump-config.md#prompt-template-syntax.command— Registered command name only ("copilot","cursor", …), not shell flags (DOCS/advanced-config.md#custom-agent-commands).$schema— Optional but recommended: most editors will then autocomplete and validate every field above.
TypeScript hints for config.js and command modules
Optional npm package [@lumpcode/cli-types](https://www.npmjs.com/package/@lumpcode/cli-types) ships defineConfig, defineCommand, and other thin helpers plus the same types the CLI uses for lump config and .lumpcode/commands/*.js. See DOCS/lump-config.md — Typed JavaScript config.
Where to next
| Doc | Contents |
| -------------------------------------------------- | ---------------------------------------------------------------------------------- |
| DOCS/concepts.md | Project, lump, context, branch, context status; run vs start; workspace copies |
| DOCS/get-started.md | Zero → first successful lumpcode run |
| DOCS/commands.md | Every subcommand and flag |
| DOCS/project-config.md | .lumpcode/project.json |
| DOCS/lump-config.md | config.json / config.js fields |
| DOCS/advanced-config.md | Hooks, dynamic steps, custom commands |
| DOCS/examples.md | Ready-made lump shapes (smoke test, migration, tickets, codemods, docs, …) |
| DOCS/types.md | Hook and JSON type shapes |
Running E2E
Scenario tests invoke the CLI in a subprocess (not Vitest handlerMaker). They cover run, start, lump-status, and clean with a harness-generated Node mock agent command.
From packages/apps/cli:
npm run test:e2e # SEA: lazy build if binary missing, then scenarios
npm run test:e2e:node # Node: lazy build:bundle if missing, then same scenarios
npm run test:e2e:ci # SEA: always build:sea first (CI parity)
npm run test:e2e:ci:node # Node: always build:bundle firstAll four use scripts/run-e2e.mjs (--node for the Node launcher, --ci to force a full build).
On Windows (PowerShell), after building:
npm run build:sea:windows
$env:LUMPCODE_E2E_BINARY = ".\bin\lumpcode-windows-x64.exe"
npm run test:e2enpm run test:e2e auto-detects bin/lumpcode-windows-x64.exe on win32 and runs build:sea:windows when the binary is missing. npm run test:e2e:node uses the npm launcher (bin/lumpcode.js → node dist/index.js when no vendor/ binary is present). E2E subprocesses use an isolated temp profile (USERPROFILE and HOME on Windows) so daemon files and project-copies do not touch your real %USERPROFILE%\.lumpcode.
Optional env overrides:
LUMPCODE_E2E_BINARY— path to an existing SEA binary (default runner)LUMPCODE_E2E_RUNNER=nodewithLUMPCODE_E2E_CLI_ENTRY— Node launcher path (set automatically bytest:e2e:node)
Unit tests stay on npm test (E2E excluded via vitest.config.ts).
