npm.io
0.2.0 • Published yesterdayCLI

@nouman-amjad/cairn

Licence
Apache-2.0
Version
0.2.0
Deps
0
Size
151 kB
Vulns
0
Weekly
0
Stars
5

cairn

npm ci license node dependencies

Platform analysis, a live dashboard and log chat for any project. Zero dependencies. Node 18.17+.

npx @nouman-amjad/cairn analyze

That is the whole first step. No config file, no signup, no API key.

Cairn dashboard

Findings, logs, services and chat

Findings

Logs

Services

Chat

Install it once and the command shortens to cairn:

npm install -g @nouman-amjad/cairn
cairn analyze
Cairn  /home/you/checkout-api
  score        62/100  (81 ms)
  stack        node, docker, kubernetes, github-actions
  files        1,284
  services     checkout-api, worker
  findings     2 high · 3 medium · 1 low

  docker
  high   Container runs as root
         Dockerfile
         No USER instruction switches away from root. A process escape starts with uid 0.
         fix Add a non-root user and `USER 10001:10001` before CMD.

  kubernetes
  high   Workload has no resource requests or limits
         k8s/deployment.yaml
         Without a memory limit one pod can evict every neighbour on the node.
         fix Set resources.requests.cpu and resources.limits.memory.

The dashboard

npx @nouman-amjad/cairn dashboard  # or: cairn dashboard, if installed

Opens on http://127.0.0.1:7777 with six tabs:

Tab What it shows
Overview Health score, stack, detected services, file inventory
Findings Every finding with its file, why it matters, and the fix
Services Live health probes against the services you configure
Logs Your log sources, tailed and streamed live, coloured by level
Config Every setting, editable in place, written straight back to disk
Chat Ask about the project, the findings and the logs

It binds to loopback by default, because it shows your configuration and your logs and a dashboard quietly listening on 0.0.0.0 is a data leak with a nice chart.

Configure it

npx @nouman-amjad/cairn init  # or: cairn init, if installed

Writes cairn.config.json, seeded from what it found — services it detected get health-check entries already filled in. Everything is optional.

{
  "name": "checkout-api",
  "dashboard": { "port": 7777, "host": "127.0.0.1" },
  "analyze": {
    "ignore": ["node_modules", ".git", "dist"],
    "mute": ["docker.no-healthcheck"]   // accepted risks live in the repo
  },
  "logs": {
    "files": ["logs/app.log"],
    "commands": ["kubectl logs -f deploy/checkout-api"]
  },
  "services": [
    { "name": "api", "url": "http://localhost:3000", "healthPath": "/health" }
  ],
  "chat": { "mode": "offline" }
}

Change any value from the Config tab, or:

cairn config                      # list everything
cairn config dashboard.port       # read one
cairn config dashboard.port 9000  # write one

Values are coerced to the type the default declares, so port stays a number and a typo is rejected at the point you make it rather than three layers down.

Chat about your logs

cairn chat "what should I fix first?"
cairn chat "why are there errors?"

Three modes, set with chat.mode:

  • offline (default) — deterministic correlation over the analysis and the log buffer. No network, no key, no cost. It clusters a thousand repeated errors into one fact and tells you which findings mention the same files. Plenty of "why is this failing" is a join, not an inference.
  • api — sends the analysis and a log summary to a model API. Set chat.apiKeyEnv to the env var holding your key.
  • gateway — hands the question to a running Cairn deployment: the full agent loop, real tool calls against your metrics and traces, and human approval gates on anything that writes.

In CI

npx @nouman-amjad/cairn analyze --fail-on high      # exit 1 if anything high is found
npx @nouman-amjad/cairn analyze --json > report.json
- run: npx @nouman-amjad/cairn analyze --fail-on high

What it checks

Group Examples
docker root user, unpinned base image, secrets baked into layers, apt cache left behind
k8s no resource limits, :latest images, privileged containers, missing probes
node no lockfile, no test script, no engines range, dependency sprawl
python no lockfile, unpinned requirements
terraform no remote state backend, unencrypted buckets
compose host networking, privileged services
ci no pipeline, a pipeline that never runs tests
secrets credential shapes in source, .env not gitignored
repo no README, no LICENSE, no .gitignore, files over 5 MB

Every finding carries a rule id, the file it came from, why it matters, and the fix. Mute one by adding its id to analyze.mute — so "we accepted that risk" lives in the repository and shows up in review.

As a library

import { analyze, load, exitCode } from "@nouman-amjad/cairn";

const report = analyze(load("."));
console.log(report.score, report.findings.length);
process.exitCode = exitCode(report, "high");

Why zero dependencies

Open package.json and look at dependencies. It is {}.

A tool that audits your supply chain should not enlarge it. Everything here is Node's standard library: the dashboard is node:http, the log tail is node:fs, the CLI parses its own arguments. npx @nouman-amjad/cairn downloads one small package and nothing else, and there is no transitive tree to review, upgrade, or get compromised.

Commands

cairn init                     Write cairn.config.json with detected defaults
cairn analyze                  Scan the project and print findings
cairn dashboard                Serve the live dashboard
cairn logs                     Tail configured log sources
cairn chat <question>          Ask about the project, its findings and its logs
cairn config [key] [value]     Show or set a configuration value

  --cwd <dir>        Run against another directory
  --json             Machine-readable output
  --fail-on <sev>    analyze: exit 1 at this severity or above
  --port <n>         dashboard: override the port
  --open             dashboard: open a browser

Licence

Apache-2.0. Part of Cairn.

Keywords