fastcoder
v1.4.0
Published
Fastcoder — CLI tool to register, inspect and report on local development projects.
Maintainers
Readme
Fastcoder
CLI tool to register, inspect and report on local development projects.
Features
- Register and remove projects (persisted in SQLite at
~/.fastcoder/fastcoder.db) - Read each project's tasks folder (default
.docs/, configurable viaTASKS_FOLDERin.envor the global settings — e.g..docs/config.jsonwith achecksarray of shell commands) - Run shell commands inside any registered project
- Run periodic check passes and store reports
- Drive coding tasks through stage folders (
todo → doing → validate → test → document → done) and implement them with Claude Code - Run a single
dothat executes one task through the full flow (continue, specification, do, validate, test, document, periodic) in priority order, across one project or every project - Track every Claude Code run as an execution (status, tokens, usage-limit headroom)
- Retry failed tasks automatically and quarantine repeat failures in a
failures/stage - Record exceptions for interrupted runs and an action log of every step
- A web-UI Chat on the Claude Agent SDK: saved chats linked to a project and an AI account, streamed replies, and Fastcoder actions (tasks, runs, settings) with confirmation for destructive ones
- Full web interface (React + Vite + Express, TypeScript) exposing every feature — manage projects, the task board, executions, exceptions, logs, reports, the scheduled job and settings
- Install/remove a system scheduled job (launchd / crontab / Task Scheduler) that runs the flow on a schedule, with a health check that tells you when the job is installed but not actually running and a one-click repair
Install (global CLI)
Prerequisites
- Node.js ≥ 22 (Node 22 LTS or Node 24 LTS recommended). Older Node
versions are unsupported — Node 18 reached end-of-life in April 2025 and
better-sqlite3no longer ships prebuilt binaries for them. - A C/C++ toolchain only if no prebuilt binary exists for your Node version/platform (see Troubleshooting below). Prebuilt binaries are shipped for the recommended Node LTS versions, so most users do not need a compiler.
Install
cd /Users/username/projects/fastcoder
npm install
npm install -g .Now fastcoder is on your PATH.
Update the local CLI (without publishing to npm)
To test your local working copy as the global fastcoder command — without
ever pushing to npm and reinstalling from there — rebuild and reinstall from the
project directory. Pick whichever workflow fits how often you iterate:
One-off update (recommended). Reinstall the current local code over the
global install. --force ensures npm overwrites the existing global package even
when the version number in package.json has not changed:
cd /Users/username/projects/fastcoder
npm run build:all # compile dist/ AND web-ui/dist (full version)
npm install -g . --forceOr, equivalently, via make:
make update-global-full # build web UI + CLI, then reinstall globally (--force)make update-global-full rebuilds the web UI and the CLI before
reinstalling. If you only changed CLI/src/ code, use make update-global
(rebuilds the CLI only). The individual steps are also available as
make build-web and make build.
Why
build:all/build:web?npm install -g .runs thepreparescript, which only compiles the TypeScript CLI intodist/. It does not rebuild the React web interface. If you changed anything underweb-ui/and want the full local version, build the web bundle first (npm run build:web) so the packagedweb-ui/distis up to date. If you only changed CLI/src/code,npm install -g . --forcealone is enough.
Live-linked update (best for frequent iteration). npm link symlinks the
global fastcoder to this folder, so you only need to recompile — no reinstall:
cd /Users/username/projects/fastcoder
npm link # link once; global `fastcoder` now points here
npm run build:all # recompile after each change (re-run as needed)Re-run npm run build (CLI) or npm run build:web (web UI) after edits and the
global fastcoder immediately reflects the rebuilt output. Run npm unlink -g
fastcoder (or make uninstall-global) to undo the link.
No-install run. To execute the local code directly without touching the global install at all, run it straight from source or the compiled output:
make dev # run the CLI from TypeScript via ts-node
node bin/fastcoder.js # run the compiled dist/ build
npm start # same as `node bin/fastcoder.js`Troubleshooting install
If npm install (or npm i -g fastcoder) fails while building
better-sqlite3 with an error like make: cc: No such file or directory
or prebuild-install warn install No prebuilt binaries found, the native
SQLite addon is falling back to compiling from source because no prebuilt
binary matches your Node/OS combination — and the system has no C compiler.
Fixes (pick one):
Use a Node version with a prebuilt binary (cheapest). Switch to Node 22 LTS or Node 24 LTS:
nvm install 22 && nvm use 22 npm i -g fastcoderInstall the build toolchain so the source compile succeeds:
- Linux / WSL (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install -y build-essential python3 - macOS:
xcode-select --install - Windows (PowerShell as admin):
npm i -g windows-build-tools(or install "Desktop development with C++" from the Visual Studio Build Tools)
Then re-run
npm i -g fastcoder.- Linux / WSL (Debian/Ubuntu):
Lint & format
npm run lint:all # ESLint check, root + web-ui
npm run lint-fix:all # ESLint --fix, root + web-ui
npm run cs-check # Prettier --check
npm run cs-fix # Prettier --write
npm --prefix web-ui run typecheck # tsc -b, no emitSee .docs/guidelines/code-linting.md for the full script table, config
locations, and severity policy.
Quick start
fastcoder register --name my-app --path /path/to/repo
fastcoder list
fastcoder check
fastcoder doctor # environment health: dependencies, tools, settings
fastcoder serve # http://localhost:4787
fastcoder cron:install # every 15 minutes by default (macOS/Linux/WSL/Windows)
# first checks `claude` is runnable from a cron-like
# environment (warn-only; skip with --no-preflight)
fastcoder cron:status # prints `health: ok` or `health: FAILED — {reason}`
# and `Last tick: …` (unhealthy after 3 missed intervals)
# also unhealthy when the job's script no longer exists
fastcoder cron:repair # re-installs the job when the health check fails
fastcoder run my-app "git status"Run without arguments for an interactive menu:
fastcoderTask workflow
Fastcoder drives coding tasks through a set of stage folders inside each
project's tasks folder (default .docs/tasks/; change the name via the
TASKS_FOLDER variable in .env or in the global settings). Create the
structure once:
fastcoder init my-appThis creates tasks/{backlog,ai-backlog,specification,todo,doing,blocked,validate,test,document,done,failures,garbage,periodic}.
Drop a Markdown task file (one feature per file) into tasks/todo/ describing
what you want done.
init also installs the fastcoder Claude helpers into the project (skipping any
already present): the fcd-* slash commands into .claude/commands/, the
bundled periodic task files into <tasks-folder>/tasks/periodic/, a starter root
sonar-project.properties keyed to the project folder name (never overwritten —
this is what the bundled sonarqube.mk scan commands read sonar.sources/
sonar.tests/coverage paths from), and the
bundled skills flat at .claude/skills/<skill>/SKILL.md — the only layout
Claude Code discovers (currently fcd-usability, sonarqube-setup,
sonarqube-todo-tasks, fix-lint, makefile-setup, ai-backlog-evaluation,
fcd-worktree-creation and fcd-git-worktree). The fcd-git-worktree skill
teaches an agent to create, set up (linking the application's own ignored
dependencies and local config, recorded in
<tasks-folder>/guidelines/git-worktree-setup.md), use and safely remove git
worktrees under <tasks-folder>/worktrees/ with the plain git CLI. When that
record exists, Fastcoder applies its "Link from the main tree" list itself each
time it prepares a (WT-…) or per-task worktree, so those runs build and test
without an agent setup step. The ai-backlog-evaluation skill scores each
ai-backlog/ idea and then discards, promotes, splits or parks it for human
approval; a promoted file is renamed {timestamp}_ai-promoted-{slug}[.step-1].md
with a fresh timestamp, so AI-promoted tasks stand out from hand-written ones.
Because promotion is unattended, a risky idea (breaking change, wide blast
radius, possible data loss) is always parked for human approval whatever its
value — value never overrides risk, and only low-risk ideas are auto-promoted.
When an idea proposes several ways to do the same thing, the skill picks the
option that fits the project and rewrites the idea file so that option is the
single stated path (the rejected ones stay as a short annotated list); a human is
asked only for the hard calls — close options, a product/cost trade-off or a
choice that would be expensive to undo. It is driven by the bundled
005-ai-backlog-auto-evaluation(1Xday).md periodic task, which runs in
manage-tasks mode (see below). A local V2 task record (.json in
ai-backlog/ with its body under <tasks-folder>/tasks-source/) is first
converted back to an ordinary backlog markdown file and then triaged; records it
cannot convert are left untouched and listed as skipped (V2 record) in the run
summary.
init never overwrites an existing file, so it cannot bring an older project up
to date. Use update for that:
fastcoder update my-app # refresh the bundled fastcoder assets
fastcoder update my-app --dry-run # report what would change, write nothingIt refreshes the fastcoder-owned assets — the fastcoder-* commands and the
bundled skills (including their references/) — to the version shipped with the
installed fastcoder, creates any missing stage folder, and adds missing starter
templates. Project-owned files (periodic task files, makefile modules, the root
Makefile, the root sonar-project.properties, the guidelines
README.md/index.md) are only ever added, never
overwritten, and nothing is ever deleted. The same action is available in the
interactive project menu as "Update structure", as the "Update structure" button
on the web UI project page, and as "Update structure on all projects" on the
Settings page (POST /api/projects/:id/update and
POST /api/settings/tasks-folder/update).
It also seeds <tasks-folder>/guidelines/ with a README.md and an index.md
(one line per guideline, saying why it exists) — neither is overwritten on
re-init. The document step keeps both, and the project README, up to date; it
never writes changelogs or step logs.
Tasks flow through the stage folders in this order:
ai-backlog → backlog → specification → todo → doing (.do) → validate → doing (.validate) → test → doing (.test) → document → doing (.document) → donedoing/ is the single active-processing folder for every step. While a file
sits there its name carries a .{step} tag (.do, .test, .validate,
.document) recording which step owns it; the tag is stripped when the step
finishes and the file moves to the next queue folder. See
.docs/guidelines/fastcoder-flow.md for
the complete reference.
do — run the next ready task through the flow
fastcoder do my-app # scope the flow to one project
fastcoder do # global: span every projectdo runs one task through the complete fastcoder flow. Each invocation
tries every step in priority order and executes the first one that has work:
| Priority | Step | What it does |
| -------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| 1 | continue | Retries a task that failed on its first do attempt |
| 2 | specification | Turns a raw brief in specification/*.md into todo/*.step-N.md plans, and archives the brief to done/*.specified.md |
| 3 | do | Implements the next *.step-N.md from todo/ → moves to validate/ |
| 4 | validate | Validates a task from validate/ → moves to test/ |
| 5 | test | Writes/runs tests for a task from test/ → moves to document/ |
| 6 | document | Generates docs for a task from document/ → moves to done/ |
| 7 | periodic | Runs one due health-check task from periodic/ (stays in place) |
Periodic task files are permanent, read-only definitions — a run never writes
into them. Each run prepends a newest-first entry to
<tasks-folder>/logs/periodic-tasks-log.md (seeded by fastcoder init, never
overwritten on re-init).
A periodic file only ever has one run in flight, even across processes: two cron
ticks racing on the same due file resolve so that exactly one runs and the other
skips silently, and running a periodic task on demand while its run is in flight
is refused instead of starting a second one. A running periodic task also counts
towards the global, per-project and per-stage parallel limits, so the flow skips
the periodic step while a health check is still running.
By default a periodic run is report-only (it never fixes anything, it only files
ai-backlog entries). A periodic file that contains the line
Periodic-mode: manage-tasks opts into the second mode instead: the run may
create, move, rename and delete markdown files inside <tasks-folder>/tasks/,
but still must not touch source code or tests. The marker lives in the file
content — there is no CLI flag or setting — and the periodic file itself is
never moved or renamed in either mode.
Scheduling rule: project priority → step priority → project rotation
tie-break. Projects marked priority are served first: the whole step chain is
attempted against them, and only when none of their steps has work do the other
projects run — so a priority project's document task beats a normal project's
todo task, and while a priority project always has work the others stay
idle (intended; unprioritize it to let them resume). Inside a group, steps have
a fixed priority and the highest-priority step with work always runs; project
rotation only breaks ties between otherwise-equal projects. A paused project
never runs, priority or not, and the global pause stops every project at
once — toggle it from the Pause Fastcoder / Resume Fastcoder button in the
web UI header (Projects and Dashboard pages), the Global pause switch on the
Settings page, the CLI config menu, or the globalPause field on
GET/PUT /api/settings. See
.docs/guidelines/fastcoder-flow.md for
the full definition.
Technical blackout. A hold that stops every Claude-invoking step until a
chosen end time, leaving only the Claude-free unblock recovery running. Declare
or end it from the Technical blackout card on the web UI Settings page (end
date, reason, description, Save / Clear) or through
PUT/DELETE /api/settings/technical-blackout; the same card holds
TIMEOUT_FOR_ERRORS, the blackout length applied when Claude returns a service
error. fastcoder config prints the current blackout (or not set) and the
Timeout for errors: {n} min line for a terminal-only check. While one is
active — or while the global pause is on — a red banner at the top of every web
UI page says so. The blackout ends by itself at its end time. See
.docs/guidelines/technical-blackout.md.
Keep the machine awake during runs. While a flow step's Claude run is in
progress, Fastcoder holds an OS sleep assertion bound to the run's process and
released when it ends: caffeinate -i -s on macOS, systemd-inhibit on Linux,
SetThreadExecutionState on Windows (no-op on WSL and inside the Docker
container, which cannot keep the host awake). On by default; toggle it
from the Settings page, the fastcoder config menu or the keepAwakeDuringRuns
field on GET/PUT /api/settings. See
.docs/guidelines/settings.md.
Per-task model override. A task file can pin the Claude model it runs on by
adding a .{model} tag to its name — add-login.opus.step-1.md runs on opus
regardless of the configured default. {model} is one of sonnet, opus,
haiku, fable. The tag stays on the file through every stage, so the same
model handles the task's do, test, validate and document steps.
The do step itself:
- Runs a check pass to inspect task status.
- If the project has a task that failed on a previous
do, that task is retried first (see below). Otherwise it moves the first file intasks/todo/intotasks/doing/tagged.do. - Runs Claude Code against the task file in
tasks/doing/to implement it. - On success, strips the tag and moves the file to
tasks/validate/. - On failure, the file stays in
tasks/doing/and an exception is recorded —pendingwhen the run can be resumed (e.g. a usage limit was hit) orignoredwhen it cannot.
Failure retries. The next time the flow runs for a project with a failed
task, the continue step resumes that task to analyse and fix the failure.
If the retry succeeds the task moves to tasks/validate/; if it fails again
the task is moved to tasks/failures/ and the exception is marked
failed-solving.
Global do. With no project, fastcoder do considers every registered
project, using Priority scheduling with round-robin tie-breaking: it walks
projects starting from the one after the project executed last time, and stops
at the first step with work, executes it and exits — so a scheduled
fastcoder do makes steady progress across every project and every stage of
the flow.
check — inspect status and preview the next do
fastcoder check my-app # one project
fastcoder check # all projectscheck runs the project's configured check commands and reports task counts
per stage. It also lists, in flow priority order, the files that are ready to
execute in the next fastcoder do cycle — the one the next run will actually
pick is marked ▶ (runs next), and steps disabled in settings are shown with a
[step disabled] note:
report #1 my-app (project #1) — .docs found · files: 0 · checks run: 0 · tasks: … · next: do → add-login.step-1.md
Ready for next `do` cycle:
▶ do todo/add-login.step-1.md (runs next)
validate validate/fix-header.step-1.md
test test/cache-layer.step-1.md
periodic periodic/daily-project-health.mddoctor — check the environment
fastcoder doctorReports whether the machine has what fastcoder needs, grouped as Dependencies
(Node.js vs. engines.node, Git, the Claude Code CLI), Recommended tools
(Playwright CLI, GitHub CLI, a SonarQube MCP entry in the project's .mcp.json),
Recommended settings (at least one AI provider account registered) and
Task queues (every registered project's task-stage folders for a task file
that sits in more than one stage at once, e.g. todo and doing). Each
non-OK line carries a hint on how to fix it.
It is informative only: nothing it reports blocks anything, and the command
always exits 0. Unlike check, which inspects a single project's task queue,
doctor mostly inspects the machine — the Task queues group is the one
project-aware exception. The same report is available over HTTP at
GET /api/doctor and on the web UI's Doctor page (/doctor), which shows
the same rows with a status badge and a Refresh button. See
.docs/guidelines/doctor.md.
config — settings and AI provider accounts
fastcoder configPrints the application settings and the registered AI provider accounts, then opens an
interactive editor. Each account pairs a provider (Claude Code, Gemini CLI, GLM, …) with its own
config dir, default model and enabled flag, and is printed as
{name} ({provider}) — model {model} — {configDir or 'provider default'} — {enabled|disabled}.
The "AI provider accounts" entry (also reachable as Manage AI provider accounts in the
interactive menu) adds, edits, deletes an account and refreshes its usage limits. The same accounts
are managed over HTTP under /api/ai-provider-accounts and on the web UI's AI Providers page.
An enabled account whose 5-hour session usage reaches 90% is skipped when the flow picks who runs
the next task, and shows up as a warning in the global alerts banner at the top of every web UI
page until its session window resets. See .docs/guidelines/ai-provider-accounts.md and
.docs/guidelines/settings.md.
executions — track Claude Code runs
Every Claude Code run started by do is recorded as an execution. An execution
is in-progress while Claude runs and becomes success or fail when it
ends, capturing token usage and remaining usage-limit headroom when available.
Each execution also records the account's last known Claude Code utilization at
the moment it started — the 5-hour and 7-day percentages, shown as
limits {short}%/{long}% in the list and a Limits: line in the detail view
(n/a when no snapshot is stored). The web UI shows the same pair in a Limits
column of the executions table (— for a missing side):
fastcoder executions # recent executions
fastcoder executions -p my-app -s in-progress # what is still running
fastcoder executions 42 # full detail of one executionExecution statuses: in-progress, success, fail.
If a run is killed with its host process (machine sleep, reboot, crash) its
in-progress row would otherwise stay open forever and keep blocking the flow.
Every flow tick reconciles such rows: after 60 minutes with no live Claude
process for that task, the execution is finished as fail with the reason
abandoned: process no longer running (the row is kept, never deleted).
continue — resume interrupted runs
fastcoder continue my-app # one project
fastcoder continue # every projectcontinue re-runs Claude Code for each pending exception. A resumed run that
completes flips the exception to solved and moves the task to tasks/test/;
a run that fails again flips it to failed-solving.
An in-flight resume counts towards the global, per-project and per-stage
parallel limits: it occupies one slot, charged to both continue and the
resumed file's original stage, so the flow skips the continue step while a
resume of that project is still running.
exceptions and logs — inspect what happened
Every do / continue step is recorded in an action log, and failed runs are
recorded as exceptions. Both can be listed and filtered:
fastcoder exceptions # all exceptions
fastcoder exceptions -p my-app -s pending # filter by project and status
fastcoder logs -p my-app -a do # logs for the `do` action
fastcoder logs --level error # only error-level logsException statuses: pending, solved, ignored, failed-solving.
Log levels: info, warn, error.
Web interface
fastcoder serve starts an Express server that exposes every application
feature as a JSON API under /api and serves a React single-page app for the
UI. The web app lives in web-ui/ (React 18 + Vite + TypeScript, PrimeReact
components, Tailwind CSS, React Router, TanStack Query for state, and
react-hook-form + zod for validation).
npm run build:web # install web-ui deps and build the SPA into web-ui/dist
fastcoder serve # serves the built SPA + API at http://localhost:4787The interface has a sidebar with menu navigation, a header and a footer, and
covers the whole feature surface: a Dashboard overview, full project CRUD, a
per-project workspace with a kanban-style task board (create / edit / move /
delete task files — several task dialogs can stay open at once, each one
collapsible to its title bar, maximizable to fill the whole page, or
minimizable to a chip in the bottom-left dock, with a Save that keeps the
dialog open next to Save and close) and the
do / check / continue / run-command actions, plus pages for executions, exceptions, action logs, reports, the scheduled job,
the environment Doctor report, the AI Providers page (accounts table with
add / edit / delete and a per-account limits refresh) and global settings, which
links to it instead of carrying the old single Claude account, model and
usage-limit rows. The Preferences card carries a Theme selector (Dark,
Light, Midnight, Daylight) that applies at once and is persisted for the whole
installation; THEME in .env sets the initial value and fastcoder config
changes it from the terminal.
The Chat page (/chat) talks to Claude through the Claude Agent SDK (pinned;
fastcoder doctor prints its version). Each chat is saved as JSON under
.docs/chat-history/ in the Fastcoder install (git-ignored), can be linked to a
project (the assistant then reads its files read-only) and to an AI account
(Auto or a fixed one — a disabled or over-limit account is refused, never
swapped silently), and streams replies live with a Stop button. Chat turns do not
count as executions and do not take the flow's parallel slots. The assistant can
also drive Fastcoder through its own services (list/create/edit/move/delete/pause
tasks, run a task, read executions, exceptions, logs and settings); deleting a
task, moving it to garbage/failures or changing a setting first asks you in a
confirmation dialog. A task run started from the chat is a regular execution, shown
as a job linked to its log. Task, execution and project references in replies are
links, and Open chat on a project page or task dialog opens a chat linked to
that project. A new chat is titled from its first message, then refined by a short
model call; a title you set yourself is never overwritten. The API lives under
/api/chats (with a Server-Sent Events stream at /api/chats/:id/stream); see
.docs/guidelines/chat.md.
Each project can also be given a colour from a fixed palette in its create/edit dialog: the project name is then shown in that colour wherever it appears (the dashboard tables, the projects list and the project page). A paused project overrides it with gray — its name and its whole dashboard row are dimmed, and it leaves the "Running now" card as soon as nothing of its is still executing.
Each task stage has its own colour too: the stage name and its task count are
shown in it on the dashboard ("Tasks by stage") and on the project board's
column headers, and a stage paused for a project turns gray. The colours are
constants that can be overridden per stage from .env with
STAGE_COLOR_{STAGE} (the stage upper-cased with - as _, e.g.
STAGE_COLOR_TODO=#0ea5e9) — see .env.example; an unset or invalid value
keeps the built-in colour.
AI-provider usage limits are colour-graded the same way: each percentage is
green below 70%, yellow below 90% and red from 90% up, on the AI Providers
page and in a dashboard AI provider limits card that lists every registered
account with its current 5-hour and 7-day windows (— when no snapshot has been
fetched yet, and the whole row dimmed to gray for a disabled account).
For UI development, run the API and the Vite dev server side by side — Vite
proxies /api to the running fastcoder serve:
fastcoder serve # API on :4787
npm --prefix web-ui run dev # Vite dev server on :4788, proxying /apiBackground daemon
fastcoder webui:install registers a per-user background service
(com.fastcoder.webui: launchd on macOS, a systemd user unit on Linux/WSL, a
scheduled task on Windows) that keeps the web UI running; webui:uninstall
removes it and webui:status reports it. webui:status also warns when the
installed daemon still runs a script that no longer exists or sits inside a task
worktree (it would stop starting once that worktree is cleaned up) — run
fastcoder webui:install to re-register it.
The daemon serves the compiled dist/ output, so a change in src/ only takes
effect after a rebuild and a restart:
fastcoder webui:status # adds a `build: up to date` / `build: STALE` line
fastcoder webui:refresh # rebuild + restart the daemon (skips when nothing is stale)
fastcoder webui:refresh --force # rebuild even when up to date
fastcoder webui:refresh --no-restart # build onlyIt exits non-zero only when the build fails. The flow triggers the same refresh
automatically after any step actually executed — turn it off with the
Auto-rebuild the web UI toggle on the Settings page, the same entry in
fastcoder config, or webuiAutoRefresh on PUT /api/settings. It is skipped
while another run is active, and when the run itself started from inside the
daemon (the next cron tick refreshes instead).
Run with Docker
Fastcoder also runs from a Docker image — the Web UI as the container's main process and every CLI command through compose or a small wrapper, with data in a per-major volume:
make docker-build # fastcoder:<version>, fastcoder:<major>, fastcoder:dev
make docker-up # Web UI on http://127.0.0.1:4787
docker compose exec fastcoder fastcoder list
bin/fastcoder-docker flow # one-off CLI run, like the native commandSwitch versions with FASTCODER_IMAGE (and FASTCODER_MAJOR), mount projects at the same
absolute path (FASTCODER_PROJECTS_DIR) and keep the port on localhost — the API is
unauthenticated. Inside the container the flow is scheduled by the server itself (cron:* report
it as built in), webui:install/uninstall/status/refresh print the matching docker compose
command, and doctor lists projects not mounted and Claude accounts without usable credentials
(claude login in the container or ANTHROPIC_API_KEY). The host must stay awake while runs are
expected. Full guide: .docs/guidelines/docker.md.
Using make
A Makefile (with one sub-file per command group under ./make/) wraps the
CLI so you can drive everything with make:
make help # list every target
make install # npm install + tsc build
make build # tsc only
make build-web # build the web UI bundle (web-ui/dist)
make watch # tsc --watch
make dev # run CLI from TS via ts-node
make install-global # npm install -g . (auto-compiles)
make update-global # rebuild CLI + reinstall locally (--force)
make update-global-full # rebuild CLI + web UI + reinstall (--force)
make uninstall-global # npm uninstall -g fastcoder
make register NAME=my-app DIR=/path/to/repo
make list
make remove TARGET=my-app
make check # all projects
make check TARGET=my-app # one project
make reports LIMIT=10
make serve # default port 4787
make serve PORT=8080
make cron-install # */15 * * * * by default
make cron-install SCHEDULE="*/30 * * * *"
make cron-uninstall
make cron-status
make hooks-install # opt in to the .githooks/ hooks
make hooks-uninstall
make hooks-status
make run TARGET=my-app CMD="git status"
make menu # interactiveSub-makefiles:
make/install.mk install, build, build-web, watch, dev, install-global, update-global, update-global-full, uninstall-global, clean, menu
make/npm.mk ci, build-all, deps-update, pack, publish, full-publish, check-next-tag, full-publish-update (npm package/release)
make/projects.mk register, list, remove
make/check.mk check, reports
make/serve.mk serve
make/cron.mk cron-install, cron-uninstall, cron-status
make/hooks.mk hooks-install, hooks-uninstall, hooks-status (see .docs/guidelines/git-hooks.md)
make/run.mk run<tasks-folder>/config.json example
Place this file inside a registered project (the folder defaults to .docs/,
override with TASKS_FOLDER or the global settings):
{
"checks": ["git status --porcelain", "npm outdated --json"],
"notifications": {
"onCheckFailure": [
{ "type": "macos" },
{ "type": "webhook", "url": "https://hooks.slack.com/services/..." }
]
}
}Each command is executed inside the project folder during fastcoder check,
and its stdout/stderr/exit code are stored in the report.
notifications.onCheckFailure lists the push channels used when a check fails
(any command exiting non-zero, or the tasks folder missing). Supported entries
are { "type": "macos" } (an osascript desktop notification), { "type":
"linux" } (notify-send) and { "type": "webhook", "url": "..." }, which
POSTs { project, kind, summary, dashboardUrl } as JSON. Unknown or invalid
entries — an unrecognised type, a webhook without a url — are ignored, and
a notifier that fails is logged as a warn (see fastcoder logs) without
affecting the check itself. Nothing is sent when every check succeeds.
Releasing
- Bump the version in
package.json(e.g.npm version patch). - Run
make release— it tagsv<version>and pushes the tag toorigin. - The tag push triggers the
Publish npm packageGitHub Actions workflow (.github/workflows/publish-npm.yml), which builds, tests, and publishes the package to npm. - The workflow requires an
NPM_TOKENrepository secret with publish access to the package on npm.
Layout (TypeScript)
src/
cli.ts # entry: runs runMain() when invoked directly
program.ts # buildProgram() + runCommand() (commander wiring)
config.ts # paths/constants
cli/ # one file per CLI command (commander actions)
domain/ # Project, Report, TaskException, ActionLog, Execution (typed)
application/ # use-case services
actions/ # single-responsibility actions (run-claude-task)
infrastructure/ # better-sqlite3, fs, shell, system-cron, express
tsconfig.json # target ES2020, module commonjs, strict, outDir dist
dist/ # compiled output (created by `make build`)
bin/fastcoder.js # thin shim: require('../dist/cli').runMain()npm install runs the prepare script which compiles to dist/. Both
fastcoder (compiled) and make dev (via ts-node src/cli.ts) work.
