Scan where the code lives.
The CLI reads your repositories on a laptop or in CI, finds the routes, calls, queues and models, and uploads only the resulting graph to your workspace. It is the same scanner our hosted runner uses, so both land identically. On a pull request it tells you what the change breaks.
$ npm install -g kuuhaku $ kuuhaku login --token <token from the app> $ kuuhaku scan ~/work/company --push $ kuuhaku check ~/work/company
Install
npm is the way to go: one command on every system with Node 18 or newer, and updates with npm update -g.
The command works in every folder after one install.
npm install -g kuuhaku
npm fetches the package on each run; good for CI and a first try.
npx kuuhaku scan . --push
One file for Windows, macOS or Linux. No Node needed: download, put it on the PATH, run it.
kuuhaku.exe scan C:\work --push
For CI systems that only run containers. The folder is mounted read-only.
docker run --rm -v "$PWD:/code:ro" \ -e KUUHAKU_TOKEN kuuhaku/cli \ scan /code --push
Through the system's package manager, updated with the rest of the machine.
brew install kuuhaku scoop install kuuhaku
Connect a machine
- Get the workspace's push token.
In the app, on the CLI page or in Settings, Scanning. The token can only upload graphs to that workspace; it is shown once.
- Log in from the terminal.
Once per machine. The token is kept in
~/.kuuhaku, readable by your user only.$ kuuhaku login --token <token> --api https://api.your-domain - Scan and push.
Point it at a folder of repositories, or at an architecture.yaml. The machine appears on the workspace's CLI page with its system, version and last push.
$ kuuhaku scan ~/work/company --push
Commands
kuuhaku scan [folder | architecture.yaml]Scans and writes graph.json. A folder of repositories scans every git repository in it, up to three levels down; one repository scans its services.
kuuhaku check [folder | architecture.yaml]What the changes in its repositories break: routes their callers lose, calls no route serves, queues left without a publisher. Each repository is compared with its base branch, nothing is pushed, and it exits 1 when something breaks.
kuuhaku login --token <token> [--api <url>]Connects this machine to a workspace and checks the token on the way.
kuuhaku push [graph.json]Uploads a graph written earlier; the last scan when no file is named.
kuuhaku statusThis machine, the API, and whether the token still opens the workspace.
kuuhaku init [folder]Writes an architecture.yaml listing the repositories found, to add hosts, docs folders and connections the code cannot show.
kuuhaku logoutForgets the token. The machine keeps its id, so it stays one entry in the workspace.
--pushUpload the graph when the scan ends.
--networkLatest versions and advisories from the npm registry and OSV. Package names leave the machine; nothing else does.
--out <dir>Where graph.json goes; ~/.kuuhaku/out/<name> by default.
--base <ref>check: the branch or commit to compare with. The remote's default branch when not given.
--markdown <file>check: also write the report as a pull request comment, each file and line linked to the repository's host.
KUUHAKU_TOKENPush without logging in, for CI.
KUUHAKU_HOMEWhere the CLI keeps its folder, for runners with a read-only home.
KUUHAKU_MACHINE_NAMEThe name this machine gets in the workspace.
In CI
Scan on every push to main. Save the token as the repository secret KUUHAKU_TOKEN; the job appears as one machine, named after the repository.
name: Kuuhaku
on:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 400
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx kuuhaku scan . --push --api https://api.your-domain
env:
KUUHAKU_TOKEN: ${{ secrets.KUUHAKU_TOKEN }}
Check every pull request. The job fails when the change breaks a caller, and the report goes on the pull request as a comment that the next run updates. Nothing is pushed, so no token is needed.
name: Kuuhaku check
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx kuuhaku check . --base origin/${{ github.base_ref }} --markdown check.md
- if: always() && hashFiles('check.md') != ''
run: gh pr comment ${{ github.event.pull_request.number }} --edit-last --body-file check.md || gh pr comment ${{ github.event.pull_request.number }} --body-file check.md
env:
GH_TOKEN: ${{ github.token }}
On Bitbucket Pipelines, fetch the destination branch first, since a pipeline clones only its own: git fetch origin "+refs/heads/$BITBUCKET_PR_DESTINATION_BRANCH:refs/remotes/origin/$BITBUCKET_PR_DESTINATION_BRANCH", then npx kuuhaku check . --base origin/$BITBUCKET_PR_DESTINATION_BRANCH. A workspace of several repositories needs the others checked out beside the changed one; they are only read.
What leaves the machine
graph.json and nothing else. You can open it before pushing: kuuhaku scan without --push writes it and stops.
- Route paths and methods, with file and line
- Call sites, queue and socket names, model fields
- Three lines of code around each item left for review
- Env key names, never their values
- Dependency names and versions
- Commit counts and author names per repo
- Whole source files
- Env values and secrets
- Database contents
The hosted runner is the other way to scan: it clones with your read-only key into a temporary folder, scans, keeps the graph and deletes the checkout. With the CLI only the graph reaches us. More on the security page.