falsegreen-skill CLI

July 8, 2026 ยท View on GitHub

Command-line interface for running the falsegreen J1-J6 protocol against test files. The CLI sends each file to an LLM provider with llm.md as the system prompt and prints the resulting findings report. Zero dependencies, Node.js 18 or newer.

Install

npm install -g falsegreen-skill

Or run without installing:

npx falsegreen-skill analyze tests/test_payment.py

Quick start

Anthropic (default provider)

export ANTHROPIC_API_KEY=sk-ant-...
falsegreen-skill analyze tests/test_payment.py

OpenAI

export OPENAI_API_KEY=sk-...
falsegreen-skill analyze tests/test_payment.py --provider openai

Google Gemini

export GEMINI_API_KEY=...
falsegreen-skill analyze tests/test_payment.py --provider gemini

Groq (openai-compatible)

export FALSEGREEN_API_KEY=gsk_...
falsegreen-skill analyze tests/test_payment.py \
  --provider openai-compatible \
  --base-url https://api.groq.com/openai/v1 \
  --model llama-3.3-70b-versatile

Ollama (local, openai-compatible)

export FALSEGREEN_API_KEY=ollama
falsegreen-skill analyze tests/test_payment.py \
  --provider openai-compatible \
  --base-url http://localhost:11434/v1 \
  --model qwen2.5-coder:32b

The same pattern works for configured OpenAI-compatible providers: pass their base URL and model name, and set FALSEGREEN_API_KEY to the provider key.

Commands

falsegreen-skill analyze <file...> [options]
falsegreen-skill generate <spec-file> [--lang <language>] [options]
falsegreen-skill fix <test-file> --case <code> --line <n> [options]
falsegreen-skill --help
falsegreen-skill --version

analyze is Mode A (review); generate is Mode B (authoring); fix is Mode C (AI-fix). Multiple files given to analyze are analyzed in separate API calls. Plain-text output is printed under a === {filename} === header. With --json, the CLI validates each model response against the canonical schema and emits one aggregate JSON report.

Flags

FlagDescriptionDefault
--provider <name>anthropic, openai, gemini, or openai-compatibleanthropic
--model <model>Model override. Required for openai-compatibleper provider (see below)
--base-url <url>API base URL. Required for openai-compatiblenone
--jsonValidate and output a JSON report conforming to schema/report.jsonoff
--conventions <file>Conventions YAML/text block injected per SKILL.md Step 0none
--temperature <n>Sampling temperature 0.0โ€“1.0. Skipped for OpenAI o-series (o3, o4-mini)0.2
--max-tokens <n>Max output tokens per request4096
--fail-on-highExit with code 2 when any HIGH finding is present. Requires --jsonoff

Default models: anthropic uses claude-sonnet-5, openai uses gpt-5, gemini uses gemini-2.5-flash. For deep case 18 analysis, pass --model claude-opus-4-8 (Anthropic) or --model o3 (OpenAI). When using o3, --temperature is ignored automatically.

Environment variables

VariableUsed by
ANTHROPIC_API_KEY--provider anthropic
OPENAI_API_KEY--provider openai (and fallback for openai-compatible)
GEMINI_API_KEY--provider gemini
FALSEGREEN_API_KEY--provider openai-compatible (takes precedence over OPENAI_API_KEY)

Exit codes

CodeMeaning
0Analysis completed (findings may still exist; this is an analysis tool, not a gate)
1Error: missing file, missing API key, bad flag, invalid JSON, schema mismatch, non-2xx API response
2--fail-on-high was set and the JSON report contains at least one HIGH finding

fix - propose a stronger test and prove it

falsegreen-skill fix <test-file> --case <code> --line <n> [options]

analyze finds a false-green; fix proposes a stronger test and runs a local gate to prove it before you trust it. It is opt-in, Python/pytest only, and propose-only: it prints a test-file patch but never applies it and never edits production code. The provider flags above apply; fix adds these:

FlagDescription
--case <code>Catalog code of the finding to fix. V1 fixable set: C2b, C20, C21, C5, C7
--line <n>Line of the finding in the test file (1-indexed)
--sut <file>Production file the test protects. Required for a validated fix
--sut-line <n>Line in the SUT to mutate. Defaults to --line
--cheapValidation tier: parse + preserve only, no mutation gate
# propose a patch for a C2b finding and run the full gate against the real SUT
falsegreen-skill fix tests/test_discount.py --case C2b --line 14 \
  --sut src/discount.py --sut-line 12

# parse + preserve only, no mutation gate (no runnable SUT, or a quick pass)
falsegreen-skill fix tests/test_discount.py --case C5 --line 9 --cheap

# machine-readable gate verdict (schema/fix-validation.json)
falsegreen-skill fix tests/test_discount.py --case C20 --line 22 \
  --sut src/discount.py --json

On a clean replica the gate runs three checks: the patch parses (py_compile), it passes pytest against the real code (preserve), and it fails on a line-scoped mutation of the SUT. A patch is accepted only when it passes on correct code and goes red on the mutant. Exit code is 0 on accept, 1 on reject/unvalidated. Without --sut (or with --cheap) the gate degrades to propose-only and labels the fix unvalidated. The honest limit: it proves the fix catches the targeted mutant, not every possible bug; JS/TS/Robot and the deep semantic cases (10/11/12/18) are v2.

generate - author a test from a spec (Mode B)

falsegreen-skill generate <spec-file> [--lang <language>] [options]

Renders a language-neutral test-spec into a real test, then runs analyze (Mode A) on the result so a false-green test cannot pass the self-check undetected. It catches false-green shapes, not a wrong-but-well-formed oracle. The spec is a schema/test-spec.json file (YAML or JSON); examples/authoring/apply-discount.spec.yaml is one spec rendered into all four stacks.

