Command line

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.

npm Recommended

The command works in every folder after one install.

npm install -g kuuhaku
npx No install

npm fetches the package on each run; good for CI and a first try.

npx kuuhaku scan . --push
Executable Soon

One file for Windows, macOS or Linux. No Node needed: download, put it on the PATH, run it.

kuuhaku.exe scan C:\work --push
Docker Soon

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
Homebrew and Scoop Soon

Through the system's package manager, updated with the rest of the machine.

brew install kuuhaku
scoop install kuuhaku

Connect a machine

  1. 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.

  2. 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
  3. 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 status

This 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 logout

Forgets the token. The machine keeps its id, so it stays one entry in the workspace.

--push

Upload the graph when the scan ends.

--network

Latest 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_TOKEN

Push without logging in, for CI.

KUUHAKU_HOME

Where the CLI keeps its folder, for runners with a read-only home.

KUUHAKU_MACHINE_NAME

The 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.

In the graph
  • 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
Never
  • 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.