# Plan: Invert verbosity default (verbose by default, `--quiet` to suppress)

## Goal

Currently the agent is silent by default and requires `-v`/`--verbose` to emit diagnostics to stderr. Invert this so diagnostics print by default and a new `--quiet`/`-q` flag suppresses them.

## Changes

### 1. `agent.py` — CLI argument

Replace the `--verbose` argument:

```python
parser.add_argument(
    "-v", "--verbose",
    action="store_true",
    help="Print diagnostics to stderr.",
)
```

with a `--quiet` argument:

```python
parser.add_argument(
    "-q", "--quiet",
    action="store_true",
    help="Suppress diagnostic output on stderr.",
)
```

### 2. `agent.py` — Derive `verbose` from `quiet`

Right after parsing args (before any use of `args.verbose`), add:

```python
args.verbose = not args.quiet
```

This keeps every downstream reference to `args.verbose` working without any other changes in `agent.py`. The `log()` function, `handle_tool_call()`, `call_llm()`, `discover_model()`, `configure_context()`, and all the `log(...)` call sites stay exactly as they are.

### 3. `thinking.py` — No changes

`ThinkingState` already accepts a `verbose` bool in its constructor. It will receive `True` by default now (since `args.verbose = not args.quiet`), which is the desired behavior. No code changes needed.

### 4. `tools.py`, `edit.py` — No changes

These files don't reference verbosity at all.

### 5. Tests

#### Existing tests — fix `SimpleNamespace` objects

All four test classes in `tests/test_logging.py` (`TestHappyPath`, `TestMaxTurns`, `TestTruncatedResponse`, `TestArgTruncation`) monkeypatch `parse_args` to return a `SimpleNamespace` with `verbose=True`. Since `main()` now runs `args.verbose = not args.quiet` before anything else, these will raise `AttributeError` because the namespace has no `quiet` attribute.

Fix: in each `SimpleNamespace(...)` constructor across these four tests, replace `verbose=True` with `quiet=False`. The derivation line in `main()` will then set `verbose=True` as before, so all existing assertions remain correct without changes.

Affected lines (4 occurrences):
- `test_logging.py:62` — `TestHappyPath`
- `test_logging.py:119` — `TestMaxTurns`
- `test_logging.py:173` — `TestTruncatedResponse`
- `test_logging.py:231` — `TestArgTruncation`

**`tests/test_think.py`** — No changes needed. These tests pass `verbose=True` or `verbose=False` directly to `ThinkingState()`, testing the class parameter rather than the CLI flag.

#### New tests — CLI arg parsing and end-to-end `--quiet` behavior

Add a new test class `TestQuietFlag` in `tests/test_logging.py` with these cases:

1. **`test_default_is_verbose`** — Parse args without `--quiet`, assert `args.verbose is True`. This catches argument-parsing regressions.
   ```python
   def test_default_is_verbose(self, monkeypatch):
       monkeypatch.setattr(sys, "argv", ["agent", "hello"])
       parser = agent.build_parser()
       args = parser.parse_args()
       args.verbose = not args.quiet  # same derivation as main()
       assert args.verbose is True
   ```

2. **`test_quiet_flag_suppresses`** — Parse args with `-q`, assert `args.verbose is False`.
   ```python
   def test_quiet_flag_suppresses(self, monkeypatch):
       monkeypatch.setattr(sys, "argv", ["agent", "hello", "-q"])
       parser = agent.build_parser()
       args = parser.parse_args()
       args.verbose = not args.quiet
       assert args.verbose is False
   ```

3. **`test_quiet_e2e_no_stderr`** — Run `main()` with `--quiet` through the same mock-LLM pattern used by existing tests. Assert stderr is empty (no diagnostics) while stdout still has the final answer.

4. **`test_default_e2e_has_stderr`** — Run `main()` without `--quiet`. Assert stderr contains diagnostics (`"--- Turn"`, `"Agent finished:"`). This is essentially what the existing `TestHappyPath` already covers, but makes the intent explicit for the new default.

This requires extracting the argument parser into a `build_parser()` function in `agent.py` (currently inline in `main()`). This is a minor refactor: move the `argparse.ArgumentParser(...)` block into its own function, call it from `main()`. Tests 1 and 2 call `build_parser()` directly instead of monkeypatching `parse_args`.

### 6. Documentation — `CLAUDE.md` and `README.md`

Both files reference `--verbose` / `-v` and need updating.

#### `CLAUDE.md`
- Line mentioning "gated by `--verbose`" → "All diagnostics go to stderr by default; use `-q`/`--quiet` to suppress."
- Update example commands that show `-v` (e.g. `uv run agent "task" --base-dir ./project -v` → remove `-v` or replace with `-q` example).

#### `README.md`
- **Options table (line 38):** Replace `| \`-v, --verbose\` | | Print diagnostics to stderr |` with `| \`-q, --quiet\` | | Suppress diagnostic output on stderr |`.
- **Examples (line 63):** Change `# No system prompt, verbose output` / `uv run agent "Hello" --no-system-prompt -v` → `# No system prompt, quiet mode` / `uv run agent "Hello" --no-system-prompt -q` (or remove the example).
- **Notes (line 132):** "All diagnostics go to stderr" is already correct — no change needed there since the new default emits them unconditionally.

## Summary of touched files

| File | What changes |
|------|-------------|
| `agent.py` | Replace `--verbose` arg with `--quiet`; extract `build_parser()`; add `args.verbose = not args.quiet` |
| `tests/test_logging.py` | Replace `verbose=True` → `quiet=False` in 4 existing `SimpleNamespace` objects; add `TestQuietFlag` class with 4 new tests |
| `CLAUDE.md` | Update verbose references and example commands |
| `README.md` | Update options table, examples, remove `-v` references |

## What does NOT change

- The `log(msg, verbose)` function signature and all its call sites
- The `handle_tool_call(..., verbose, ...)` signature
- The `ThinkingState(verbose=...)` constructor
- The `call_llm(..., verbose)` signature
- stdout remains exclusively for the final answer
