Metadata-Version: 2.3
Name: winnow-review
Version: 0.1.0
Summary: Read-only, question-driven codebase review with bounded agents
Requires-Dist: cryptography>=46,<51
Requires-Dist: httpx>=0.28,<1
Requires-Dist: openai-codex>=0.144.4,<0.145
Requires-Dist: pydantic>=2.12,<3
Requires-Dist: rich>=15,<16
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# Winnow

Winnow questions a codebase without changing it. Before decomposition, one typed direction turn translates the user's custom review instructions into additive guidance for every downstream system prompt. This keeps a request aimed at one subsystem focused there through scouting, allocation, review, and synthesis. A deterministic inventory then gives an agent-led splitter safe orientation, the splitter chooses semantic subsystems, one scout for every inventory shard supplies concrete leads to a separate allocator, and independent rubric and freeform reviewers investigate the allocation in parallel. One clean final turn reconciles both evidence streams. Codex remains the default, while any role can instead use Claude Code or Grok Build.

Every Codex thread is ephemeral, denies approval requests, and uses a workspace-scoped read-only permission profile. The profile denies reads outside the target repository and Codex's minimal runtime paths, and it also denies `.env*` and `.winnow.toml` inside the repository. Codex's native web search runs in live mode, while automatic skills, plugins, Codex Apps, login shells, and non-core shell environment variables are disabled. Winnow also disables configured ambient MCP servers on every turn.

