From bb8f5bd6754880edb39bc057bae2b86414b9d979 Mon Sep 17 00:00:00 2001 From: HerenderKumar Date: Tue, 21 Jul 2026 10:14:56 +0530 Subject: [PATCH] docs(cli): surface --code-only in the extract usage and README (#2071) The top-level `graphify --help` has listed --code-only since #1734, but the `graphify extract` usage string and the README never mentioned it. A user evaluating graphify on a "can this run with no network call" constraint sees the extract usage / README first and can conclude the flag doesn't exist. Add --code-only to the extract usage line, name it in the Privacy section and the command reference, and add a test asserting the usage advertises it. --- README.md | 3 ++- graphify/cli.py | 2 +- tests/test_extract_code_only_cli.py | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 90ed2105..2f273566 100644 --- a/README.md +++ b/README.md @@ -530,7 +530,7 @@ These are only needed for **headless / CI extraction** (`graphify extract`). Whe ## Privacy -- **Code files** — processed locally via tree-sitter. Nothing leaves your machine. A code-only corpus requires no API key — `graphify extract` runs fully offline. +- **Code files** — processed locally via tree-sitter. Nothing leaves your machine. A code-only corpus requires no API key — `graphify extract` runs fully offline. On a mixed repo, add `--code-only` to index just the code and skip the docs/PDFs/images that would otherwise need an LLM. - **Video / audio** — transcribed locally with faster-whisper. Nothing leaves your machine. - **Docs, PDFs, images** — sent to your AI assistant for semantic extraction (via the `/graphify` skill, using whatever model your IDE session runs). Headless `graphify extract` requires `GEMINI_API_KEY` / `GOOGLE_API_KEY` (Gemini), `MOONSHOT_API_KEY` (Kimi), `ANTHROPIC_API_KEY` (Claude), `OPENAI_API_KEY` (OpenAI), `DEEPSEEK_API_KEY` (DeepSeek), a running Ollama instance (`OLLAMA_BASE_URL`), AWS credentials via the standard provider chain (Bedrock - no API key needed, uses IAM), or the `claude` CLI binary (Claude Code - no API key needed, uses your Claude subscription). The `--dedup-llm` flag uses the same key. - **Data residency** — `graphify extract` auto-detects which provider to use based on which API key is set (priority: Gemini → Kimi → Claude → OpenAI → DeepSeek → Azure → Bedrock → Ollama). For code with data-residency requirements, use `--backend ollama` (fully local) or pass an explicit `--backend` flag. Kimi (`MOONSHOT_API_KEY`) routes to Moonshot AI servers in China. @@ -632,6 +632,7 @@ graphify-out/ /graphify # run on current directory /graphify ./raw # run on a specific folder /graphify ./raw --mode deep # more aggressive relationship extraction +/graphify ./raw --code-only # index code only — local AST, no API key (skips docs/PDFs/images) /graphify ./raw --update # re-extract only changed files /graphify ./raw --directed # preserve edge direction /graphify ./raw --cluster-only # rerun clustering on existing graph diff --git a/graphify/cli.py b/graphify/cli.py index b6da9020..06942728 100644 --- a/graphify/cli.py +++ b/graphify/cli.py @@ -2427,7 +2427,7 @@ def dispatch_command(cmd: str) -> None: print( "Usage: graphify extract [--backend gemini|kimi|claude|openai|deepseek|ollama] " "[--model M] [--mode deep] [--out DIR|--output DIR] [--google-workspace] [--no-cluster] " - "[--no-gitignore] " + "[--no-gitignore] [--code-only] " "[--max-workers N] [--token-budget N] [--max-concurrency N] " "[--api-timeout S] [--postgres DSN] [--cargo] [--allow-partial] [--timing]", file=sys.stderr, diff --git a/tests/test_extract_code_only_cli.py b/tests/test_extract_code_only_cli.py index 0878db07..437f5bdb 100644 --- a/tests/test_extract_code_only_cli.py +++ b/tests/test_extract_code_only_cli.py @@ -56,6 +56,19 @@ def test_mixed_repo_without_key_errors_and_points_at_code_only(tmp_path): assert "--code-only" in r.stderr, "the no-key error must point users at --code-only" +def test_extract_usage_advertises_code_only(tmp_path): + """#2071: --code-only must be discoverable in the extract usage text, not only + by triggering the no-key error. `graphify extract` with no path prints usage.""" + r = subprocess.run( + [PYTHON, "-m", "graphify", "extract"], + cwd=tmp_path, capture_output=True, text=True, + ) + assert r.returncode != 0 + assert "--code-only" in r.stdout + r.stderr, ( + "extract usage must advertise --code-only (#2071)" + ) + + def _run_relative_out(repo: Path, *extra: str): """Like _run but with a RELATIVE GRAPHIFY_OUT so --out/--output controls the parent dir (an absolute GRAPHIFY_OUT would override the flag)."""