forge-doctor
v0.1.2
Published
Forge repository health-check, compliance, and readiness CLI.
Readme
forge-doctor
forge-doctor is a local, read-only repository health-check CLI for JavaScript
and TypeScript projects. It detects practical signals about project readiness,
configuration, package hygiene, TypeScript safety, environment variable
documentation, GitHub Actions setup, and framework-specific gaps.
It is designed for humans first: run it locally, see what matters, fix the highest-impact issues, and optionally emit JSON for CI, dashboards, or Forge.
MVP 1 is implemented and published as [email protected].
Why It Exists
Forge is a governed engineering control plane for AI agents and repository automation. Before an agent can safely work in a repository, Forge needs a structured snapshot of that repository's technical health.
forge-doctor provides that snapshot without running project code, installing
dependencies, mutating files, or reading secret values.
Use it to answer questions like:
- Is this repository ready for CI?
- Are minimum project files and package scripts present?
- Does TypeScript have a safe baseline?
- Are environment variables documented without exposing values?
- Are GitHub Actions workflows missing risky defaults?
- Does the repository look like React, Vite, NestJS, or Cloudflare Workers?
- Can Forge receive a stable machine-readable health report?
Quick Start
Run without installing:
npx forge-doctor scanInstall in a project:
pnpm add -D forge-doctorAdd a script:
{
"scripts": {
"doctor": "forge-doctor scan"
}
}Run the scan:
pnpm doctorCreate a baseline config:
forge-doctor init --yesEmit JSON for automation:
forge-doctor scan --json --output forge-report.jsonFail CI on high-severity findings:
forge-doctor scan --fail-on highInstallation
One-off usage
npx forge-doctor scanProject-local usage
pnpm add -D forge-doctor
pnpm exec forge-doctor scanGlobal usage
npm install -g forge-doctor
forge-doctor scanCommands
forge-doctor scan [path]
Scans the repository at path. If path is omitted, the current working
directory is scanned.
forge-doctor scan
forge-doctor scan ../my-app
forge-doctor scan --json
forge-doctor scan --fail-on highOptions:
| Option | Description |
| --- | --- |
| --json | Print the stable JSON report to stdout. |
| --output <file> | Write the JSON report to a file. Terminal output still goes to stdout unless --json is used. |
| --send | Upload the report to the Forge API. |
| --api-url <url> | Forge API URL. Overrides config and environment. |
| --token <token> | Forge API token. Overrides config and environment. |
| --offline | Disable all upload behavior, even if upload is enabled elsewhere. |
| --config <file> | Load a custom config file. |
| --level <level> | quick, standard, or deep. In MVP 1, all levels run the quick scan and non-quick levels print a warning. |
| --fail-on <severity> | Exit with code 1 when a finding at or above the severity exists. |
| --include <list> | Run only matching scanner ids or categories. Comma-separated. |
| --exclude <list> | Skip matching scanner ids or categories. Comma-separated. |
| --no-color | Disable terminal colors. Reserved for terminal compatibility. |
| --verbose | Reserved for future detailed logs. |
| --debug | Reserved for future internal debugging logs. |
Examples:
forge-doctor scan --include typescript,environment
forge-doctor scan --exclude ci
forge-doctor scan --level deep
forge-doctor scan --config .forge/doctor.ymlforge-doctor init
Creates .forge/doctor.yml.
forge-doctor init
forge-doctor init --yes
forge-doctor init --profile viteOptions:
| Option | Description |
| --- | --- |
| --yes | Overwrite an existing config without prompting. |
| --profile <name> | Generate a baseline for default, react, vite, nestjs, or workers. |
If the config already exists and --yes is not used, the CLI prompts before
overwriting. Non-file targets such as directories are rejected.
forge-doctor version
Prints the package version.
forge-doctor versionConfiguration
Default config path:
.forge/doctor.ymlConfiguration precedence:
- CLI flags.
- Environment variables.
.forge/doctor.yml.- Internal defaults.
Minimal example:
version: 1
project:
name: auto
scan:
maxFileSizeKb: 512
ignores:
- '**/.git/**'
- '**/node_modules/**'
- '**/dist/**'
- '**/build/**'
- '**/.next/**'
- '**/.turbo/**'
- '**/coverage/**'
- '**/.wrangler/**'
- '**/.cache/**'
- '**/.test-tmp/**'
level: quick
offline: false
include: []
exclude: []
compliance:
requiredFiles:
- README.md
- .gitignore
- .env.example
package:
requiredScripts:
- lint
- test
- typecheck
- build
requiredFields:
- packageManager
- engines.node
env:
requireExampleForUsedVars: true
thresholds:
failOn: high
upload:
enabled: false
apiUrl: https://api.example.testGlob patterns that start with * should be quoted in YAML. forge-doctor init
does this automatically.
Environment Variables
| Variable | Purpose |
| --- | --- |
| FORGE_API_URL | Forge API URL for uploads. |
| FORGE_TOKEN | Forge API token for uploads. |
| FORGE_DOCTOR_CONFIG | Alternative config path when --config is not provided. |
| FORGE_REPOSITORY_ID | Optional Forge repository id included in safe metadata. |
| FORGE_INSTALLATION_ID | Optional Forge installation id included in safe metadata. |
| CI | CI detection signal. |
| GITHUB_ACTIONS | GitHub Actions detection signal. |
| GITHUB_REPOSITORY | Safe GitHub repository metadata. |
| GITHUB_SHA | Safe commit metadata. |
| GITHUB_REF | Safe branch/ref metadata. |
| GITHUB_RUN_ID | Safe CI run metadata. |
| GITHUB_RUN_ATTEMPT | Safe CI attempt metadata. |
Secrets such as FORGE_TOKEN are used only for upload authorization. They are
not written into report payloads.
Output Modes
Terminal Output
Default output is a human-readable summary with:
- overall health score;
- finding counts by severity;
- stack summary;
- high-priority findings;
- scanner run status.
forge-doctor scanJSON Output
forge-doctor scan --jsonJSON output uses:
forge.doctor.report.v1The report includes:
- repository metadata;
- runtime environment metadata;
- detected stack fingerprint;
- summary counts;
- category and overall scores;
- normalized findings;
- scanner runs;
- safe metadata.
The JSON report is meant to be stable enough for CI and dashboards. Timestamps and scanner durations are intentionally runtime-specific.
Output File
forge-doctor scan --output forge-report.json--output always writes the JSON report. Without --json, stdout remains a
terminal report.
Upload To Forge
Uploads are opt-in.
FORGE_API_URL=https://api.forge.noagi.cloud \
FORGE_TOKEN=... \
forge-doctor scan --sendOr with flags:
forge-doctor scan \
--send \
--api-url https://api.forge.noagi.cloud \
--token "$FORGE_TOKEN"Upload behavior:
- sends
POST /v1/doctor/scans; - includes
Authorization,Content-Type, andUser-Agentheaders; - sends the safe
ScanReportJSON body; - returns exit code
4if required upload fails; - never uploads when
--offlineis present.
Local-only mode:
forge-doctor scan --offlineExit Codes
| Code | Meaning |
| --- | --- |
| 0 | Scan completed and no finding met the configured failure threshold. |
| 1 | A finding met or exceeded --fail-on or thresholds.failOn. |
| 2 | CLI usage error, such as an unknown flag or invalid severity. |
| 3 | Internal scan failure, such as a scanner crash or invalid file that blocks scanner execution. |
| 4 | Upload was required but failed. |
Severity order:
critical > high > medium > low > infoExample:
forge-doctor scan --fail-on mediumThis exits with 1 if any critical, high, or medium finding exists.
Scanners
Stack Detector
Detects high-level repository shape:
- package manager:
pnpm,npm,yarn,bun, orunknown; - monorepo signals;
- TypeScript and JavaScript;
- React;
- Vite;
- NestJS;
- Cloudflare Workers;
- GitHub Actions;
- package manifests;
- lockfiles;
- common config files.
Compliance Scanner
Checks for baseline repository files and package metadata:
- required files such as
README.md,.gitignore, and.env.example; - required scripts such as
lint,test,typecheck, andbuild; - required package fields such as
packageManagerandengines.node; - missing
.forge/doctor.yml.
Package Scanner
Checks package hygiene:
- multiple lockfiles;
- package manager mismatch;
- missing lockfile;
- app packages missing
private: true; - lifecycle scripts such as
postinstall.
Lifecycle scripts are informational in MVP 1 because they may be legitimate, but they are useful for human review.
TypeScript Scanner
Checks TypeScript readiness:
- missing
tsconfig.json; strictmissing or disabled;noImplicitAny: false;allowJs: true;- missing
typecheckscript; compilerOptions.pathswithoutbaseUrl.
The scanner reads config files; it does not run tsc.
Environment Scanner
Checks environment variable documentation and client-side exposure risk:
- detects
process.env.NAME; - detects
process.env["NAME"]; - detects
import.meta.env.NAME; - reports used variables missing from
.env.example,.env.sample, or.env.template; - reports secret-like
VITE_variable names such asVITE_API_SECRET; - reports committed dotenv files such as
.envwithout reading or reporting values.
The scanner reports variable names, not secret values.
GitHub Actions Scanner
Checks basic CI safety:
- missing workflows;
- jobs without
timeout-minutes; permissions: write-all;npm installin workflows;actions/setup-nodewithout dependency cache;- actions pinned to floating branches such as
@mainor@master.
Framework Hint Scanner
Adds framework-specific hints:
- React projects missing
eslint-plugin-react-hooks; - NestJS projects missing
nest-cli.json; - NestJS projects missing
class-validatororclass-transformer; - Workers projects missing
wrangler.toml,wrangler.json, orwrangler.jsonc; - Workers projects missing
@cloudflare/workers-types.
Include And Exclude
--include and --exclude accept scanner ids or categories.
Scanner ids:
compliance
package
typescript
environment
github-actions
frameworkCategories:
compliance
dependencies
typescript
environment
ci
framework
maintainabilityExamples:
forge-doctor scan --include typescript,environment
forge-doctor scan --exclude ciCI Example
name: Forge Doctor
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
jobs:
doctor:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm exec forge-doctor scan --json --output forge-report.json --fail-on highWith upload:
- run: pnpm exec forge-doctor scan --json --output forge-report.json --send --fail-on high
env:
FORGE_API_URL: ${{ vars.FORGE_API_URL }}
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}Safety Model
forge-doctor scan is observational. It does not:
- execute repository code;
- run package scripts;
- install dependencies in the scanned repository;
- modify scanned files;
- perform auto-fixes;
- read or upload dotenv values;
- upload anything unless explicitly enabled.
The scanner may read safe project files such as package.json, tsconfig.json,
workflow YAML, and source files within the configured size limit. Findings may
include paths, line numbers, rule ids, variable names, and recommendations.
What MVP 1 Does Not Do
MVP 1 intentionally does not include:
- deep SAST;
- full vulnerability scanning;
- full secret scanning;
- dependency graph analysis;
- coverage analysis;
- bundle analysis;
- SARIF output;
- SBOM generation;
- GitHub issue creation;
- auto-fixes;
- LLM analysis.
Those are possible future additions, but the current package focuses on fast, safe, practical readiness checks.
Troubleshooting
forge-doctor scan returns code 1
A finding met your configured threshold. Run without --fail-on, or inspect the
terminal/JSON report and fix the findings.
forge-doctor scan --send returns code 4
Upload was required but failed. Check:
FORGE_API_URLor--api-url;FORGE_TOKENor--token;- network access;
- Forge API availability.
Use --offline to force local-only behavior.
Config fails to parse
Quote glob patterns that start with *:
scan:
ignores:
- '**/node_modules/**'forge-doctor init generates quoted patterns automatically.
The scan is seeing generated files
Add ignores to .forge/doctor.yml:
scan:
ignores:
- '**/node_modules/**'
- '**/dist/**'
- '**/.cache/**'
- '**/test/fixtures/**'Project-specific fixture ignores should live in project config, not in the package defaults.
Development
This repository uses pnpm.
pnpm install
pnpm test
pnpm typecheck
pnpm lint
pnpm buildPackage smoke:
pnpm pack --pack-destination .test-tmp/pack-smoke
pnpm dlx "$(pwd)/.test-tmp/pack-smoke/forge-doctor-0.1.2.tgz" versionDogfood:
node dist/bin.js scan . --json --offline --output .test-tmp/dogfood-report.json