FlagMeaningDefault
--lang <language>python, typescript, javascript, tsx, jsx, or robot. tsx/jsx cover the React side of the JS/TS family (same shared JS* catalog falsegreen-js uses over .js/.ts/.tsx/.jsx). One language per run - the spec is the single source, re-run to render another stackspec's first languages entry, else python
# render the example spec to a Python test and self-check it
falsegreen-skill generate examples/authoring/apply-discount.spec.yaml --lang python

# same spec, TypeScript
falsegreen-skill generate examples/authoring/apply-discount.spec.yaml --lang typescript

# machine-readable: { language, test, self_check, self_check_passed, self_check_error }
falsegreen-skill generate my-spec.yaml --lang python --json

Offline guards (no API call). The command refuses early, exit 1, when the language is unknown, the spec file is missing, or the spec carries no oracle: / expected: key. The last is the point: a test generated from the code's current output only freezes the bug (a characterization test). The guard anchors on the keys, so the words in a comment no longer pass; the oracle's value is your responsibility.

Self-check and exit codes. After generating, the CLI runs Mode A on the test. If it trips a HIGH false-green finding, the CLI revises once and re-checks (bounded to one revision - it is a command, not an agent loop). The exit code is the CI contract, and it fails closed:

ExitStateMeaning
0PASSEDself-check ran, no HIGH false-green
1FAILEDa surviving false-green was confirmed (also: bad spec / API error via the offline guards above)
3UNVERIFIEDthe self-check could not run; the test is printed to stdout, the banner to stderr, and it is not accepted

Gate CI on the exit code, or on self_check_passed in --json. The self-check is a same-model static review, not an execution: it does not run the test, verify it compiles/imports, or confirm the oracle value. generate needs a model that both fits the ~33k-token prompt and can emit the JSON report - see the provider table below.

OpenAI-compatible providers

Every provider that speaks the OpenAI Chat Completions API works through --provider openai-compatible: set FALSEGREEN_API_KEY to the provider key, point --base-url at the /v1 root (the CLI appends /chat/completions), and pass the provider's model id with --model. The table below covers the common hosts. "Fits 33k?" is whether the free tier accepts the skill's ~33k-token system prompt; a paid tier on the same host usually lifts the cap.

Provider--base-urlExample --modelFree tier fits 33k prompt?
Groqhttps://api.groq.com/openai/v1llama-3.3-70b-versatileNo - 12k TPM cap (HTTP 413)
Cerebrashttps://api.cerebras.ai/v1gpt-oss-120bNo - token quota (HTTP 429)
OpenRouterhttps://openrouter.ai/api/v1meta-llama/llama-3.3-70b-instruct (or :free)Partial - :free models are rate-limited upstream
NVIDIA NIMhttps://integrate.api.nvidia.com/v1meta/llama-3.3-70b-instructYes, on most models
DeepInfrahttps://api.deepinfra.com/v1/openaimeta-llama/Llama-3.3-70B-Instruct-TurboNo - needs positive balance (HTTP 402)
Mistralhttps://api.mistral.ai/v1mistral-large-latestPaid
DeepSeekhttps://api.deepseek.com/v1deepseek-chatPaid
Fireworkshttps://api.fireworks.ai/inference/v1accounts/fireworks/models/llama-v3p3-70b-instructPaid
Alibaba Qwenhttps://dashscope-intl.aliyuncs.com/compatible-mode/v1qwen-plus (must be enabled on the account)Region/plan dependent
Hugging Facehttps://router.huggingface.co/v1meta-llama/Llama-3.3-70B-InstructYes, within monthly credits
Coherehttps://api.cohere.ai/compatibility/v1command-a-03-2025Trial key works, rate-limited
Ollama (local)http://localhost:11434/v1qwen2.5-coder:32bYes - local, no cap, any key placeholder
Ollama Cloudhttps://ollama.com/v1gpt-oss:120bPlan dependent
# example: OpenRouter (verified end-to-end for generate and analyze)
export FALSEGREEN_API_KEY=sk-or-...
falsegreen-skill analyze tests/test_payment.py \
  --provider openai-compatible \
  --base-url https://openrouter.ai/api/v1 \
  --model meta-llama/llama-3.3-70b-instruct --max-tokens 8192

Notes: Cohere is reached through its dedicated OpenAI-compatibility path (/compatibility/v1), not its native /v2/chat. Ollama ignores the key, so any placeholder (FALSEGREEN_API_KEY=ollama) works. Raise --max-tokens (8192+) for reasoning models that spend budget on chain-of-thought and get cut off mid-report.

CI usage

Combine --json with --fail-on-high to gate a pipeline on HIGH-confidence findings. GitHub Actions example:

- name: Detect false-positive tests
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
  run: |
    npx falsegreen-skill analyze tests/test_payment.py tests/test_orders.py \
      --json --fail-on-high > falsegreen-report.json

- name: Upload report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: falsegreen-report
    path: falsegreen-report.json

The step fails with exit 1 if the model returns invalid JSON or fields that do not match schema/report.json. It fails with exit 2 only when the validated report contains a HIGH-confidence finding. LOW findings and clean tests keep the pipeline green.

Project conventions

If your project uses custom assertion helpers or intentional patterns that look like smells, declare them in a conventions file and pass it with --conventions:

conventions:
  custom_assertion_helpers:
    - verify_payment_state
  intentional_patterns:
    - "smoke tests in tests/smoke/ assert only that no exception is raised"

The block is injected before the file content, per Step 0 of the protocol, so the model incorporates it before applying any judgment.