Claude Code runs in safe, non-persistent print mode with `Read`, `Grep`, `Glob`, `WebSearch`, and `WebFetch`. Grok Build runs standalone in its strict OS sandbox with `read_file`, `grep`, `list_dir`, `web_search`, and `web_fetch`; shell, editing, MCP, memory, and subagents remain disabled for both external providers. Grok Build currently retains its own headless session history under `~/.grok/sessions`; Winnow never resumes those sessions. See the official [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference) and [Grok Build headless reference](https://docs.x.ai/build/cli/headless-scripting) for their underlying CLI contracts.

## Setup

Winnow requires Python 3.11+, Git, and an authenticated CLI for every provider selected by the run.

Install the CLI and its optional global Codex skill:

```bash
uv tool install winnow-review
winnow install-skill
winnow --help
```

The installer writes `~/.codex/skills/winnow/SKILL.md`. It is safe to rerun and preserves a different existing skill unless `--force` is explicit.

For development from a source checkout:

```bash
codex login
codex login status
# Run `claude auth login` when selecting Claude Code.
# Run `grok login` when selecting Grok Build.
uv sync
mkdir -p ~/.config/winnow
chmod 700 ~/.config/winnow
```

Create `~/.config/winnow/config.toml` and keep it private:

```toml
provider = "codex"

# Cost and concurrency bounds.
max_work_items = 8
max_concurrency = 4

# Provider defaults are Codex Terra/xhigh, Claude Fable 5/high, and Grok 4.5/high.
# Set either value only to override those defaults for the whole run.
# model = "gpt-5.6-sol"
# effort = "high"

# Optional: route materially different roles to different providers.
# [role_providers]
# customize = "codex"
# decompose = "codex"
# scout = "codex"
# allocate = "claude-code"
# rubric = "claude-code"
# freeform = "grok-build"
# synthesize = "codex"

# Optional: model names are interpreted by each role's selected provider.
# [role_models]
# customize = "gpt-5.6-sol"
# allocate = "claude-fable-5"
# rubric = "claude-fable-5"
# freeform = "grok-4.5"
```

```bash
chmod 600 ~/.config/winnow/config.toml
uv run winnow run "Review the async boundaries" /path/to/git/repository --output review.md
# Or force one provider for the whole run; its Winnow defaults apply:
uv run winnow run "Review the async boundaries" . --provider claude-code
```

Each adapter delegates authentication to its provider CLI; Winnow does not ask for or copy model-provider credentials. Output goes to stdout unless `--output` is supplied. Use `--workers N` to override the configured worker count for one run. Role providers fall back to `provider`; role models fall back to `model`, then Winnow's default for the selected provider. An explicit `effort` overrides the provider-specific effort default for every role. `--provider` forces one provider for the run; pair it with `--model` when overriding the model too. For mixed-provider runs, configure model names under `[role_models]` because model identifiers are provider-specific.

Run `uv run winnow` (or `uv run winnow dashboard`) in another terminal to watch every run. Each `winnow run` stays in its foreground terminal, while an atomic record under `~/.local/state/winnow/runs` lets the dashboard show concurrent runs, their prompts, current steps, and progress. Agent decomposition and scout-backed allocation each advance one stage, parallel work items fill the third stage as they finish, and synthesis completes the fourth.

Use `uv run winnow path RUN_ID` to print the absolute report path recorded for a run, including while that run is still active and the report file does not exist yet.

Use `uv run winnow transcript RUN_ID` for a polished human view that follows an active run, renders newly completed turns into terminal scrollback, keeps live progress at the bottom, and exits when the run finishes. Agents should use `uv run winnow transcript RUN_ID --agent` to receive the current original Markdown immediately without rendering or watching. Transcripts include developer instructions, prompts, SDK-visible activity, and responses. Runs created by older Winnow versions have no recoverable transcript.

Use `uv run winnow report RUN_ID` for the same polished live status and Markdown rendering around the final report. Agents should use `uv run winnow report RUN_ID --agent` for raw Markdown. Every new run persists its report by ID even when `--output` is omitted; `--output` remains an optional additional destination.

Every role can use its selected provider's native web search, but no MCP server is enabled. Each role's prompt ties research to its own decision: scope, questions, allocation, review evidence, or final verification. Agents never include source code, file contents, secrets, or non-public repository details in search queries.

## GitHub App bot

`winnow github serve` accepts `@winnow <review focus>` in a new pull-request issue comment. It verifies GitHub's webhook signature, allows only users with repository write access, checks out the exact PR head with a short-lived installation token, runs the existing read-only CLI, and posts the report back to the PR. Reviews run one at a time on the worker.

Create a GitHub App with a public HTTPS webhook URL ending in `/github/webhook`, subscribe it to **Issue comments**, and install it only on repositories Winnow may review. Grant **Contents: Read-only**, **Issues: Read and write**, and **Pull requests: Read-only** permissions. GitHub's webhook secret, App ID, and downloaded private key stay on the worker, never in the reviewed repository.

```bash
export WINNOW_GITHUB_APP_ID="..."
export WINNOW_GITHUB_PRIVATE_KEY_FILE="$HOME/.config/winnow/github-app.pem"
export WINNOW_GITHUB_WEBHOOK_SECRET="..."
chmod 600 "$WINNOW_GITHUB_PRIVATE_KEY_FILE"

uv run winnow github serve --host 127.0.0.1 --port 8787
```

Put a TLS reverse proxy or tunnel in front of `127.0.0.1:8787` and point the GitHub App webhook URL at its `/github/webhook` path. `GET /healthz` returns `ok` for proxy health checks. Pass `--config ~/.config/winnow/config.toml` when the webhook process should use a non-default Winnow review config.

## What runs

1. `customize` receives the user's request and the exact base prompts for decomposition, scouting, allocation, both reviewer modes, and synthesis. With the selected provider's reasoning effort, it returns a strict Pydantic object containing one concise addition per role. The additions can narrow focus and priorities, but cannot replace Winnow's read-only, evidence, or output rules.
2. `decompose` asks Git for a bounded inventory, then gives that seed, the invoked repository-relative scope, and its generated direction to a read-only splitting agent. The agent inspects the repository and splits a whole codebase into semantic subsystems, or treats an explicitly requested subsystem as the target and divides it into smaller parts.
3. `plan` preserves one directed scout per deterministic inventory shard. A separate directed allocation turn combines every scout's questions with the semantic subsystem plan and covers each subsystem with balanced rubric and freeform assignments plus deliberate overlaps.
4. `execute` fans out one isolated, read-only provider turn per directed assignment. Half apply the complete production rubric and `check-normal` evidence process. Half retain Winnow's existing open professional review. With an odd worker bound, the extra worker is freeform; a bound of one keeps the original freeform lane.
5. `synthesize` gives the subsystem plan, role-labelled assignments, selected providers and models, unchanged `WorkResult` records, and the generated reporting direction to one clean provider turn. It collapses repeated mechanisms, preserves disagreements and coverage gaps, and emits the most actionable Markdown report first.

The allocation—not peer findings—is shared with workers. This keeps the two review modes independent and leaves cross-agent reconciliation to the synthesis stage. Every downstream review turn receives guidance to start from the charitable prior that the author is a highly capable programmer, reconstruct the strongest coherent rationale, and then try to falsify it against actual behavior. This is agent guidance, not a deterministic intent mechanism; it cannot excuse a demonstrated gap or turn inferred intent into fact. Each turn is also told the exact target path, that it is working locally on the user's machine, and which provider-specific read-only controls apply.

## Development

Review standards are documented in [Repository guidance and engineering practice](docs/repository-guidance.md),
with testing details in [Test quality and suite stewardship](docs/testing-quality.md).

```bash
uv run ruff check .
uv run pytest
```
