Skip to content

Commit b166dca

Browse files
authored
Slim down init/scan CLI flags (#34)
Reduce the option surface on two commands: whygraph init (7 flags -> 3: --agent, --force, --yes) - Drop --list-agents; the supported-agents list now renders in `whygraph init --help` via a no-rewrap epilog. - Drop --print entirely (flag + docstring mentions); the manual-merge path survives for user-scoped agents via render_snippet(). - Drop --install-assets/--no-install-assets; assets always install (still --force-gated for overwrite). - Drop --skip-preflight; preflight diagnostics always run. whygraph scan - Rename --no-llm-descriptions -> --skip-analyze (same behavior), propagated to the git-hook helper, MCP/analyze comments, CLAUDE.md, and the docs site. Tests updated (incl. rename of the scan flag test file); full suite, ruff check, and ruff format --check all pass.
1 parent 9db2751 commit b166dca

14 files changed

Lines changed: 92 additions & 141 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ CodeGraph indexing belongs to **`whygraph scan`, not `whygraph init`** — `init
8787

8888
### Auto-rescan git hooks
8989

90-
`whygraph hooks install` (opt-in; `cli/commands/hooks.py`) wires `post-commit` / `post-merge` / `post-rewrite` to keep the DBs current as the developer works — no daemon. Each hook execs a shared helper (`.whygraph/hooks/whygraph-scan`, gitignored) that runs `whygraph scan --no-llm-descriptions --no-remote` (git history + `codegraph sync` only — fast, offline, no token; LLM descriptions stay on lazy backfill). The helper is **detached** (commits return instantly) and **single-flight + coalescing** (portable `mkdir` lock + a `pending` flag, since macOS has no `flock`), so rapid commits neither stack nor drop the latest `HEAD`. Installs are **sentinel-guarded** (`# >>> whygraph managed >>>`) and append to a foreign hook rather than clobber it. The `--no-remote` flag on `scan` exists for this path; `db/engine.py` sets `PRAGMA busy_timeout` so a background rescan and a manual scan don't collide.
90+
`whygraph hooks install` (opt-in; `cli/commands/hooks.py`) wires `post-commit` / `post-merge` / `post-rewrite` to keep the DBs current as the developer works — no daemon. Each hook execs a shared helper (`.whygraph/hooks/whygraph-scan`, gitignored) that runs `whygraph scan --skip-analyze --no-remote` (git history + `codegraph sync` only — fast, offline, no token; LLM descriptions stay on lazy backfill). The helper is **detached** (commits return instantly) and **single-flight + coalescing** (portable `mkdir` lock + a `pending` flag, since macOS has no `flock`), so rapid commits neither stack nor drop the latest `HEAD`. Installs are **sentinel-guarded** (`# >>> whygraph managed >>>`) and append to a foreign hook rather than clobber it. The `--no-remote` flag on `scan` exists for this path; `db/engine.py` sets `PRAGMA busy_timeout` so a background rescan and a manual scan don't collide.
9191

9292
Deferred (net-new, not built yet): a project registry for cross-repo orchestration, a persistent/server mode, and per-branch CodeGraph/WhyGraph databases.
9393

docs/getting-started/quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ evidence WhyGraph serves.
3939
For a fast, offline pass - no remote calls, no LLM - skip both phases:
4040

4141
```bash
42-
whygraph scan --no-remote --no-llm-descriptions
42+
whygraph scan --no-remote --skip-analyze
4343
```
4444

4545
Descriptions backfill lazily later, so this is a fine way to get started quickly. See

docs/guide/editors.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ inside the repo, so you can commit it and every teammate's editor picks it up.
2121
| `vscode` (alias `copilot`) | VS Code / GitHub Copilot | `.vscode/mcp.json` |
2222
| `codex` | OpenAI Codex | `.codex/config.toml` |
2323

24-
Run `whygraph init --list-agents` to print these paths for your own checkout.
24+
Run `whygraph init --help` to see the supported agents.
2525

2626
The generated config launches `whygraph-mcp` by bare command name, so the same checked-in file works
2727
for everyone who has WhyGraph installed - no absolute paths to scrub.
@@ -32,19 +32,16 @@ for everyone who has WhyGraph installed - no absolute paths to scrub.
3232
leaves your existing files alone; pass `--force` to overwrite them.
3333

3434
```bash
35-
whygraph init --agent claude --no-install-assets # MCP wiring only, skip the .claude/ copy
36-
whygraph init --agent claude --force # overwrite existing .claude/ files
35+
whygraph init --agent claude # wire MCP + copy the .claude/ assets
36+
whygraph init --agent claude --force # overwrite existing .claude/ files
3737
```
3838

3939
## Useful flags
4040

4141
| Flag | What it does |
4242
|---|---|
43-
| `--print` | Print the MCP snippet to stdout instead of writing any file. Good for pasting by hand. |
44-
| `--list-agents` | List supported agents and their config paths, then exit. |
45-
| `--install-assets / --no-install-assets` | Copy (or skip) the agent's bundled assets. Default: copy. No-op for agents with no asset tree. |
46-
| `--skip-preflight` | Skip the host-tool diagnostics. For known-good scripted environments. |
4743
| `--force` | Overwrite existing asset files in the destination directory. |
44+
| `--yes` / `-y` | Accept all defaults without prompting (also implied off a TTY). |
4845

4946
## Verify
5047

docs/guide/scanning.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ without polluting area history.
2929

3030
| Flag | Default | What it does |
3131
|---|---|---|
32-
| `--no-llm-descriptions` | off | Skip the per-commit LLM phase. Git and GitHub crawlers still run; descriptions backfill lazily and on a later full scan. |
32+
| `--skip-analyze` | off | Skip the per-commit LLM phase. Git and GitHub crawlers still run; descriptions backfill lazily and on a later full scan. |
3333
| `--codegraph / --no-codegraph` | on | Refresh the CodeGraph index concurrently with the crawl. |
3434
| `--codegraph-image TEXT` | pinned tag | Override the Docker image for the CodeGraph fallback. Ignored when a local `codegraph` binary is found. |
3535
| `--remote / --no-remote` | on | Crawl the remote for PRs and issues per `[scan].provider`. `--no-remote` is a fast, offline, token-free scan. |
@@ -38,7 +38,7 @@ without polluting area history.
3838
A common fast pass while iterating:
3939

4040
```bash
41-
whygraph scan --no-remote --no-llm-descriptions
41+
whygraph scan --no-remote --skip-analyze
4242
```
4343

4444
!!! tip "Lazy backfill"
@@ -55,7 +55,7 @@ whygraph hooks install
5555
```
5656

5757
This wires `post-commit`, `post-merge`, and `post-rewrite` to run
58-
`whygraph scan --no-remote --no-llm-descriptions` **in the background**. Git history and a CodeGraph
58+
`whygraph scan --no-remote --skip-analyze` **in the background**. Git history and a CodeGraph
5959
`sync` only - no LLM, no remote calls - so commits stay instant and the scan is offline and
6060
token-free.
6161

docs/reference/cli.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,12 @@ agents are project-scoped, so the config file is written inside the repo.
4141

4242
| Option | Description |
4343
|---|---|
44-
| `--agent [claude\|codex\|copilot\|cursor\|vscode]` | Wire the MCP server into the named agent's config. On a terminal, skips the interactive agent prompt. |
44+
| `--agent [claude\|codex\|copilot\|cursor\|vscode]` | Wire the MCP server into the named agent's config. On a terminal, skips the interactive agent prompt. Run `whygraph init --help` for the full list of supported agents. |
4545
| `--yes` / `-y` | Accept all defaults without prompting (also implied off a TTY). Writes a default `whygraph.toml` only if none exists. |
46-
| `--print` | Print the MCP snippet to stdout instead of writing any config file. |
47-
| `--list-agents` | List supported agents (with config-file paths) and exit. |
48-
| `--install-assets / --no-install-assets` | Copy the chosen agent's bundled assets into the project. Default: enabled. No-op for agents that ship no asset tree. |
49-
| `--skip-preflight` | Skip the host-tool diagnostics that normally run first. For known-good scripted environments. |
5046
| `--force` | When installing assets, overwrite existing files in the agent's destination directory. |
5147

48+
Preflight diagnostics and asset install both always run — the chosen agent's bundled assets are copied into the repo automatically (use `--force` to overwrite local edits).
49+
5250
See [Wiring your editor](../guide/editors.md) for the per-agent paths.
5351

5452
## `whygraph scan`
@@ -59,7 +57,7 @@ picks up new commits and backfills what's missing.
5957

6058
| Option | Default | Description |
6159
|---|---|---|
62-
| `--no-llm-descriptions` | off | Skip the per-commit LLM description phase. The git and GitHub crawlers still run; descriptions backfill lazily on demand and on a later full scan. |
60+
| `--skip-analyze` | off | Skip the per-commit LLM description phase. The git and GitHub crawlers still run; descriptions backfill lazily on demand and on a later full scan. |
6361
| `--codegraph / --no-codegraph` | on | Refresh the CodeGraph index concurrently with the crawl - `codegraph sync` when an index exists, `codegraph init -i` on first run. A failure here warns rather than aborting. |
6462
| `--codegraph-image TEXT` | pinned tag | Override the Docker image used for the CodeGraph refresh fallback. Ignored when a local `codegraph` binary is found. |
6563
| `--remote / --no-remote` | on | Crawl the source-control remote (GitHub PRs / issues) per `[scan].provider`. `--no-remote` skips it for a fast, offline, token-free scan. |
@@ -99,5 +97,5 @@ whygraph hooks install
9997
```
10098

10199
The hooks wire `post-commit`, `post-merge`, and `post-rewrite` to run
102-
`whygraph scan --no-remote --no-llm-descriptions` in the background. See
100+
`whygraph scan --no-remote --skip-analyze` in the background. See
103101
[Keep it fresh](../guide/scanning.md#keep-it-fresh) for the details.

src/whygraph/agents.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class AgentTarget:
6868
Serialization format of the target file. Determines which
6969
renderer :func:`render_snippet` uses.
7070
description : str
71-
Short one-line description shown by ``whygraph init --list-agents``.
71+
Short one-line description shown in ``whygraph init --help``.
7272
assets_subdir : str or None
7373
Name of the source directory under ``src/whygraph/assets/`` that
7474
holds this agent's bundled asset tree, or ``None`` if the agent
@@ -268,8 +268,8 @@ def write_snippet(target: AgentTarget, project_root: Path) -> Path:
268268
other servers and top-level keys are preserved.
269269
* If the file exists but is unparseable, a fresh minimal config
270270
replaces it. This is a conscious trade-off: we surface the new
271-
config rather than refuse to proceed. Callers can offer
272-
``--print`` for users who'd rather merge by hand.
271+
config rather than refuse to proceed. Users who'd rather merge by
272+
hand can render the snippet with ``render_snippet()`` instead.
273273
274274
Parameters
275275
----------
@@ -293,8 +293,8 @@ def write_snippet(target: AgentTarget, project_root: Path) -> Path:
293293
Comments and incidental formatting in the existing config file are
294294
not preserved across the read-modify-write cycle (``tomllib`` strips
295295
comments on parse; ``json.load`` collapses whitespace). Users who
296-
care about preserving their hand-formatted config should use
297-
``--print`` and merge the snippet manually.
296+
care about preserving their hand-formatted config should render the
297+
snippet with ``render_snippet()`` and merge it manually.
298298
"""
299299
if target.scope != "project":
300300
raise ValueError(

src/whygraph/analyze/backfill.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
The :class:`~whygraph.scan.analyze_crawler.AnalyzeCrawler` describes
44
every undescribed commit in bulk at scan time. When a scan is run with
5-
``whygraph scan --no-llm-descriptions`` (or when a commit was added to
5+
``whygraph scan --skip-analyze`` (or when a commit was added to
66
the database before its description could be generated), the
77
``commit.llm_description`` column is left ``NULL``. The MCP tools
88
:func:`whygraph.mcp.evidence.whygraph_evidence_for` and

src/whygraph/cli/commands/hooks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
if mkdir "$lock" 2>/dev/null; then
5656
trap 'rmdir "$lock" 2>/dev/null' EXIT INT TERM
5757
rm -f "$pending"
58-
whygraph scan --no-llm-descriptions --no-remote >> "$log" 2>&1
58+
whygraph scan --skip-analyze --no-remote >> "$log" 2>&1
5959
rmdir "$lock" 2>/dev/null
6060
trap - EXIT INT TERM
6161
else

src/whygraph/cli/commands/init.py

Lines changed: 42 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,40 @@
1212
from ..console import fail
1313

1414

15-
@click.command(name="init")
15+
def _agents_epilog() -> str:
16+
"""Render the supported-agents block for ``whygraph init --help``.
17+
18+
Lists each agent's name, aliases, scope, format, and one-line
19+
description — the discoverability the old ``--list-agents`` command
20+
provided, minus its cwd-relative config path (help text isn't
21+
cwd-anchored; the write step still echoes the real path). Built at
22+
import from :data:`whygraph.agents.AGENTS`.
23+
24+
The leading ``\\b`` marker tells Click's help formatter not to
25+
re-wrap the block, so the indented per-agent layout survives. Click
26+
ends a "no-rewrap" paragraph at the first blank line, so the whole
27+
block is kept as a single paragraph with no interior blank lines.
28+
"""
29+
lines = ["\b", "Supported agents (use with --agent):"]
30+
for name in sorted(agents.AGENTS):
31+
target = agents.AGENTS[name]
32+
aliases = f" (aliases: {', '.join(target.aliases)})" if target.aliases else ""
33+
scope = "project" if target.scope == "project" else "user"
34+
lines.append(
35+
f" {target.name}{aliases} — scope: {scope}, format: {target.format}"
36+
)
37+
lines.append(f" {target.description}")
38+
return "\n".join(lines)
39+
40+
41+
@click.command(name="init", epilog=_agents_epilog())
1642
@click.option(
1743
"--agent",
1844
"agent_name",
1945
type=click.Choice(agents.known_agent_names(), case_sensitive=False),
2046
default=None,
2147
help="Wire the WhyGraph MCP server into the named LLM agent's config.",
2248
)
23-
@click.option(
24-
"--print",
25-
"print_only",
26-
is_flag=True,
27-
help="Print the MCP snippet to stdout instead of writing any config file.",
28-
)
29-
@click.option(
30-
"--list-agents",
31-
"list_agents",
32-
is_flag=True,
33-
help="List supported agents (with config-file paths) and exit.",
34-
)
35-
@click.option(
36-
"--install-assets/--no-install-assets",
37-
"install_assets",
38-
default=True,
39-
help=(
40-
"Copy the chosen agent's bundled assets (if any) into the project."
41-
" Default: enabled. No-op for agents that ship no asset tree."
42-
),
43-
)
44-
@click.option(
45-
"--skip-preflight",
46-
"skip_preflight",
47-
is_flag=True,
48-
help=(
49-
"Skip the host-tool diagnostics that normally run at the top of"
50-
" `whygraph init`. Use only in scripted environments where the"
51-
" environment is known-good."
52-
),
53-
)
5449
@click.option(
5550
"--force",
5651
"force",
@@ -75,10 +70,6 @@
7570
)
7671
def init_cmd(
7772
agent_name: str | None,
78-
print_only: bool,
79-
list_agents: bool,
80-
install_assets: bool,
81-
skip_preflight: bool,
8273
force: bool,
8374
yes: bool,
8475
) -> None:
@@ -106,27 +97,22 @@ def init_cmd(
10697
subsequent run).
10798
10899
With ``--agent X``, registers the WhyGraph MCP server with the named
109-
agent. All supported agents are project-scoped — their MCP config
110-
file is written / merged in the repo. Pass ``--print`` to skip the
111-
write and emit the snippet for manual pasting.
100+
agent (run ``whygraph init --help`` for the list of supported
101+
agents). All supported agents are project-scoped — their MCP config
102+
file is written / merged in the repo. Agents whose config can't be
103+
written automatically get the snippet printed for manual pasting.
112104
113105
If the chosen agent ships a bundled asset tree (see
114106
:attr:`whygraph.agents.AgentTarget.has_assets`), the tree is copied
115107
into the matching destination directory under the repo. Pre-existing
116-
files are left alone unless ``--force`` is passed; pass
117-
``--no-install-assets`` to skip the copy entirely.
108+
files are left alone unless ``--force`` is passed.
118109
119110
Idempotent — re-running on an already-initialized project just
120111
confirms both databases are present and at head.
121112
"""
122-
if list_agents:
123-
_print_agent_list()
124-
return
125-
126113
project_root = Path.cwd()
127114

128-
if not skip_preflight:
129-
_run_preflight()
115+
_run_preflight()
130116

131117
# Prompt only on a real terminal and only when not told to accept
132118
# defaults. Pipes / CI / the git hooks have no TTY and fall straight
@@ -144,30 +130,30 @@ def init_cmd(
144130
resolved_agent = answers.agent or agent_name
145131
if resolved_agent is None:
146132
click.echo(
147-
"Tip: run `whygraph init --list-agents` to see supported agents,"
133+
"Tip: run `whygraph init --help` to see supported agents,"
148134
" then `whygraph init --agent <name>` to wire it up."
149135
)
150136
return
151137

152138
target = agents.resolve_agent(resolved_agent)
153139
snippet = agents.render_snippet(target)
154140

155-
if print_only or not agents.is_write_supported(target):
141+
if not agents.is_write_supported(target):
156142
_print_snippet(target, project_root, snippet)
157143
else:
158144
path = agents.write_snippet(target, project_root)
159145
click.echo(f"Wrote whygraph MCP entry to {path}")
160146

161-
if install_assets and target.has_assets:
147+
if target.has_assets:
162148
result = assets.install_assets(target, project_root, force=force)
163149
_print_install_summary(target, project_root, result, force=force)
164150

165151

166152
def _run_preflight() -> None:
167153
"""Echo the diagnostics block; ``fail`` with a clean error on missing tools.
168154
169-
Imported here (not at module top) so ``--list-agents`` and ``--help``
170-
don't pay the import cost.
155+
Imported here (not at module top) so ``--help`` doesn't pay the
156+
import cost.
171157
"""
172158
from whygraph.cli.preflight import PreflightError, run_preflight
173159

@@ -224,8 +210,8 @@ def _scaffold_example_config(project_root: Path, answers) -> None:
224210
225211
Always refreshed so it tracks the shipped defaults and any non-secret
226212
choices from ``answers``. Secrets are never written here. Lazy-imports
227-
the config helper so lightweight surfaces like ``--list-agents`` and
228-
``--help`` don't pay the cost.
213+
the config helper so lightweight surfaces like ``--help`` don't pay
214+
the cost.
229215
"""
230216
from whygraph.core.config import write_example_config
231217

@@ -275,27 +261,14 @@ def _ensure_db_initialized() -> Path:
275261
"""Bootstrap the WhyGraph DB, lazy-importing the heavy chain.
276262
277263
Imported here (not at module top) so that lightweight CLI surfaces
278-
like ``--list-agents`` and ``--help`` don't fail when the DB layer
279-
or its dependencies are mid-rewrite.
264+
like ``--help`` don't fail when the DB layer or its dependencies are
265+
mid-rewrite.
280266
"""
281267
from whygraph.db import ensure_initialized
282268

283269
return ensure_initialized()
284270

285271

286-
def _print_agent_list() -> None:
287-
click.echo("Supported agents:")
288-
for name in sorted(agents.AGENTS):
289-
target = agents.AGENTS[name]
290-
aliases = f" (aliases: {', '.join(target.aliases)})" if target.aliases else ""
291-
path = agents.config_path_for(target, Path.cwd())
292-
scope = "project" if target.scope == "project" else "user"
293-
click.echo(f" {target.name}{aliases}")
294-
click.echo(f" scope: {scope} format: {target.format}")
295-
click.echo(f" path: {path}")
296-
click.echo(f" note: {target.description}")
297-
298-
299272
def _print_snippet(
300273
target: agents.AgentTarget, project_root: Path, snippet: str
301274
) -> None:

src/whygraph/cli/commands/scan.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949

5050
@click.command(name="scan")
5151
@click.option(
52-
"--no-llm-descriptions",
53-
"no_llm_descriptions",
52+
"--skip-analyze",
53+
"skip_analyze",
5454
is_flag=True,
5555
default=False,
5656
help=(
@@ -109,7 +109,7 @@
109109
),
110110
)
111111
def scan_cmd(
112-
no_llm_descriptions: bool,
112+
skip_analyze: bool,
113113
refresh_codegraph: bool,
114114
codegraph_image: str | None,
115115
remote: bool,
@@ -135,12 +135,12 @@ def scan_cmd(
135135
else:
136136
github_client = None
137137

138-
if no_llm_descriptions:
138+
if skip_analyze:
139139
# Bypass the LlmDescriptor probe entirely so a broken `[analyze]`
140140
# config still lets users run a fast scan and rely on the MCP
141141
# tools' lazy backfill for descriptions.
142142
descriptor = None
143-
analyze_skip: str | None = "--no-llm-descriptions"
143+
analyze_skip: str | None = "--skip-analyze"
144144
else:
145145
try:
146146
descriptor = LlmDescriptor.from_config(config.analyze)
@@ -334,7 +334,7 @@ def _optional_phase_cells(
334334
"""Return the (status, summary, timing) cells for an optional phase.
335335
336336
A crawler that never ran (phase skipped via ``--no-remote`` /
337-
``--no-llm-descriptions``) renders a dim ``— skipped`` status with no
337+
``--skip-analyze``) renders a dim ``— skipped`` status with no
338338
summary or timing.
339339
"""
340340
if crawler is None:

0 commit comments

Comments
 (0)