messygit 0.3.2__tar.gz → 0.4.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. messygit-0.4.5/ARCHITECTURE.md +93 -0
  2. messygit-0.4.5/CHANGELOG.md +40 -0
  3. {messygit-0.3.2 → messygit-0.4.5}/PKG-INFO +102 -6
  4. {messygit-0.3.2 → messygit-0.4.5}/README.md +101 -5
  5. messygit-0.4.5/evals/README.md +90 -0
  6. messygit-0.4.5/evals/__init__.py +11 -0
  7. messygit-0.4.5/evals/changelog_eval.py +310 -0
  8. messygit-0.4.5/evals/commit_eval.py +258 -0
  9. messygit-0.4.5/evals/core.py +248 -0
  10. messygit-0.4.5/evals/fixtures.py +99 -0
  11. messygit-0.4.5/evals/incremental_suggest_eval.py +342 -0
  12. messygit-0.4.5/evals/results/changelog/2026-07-01_22-15-24.md +25 -0
  13. messygit-0.4.5/evals/results/commit/2026-06-26_23-26-23.md +45 -0
  14. messygit-0.4.5/evals/results/suggest/2026-07-01_22-16-20.md +25 -0
  15. messygit-0.4.5/evals/results/suggest/2026-07-01_22-32-01.md +25 -0
  16. messygit-0.4.5/evals/results/suggest/2026-07-01_22-36-50.md +25 -0
  17. messygit-0.4.5/evals/results/suggest-incremental/2026-07-05_21-47-23.md +30 -0
  18. messygit-0.4.5/evals/results/suggest-incremental/2026-07-05_21-56-31.md +30 -0
  19. messygit-0.4.5/evals/suggest_eval.py +259 -0
  20. {messygit-0.3.2 → messygit-0.4.5}/messygit/agent/agent.py +66 -21
  21. {messygit-0.3.2 → messygit-0.4.5}/messygit/agent/tools.py +111 -1
  22. messygit-0.4.5/messygit/cli.py +218 -0
  23. messygit-0.4.5/messygit/commands/__init__.py +0 -0
  24. messygit-0.4.5/messygit/commands/account_cmds.py +128 -0
  25. messygit-0.4.5/messygit/commands/agent_cmds.py +179 -0
  26. messygit-0.4.5/messygit/commands/app_cmds.py +86 -0
  27. messygit-0.4.5/messygit/commands/git_cmds.py +134 -0
  28. messygit-0.4.5/messygit/commands/trace.py +115 -0
  29. messygit-0.4.5/messygit/commands/usage.py +60 -0
  30. {messygit-0.3.2 → messygit-0.4.5}/messygit/config.py +55 -0
  31. {messygit-0.3.2 → messygit-0.4.5}/messygit/git.py +75 -0
  32. messygit-0.4.5/messygit/prompts.py +278 -0
  33. messygit-0.4.5/messygit/ui/__init__.py +0 -0
  34. messygit-0.4.5/messygit/ui/banner.py +54 -0
  35. messygit-0.4.5/messygit/ui/output.py +29 -0
  36. messygit-0.4.5/messygit/ui/spinner.py +94 -0
  37. messygit-0.4.5/messygit/ui/theme.py +59 -0
  38. {messygit-0.3.2 → messygit-0.4.5}/pyproject.toml +1 -1
  39. {messygit-0.3.2 → messygit-0.4.5}/tests/config_test.py +34 -0
  40. messygit-0.4.5/tests/suggest_test.py +60 -0
  41. messygit-0.4.5/tests/trace_test.py +115 -0
  42. messygit-0.4.5/tests/verbose_test.py +145 -0
  43. messygit-0.3.2/ARCHITECTURE.md +0 -64
  44. messygit-0.3.2/messygit/cli.py +0 -762
  45. messygit-0.3.2/messygit/prompts.py +0 -108
  46. {messygit-0.3.2 → messygit-0.4.5}/.github/workflows/publish.yml +0 -0
  47. {messygit-0.3.2 → messygit-0.4.5}/.github/workflows/test.yml +0 -0
  48. {messygit-0.3.2 → messygit-0.4.5}/.gitignore +0 -0
  49. {messygit-0.3.2 → messygit-0.4.5}/.vscode/settings.json +0 -0
  50. {messygit-0.3.2 → messygit-0.4.5}/messygit/__init__.py +0 -0
  51. {messygit-0.3.2 → messygit-0.4.5}/messygit/agent/tool.py +0 -0
  52. {messygit-0.3.2 → messygit-0.4.5}/messygit/llm.py +0 -0
  53. {messygit-0.3.2 → messygit-0.4.5}/messygit/models.py +0 -0
  54. {messygit-0.3.2 → messygit-0.4.5}/messygit/usage.py +0 -0
  55. {messygit-0.3.2 → messygit-0.4.5}/tests/agent_test.py +0 -0
  56. {messygit-0.3.2 → messygit-0.4.5}/tests/git_test.py +0 -0
  57. {messygit-0.3.2 → messygit-0.4.5}/tests/llm_test.py +0 -0
  58. {messygit-0.3.2 → messygit-0.4.5}/tests/tool_schema_test.py +0 -0
@@ -0,0 +1,93 @@
1
+ # Architecture
2
+
3
+ This document describes the purpose of each file in the `messygit` project.
4
+
5
+ The package is organized in layers. `ui/` is the shared presentation foundation
6
+ (console, theme, spinner, banner). `commands/` holds the command handlers grouped
7
+ the same way the `help` screen groups them. `agent/` is a self-contained tool-use
8
+ loop. `cli.py` is a thin shell that wires everything together. Dependencies flow
9
+ one way — `ui/` knows nothing about `commands/`, and `commands/` knows nothing
10
+ about `cli` — so there are no import cycles.
11
+
12
+ ## Root
13
+
14
+ | File | Purpose |
15
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
16
+ | `pyproject.toml` | Package metadata, dependencies (`anthropic`, `click`, `rich`), build system (hatchling), and the `messygit` console script. |
17
+ | `README.md` | User-facing documentation: install, usage, commands, and development instructions. |
18
+ | `ARCHITECTURE.md` | This file — a per-module map of the codebase. |
19
+ | `CHANGELOG.md` | Release notes, generated/updated by the `changelog` command. |
20
+ | `.gitignore` | Keeps `.venv/`, `__pycache__/`, `dist/`, and `*.egg-info/` out of version control. |
21
+ | `.github/workflows/test.yml` | Runs `pytest` on every push/PR across Python 3.10–3.13. |
22
+ | `.github/workflows/publish.yml` | Builds and publishes to PyPI via trusted publishing on release. |
23
+
24
+ ## `messygit/` (core package)
25
+
26
+ | File | Purpose |
27
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
28
+ | `__init__.py` | Marks the directory as a Python package. |
29
+ | `cli.py` | The REPL shell: prints the startup dashboard, runs the prompt loop, owns the `COMMANDS` dispatch table and the `help` screen, and applies the saved theme on launch. Delegates all real work to `commands/`. |
30
+ | `git.py` | All subprocess calls to `git`. Reads staged diffs (`git diff --cached -U0`), parses them into a compact changed-lines format, filters noise files, handles the large-diff fallback (stat summary + top-N changed files), and runs `add`/`commit`/`push`. Also exposes the primitives incremental `suggest` needs: `get_head_hash`, `get_repo_root`, `is_ancestor` (validate a saved checkpoint), and `get_commits_since`/`get_range_context` (the `saved_hash..HEAD` delta). |
31
+ | `llm.py` | Anthropic SDK integration for the (non-agentic) `commit` path. Creates the client, calls `messages.create`, extracts text, and maps SDK exceptions (auth, permission, billing/402) into user-friendly error classes. Exposes helpers reused by `agent/agent.py`. |
32
+ | `config.py` | Reads/writes `~/.messygit/config.json`: API key (plus `ANTHROPIC_API_KEY` env resolution), theme, model, todo, the `verbose` flag, and per-repo `suggest` checkpoints (`{head, suggestions, incremental_runs}`, keyed by repo root). Masks keys for display and defines user-facing error messages and exception classes. |
33
+ | `models.py` | The selectable Claude models, their labels, and approximate per-million-token pricing; resolves the active model from config. |
34
+ | `usage.py` | Session-local token-usage tracker (`SESSION_USAGE`) and the billing URL. The API exposes no balance endpoint, so usage/cost are accumulated per session. |
35
+ | `prompts.py` | The system prompts — `COMMIT_SYSTEM_PROMPT`, `SUGGESTION_SYSTEM_PROMPT`, `SUGGESTION_INCREMENTAL_SYSTEM_PROMPT` (delta-only "update the existing list" variant), `CHANGELOG_SYSTEM_PROMPT` — plus `build_user_prompt`. Each prompt includes anti-hallucination and untrusted-input guardrails. |
36
+
37
+ ## `messygit/ui/` (shared presentation)
38
+
39
+ | File | Purpose |
40
+ | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
41
+ | `theme.py` | Color palette and theme state. `BRAND`/`BRAND_RGB`/`BANNER_COLOR` are reassigned at runtime by `apply_theme()`, so other modules read them as `theme.BRAND` (never import the name directly). Also `brand_ansi()` and `active_theme()`. |
42
+ | `output.py` | The shared `console`/`err_console` objects and the small print helpers (`print_error`, `success`, `warn`, `field`). |
43
+ | `spinner.py` | The threaded `_CharSpinner` loading animation and the `spinner()` factory. |
44
+ | `banner.py` | The ASCII banner art and its boot animation (`animate_banner`). |
45
+
46
+ ## `messygit/commands/` (command handlers)
47
+
48
+ | File | Purpose |
49
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
50
+ | `git_cmds.py` | The git group: `add`, `commit` (AI message + Y/n/e prompt), `push`, `outbox`. |
51
+ | `agent_cmds.py` | The agent group: `suggest` and `changelog`. `_drive()` runs an agent either under a spinner or streaming live (verbose), and records the run's trace. `suggest` is incremental: `_choose_mode` picks a full scan (first run, stale/diverged checkpoint, `suggest full`, or a periodic re-audit every `AUTO_FULL_SCAN_EVERY` runs) vs an incremental run that feeds the prior suggestions plus only the `saved_hash..HEAD` delta (`_incremental_prompt`), then advances the per-repo checkpoint. |
52
+ | `account_cmds.py` | The account group: `config`, `show`, `model`, `tokens`. |
53
+ | `app_cmds.py` | The app group: `todo`, `theme`, `verbose`. |
54
+ | `usage.py` | Token-usage/cost *display* helpers (`usage_summary`, `print_usage_delta`, `model_pricing`, the high-usage warning). Distinct from the root `usage.py` tracker. |
55
+ | `trace.py` | The `trace` command. Stores the last agent run's steps and renders them as a panel; also provides `live_reporter()`, the per-step formatter that verbose mode streams. |
56
+
57
+ ## `messygit/agent/` (agentic tool-use subpackage)
58
+
59
+ | File | Purpose |
60
+ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
+ | `tool.py` | `Tool` dataclass wrapping a Python callable with a name, description, and parameter schema. `run()` invokes the function; `to_schema()` emits an Anthropic-compatible tool definition. |
62
+ | `tools.py` | Concrete tools: `run_git_tool` (allowlisted read-only git, including tag ranges), `read_file_tool`, `list_directory_tool`, `search_code_tool` (`git grep`), `write_file_tool` (full overwrite), and `edit_file_tool` (unique-match string replace). All file tools reject paths outside the repo root. |
63
+ | `agent.py` | The agentic loop. Sends messages to Claude with tool definitions, dispatches `tool_use` blocks to matching `Tool`s, feeds results back, and iterates up to `max_iterations`. Records each step as a `TraceStep` (optionally streamed via an `on_step` callback) and warns when the iteration cap is hit before finishing. |
64
+
65
+ ## Data flow
66
+
67
+ ```
68
+ User runs `messygit` → cli.py REPL (dispatch table)
69
+
70
+ ├── "add <files>" / "push" ─────► commands/git_cmds.py ─► git.py
71
+ ├── "config" / "show" / "model" / "tokens" ─► commands/account_cmds.py ─► config.py / usage.py
72
+ ├── "todo" / "theme" / "verbose" ─────► commands/app_cmds.py ─► config.py
73
+ ├── "trace" ─────────────────────► commands/trace.py (render last run)
74
+
75
+ ├── "commit" ──► commands/git_cmds.py
76
+ │ │ ├── git.py (staged diff + token budget)
77
+ │ │ └── llm.py ─► prompts.COMMIT_SYSTEM_PROMPT, config.py (key)
78
+ │ ▼
79
+ │ Y/n/e prompt ─► git.py (git commit)
80
+
81
+ └── "suggest" / "changelog" ──► commands/agent_cmds.py
82
+ │ ├── config.py: load/save suggest checkpoint (suggest only)
83
+ │ │ └── full scan on first run / stale hash / `suggest full`
84
+ │ │ / every AUTO_FULL_SCAN_EVERY runs; else incremental
85
+ │ │ (git.py: saved_hash..HEAD delta → _incremental_prompt)
86
+ │ └── agent/agent.py (tool-use loop)
87
+ │ ├── config.py (key) + models.py
88
+ │ ├── prompts.{SUGGESTION,SUGGESTION_INCREMENTAL,CHANGELOG}_SYSTEM_PROMPT
89
+ │ └── agent/tools.py (run_git, read_file, list_directory,
90
+ │ write_file, edit_file)
91
+
92
+ spinner OR live step stream (verbose); steps saved for `trace`
93
+ ```
@@ -0,0 +1,40 @@
1
+ ## [Unreleased]
2
+ ### Added
3
+ - Comprehensive evaluation framework (`evals/`) for testing AI model outputs, including:
4
+ - Generic evaluation harness supporting multiple eval types with deterministic scorers and optional LLM-as-judge grading
5
+ - Commit message evaluation with test cases for format, semantic accuracy, and adversarial prompt injection
6
+ - Agentic evaluators for `suggest` and `changelog` commands that build throwaway git repos and grade both output quality and agent process (tool usage, iteration budget, hallucination detection)
7
+ - Evaluation result reporting with markdown scorecards and aggregated pass rates
8
+
9
+ ## [v0.4.0] - 2026-06-23
10
+ ### Added
11
+ - `trace` command to inspect and display the detailed steps of the last agent run (show what tools were called, their inputs, and results)
12
+ - `verbose` mode toggle to stream agent steps live as they execute (replaces the spinner with real-time output during `suggest` and `changelog` operations)
13
+ - `edit_file` tool for the agent to make precise edits to existing files by replacing specific text spans (complements `write_file` for partial updates)
14
+ - `changelog` command to automatically generate and update a CHANGELOG.md file by analyzing git history between tags
15
+ - Iteration limit warning that displays when an agent run hits the maximum iteration limit before completing, alerting users that the task may be incomplete
16
+
17
+ ### Changed
18
+ - CLI code reorganized from a single monolithic module into separate command modules (account_cmds, git_cmds, agent_cmds, app_cmds) and UI modules (banner, spinner, theme, output) for better maintainability
19
+
20
+ ## [v0.3.2] - 2026-06-20
21
+ ### Added
22
+ - Error handling for unknown tools—agent now returns an error result instead of crashing when the model requests a non-existent tool
23
+ - Exception handling for tool execution—tool errors are caught and reported back to the model as error results
24
+ - `outbox` command to display committed but unpushed commits, showing how many commits are ahead of the upstream branch
25
+ - Input validation and security checks for `read_file` and `list_directory` tools to prevent directory traversal attacks
26
+ - Enhanced tool descriptions with detailed documentation of parameters and usage examples
27
+ - Support for `required` field in tool schemas for better validation
28
+ - Comprehensive pytest test suite covering agent tool execution, config management, git diff parsing, LLM error handling, and tool schemas
29
+ - GitHub Actions CI workflow for automated testing across Python 3.10–3.13
30
+
31
+ ### Changed
32
+ - Tool schema generation now includes required field declarations
33
+ - Improved error messages throughout the CLI for better user guidance
34
+ - Tool functions now validate inputs for security and proper error reporting
35
+
36
+ ## [v0.3.1] - 2026-06-20
37
+
38
+ ## [v0.3.0] - 2026-06-20
39
+
40
+ ## [v0.2.1] - 2026-06-20
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: messygit
3
- Version: 0.3.2
3
+ Version: 0.4.5
4
4
  Summary: An AI-powered interactive git CLI with agentic tools for commits, code suggestions, and workflow automation.
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
@@ -13,16 +13,18 @@ Description-Content-Type: text/markdown
13
13
 
14
14
  # messygit
15
15
 
16
- **messygit** is an interactive CLI that turns messy git workflows into clean Conventional Commits — stage, commit, push, and get AI-powered project suggestions, all from one interface powered by [Claude](https://www.anthropic.com/api).
16
+ **messygit** is an interactive CLI that turns messy git workflows into clean Conventional Commits — stage, commit, push, generate changelogs, and get AI-powered project suggestions, all from one interface powered by [Claude](https://www.anthropic.com/api).
17
17
 
18
18
  ## Why use it
19
19
 
20
20
  - **Interactive REPL** — one command drops you into a persistent session where you can stage, commit, push, and more without leaving.
21
21
  - **AI commit messages** — sends your staged diff to Claude and suggests a clean Conventional Commits subject line.
22
- - **Project suggestions** — an AI agent inspects your repo and recommends concrete next steps.
22
+ - **Project suggestions** — an AI agent inspects your repo and recommends concrete next steps. After the first run it only re-analyzes what changed (cheaper) while carrying its previous list forward, and periodically re-audits the whole repo on its own.
23
+ - **Changelog generation** — an agent reads the commits between your two latest tags, drills into unclear ones, categorizes the changes, and writes/updates `CHANGELOG.md`.
24
+ - **See what the agent did** — runs are clean by default; type `trace` to expand the last run's tool calls, or flip `verbose` on to stream each step live.
23
25
  - **Token usage & cost** — tracks the tokens each session uses and shows a rough cost estimate, with a one-command jump to billing.
24
26
  - **Themed UI** — a colored startup animation and prompt you can recolor with the `theme` command.
25
- - **Safe by default** — only the staged diff is sent to the model. Your API key is never printed in full.
27
+ - **Safe by default** — only the staged diff is sent for `commit`; agents use read-only git plus repo-scoped file tools that reject paths outside the repository. Your API key is never printed in full.
26
28
 
27
29
  ## Requirements
28
30
 
@@ -96,12 +98,16 @@ Commands are grouped on the `help` screen:
96
98
  | `add <file>` or `add .` | Stage files for commit |
97
99
  | `commit` | Generate an AI commit message from staged changes, then commit / cancel / edit |
98
100
  | `push` | Push commits to remote |
101
+ | `outbox` | Show commits made locally but not yet pushed to the upstream branch |
99
102
 
100
103
  **messyagent**
101
104
 
102
105
  | Command | Description |
103
106
  |---------|-------------|
104
- | `suggest` | Get AI-powered next-step suggestions for your project |
107
+ | `suggest` | Get AI-powered next-step suggestions for your project (incremental after the first run) |
108
+ | `suggest full` | Force a fresh full-repo review, ignoring the saved checkpoint |
109
+ | `changelog` | Generate or update `CHANGELOG.md` from the commits between your two latest tags (requires at least one tag) |
110
+ | `trace` | Show what the last agent run actually did — its tool calls and results |
105
111
 
106
112
  **account**
107
113
 
@@ -118,6 +124,7 @@ Commands are grouped on the `help` screen:
118
124
  |---------|-------------|
119
125
  | `todo` | Open your todo list in `$EDITOR` (saved to `~/.messygit/todo.md`) |
120
126
  | `theme` or `theme <name>` | Change the UI color (run `theme` to list presets) |
127
+ | `verbose` or `verbose on\|off` | Toggle live streaming of agent steps (persists; off by default) |
121
128
  | `help` | List available commands |
122
129
  | `quit` / `exit` | Exit messygit |
123
130
 
@@ -136,6 +143,66 @@ messygit > push
136
143
 
137
144
  > Tip: run `suggest` for AI next-step ideas, or `theme` to recolor the UI.
138
145
 
146
+ ### Agent commands & transparency
147
+
148
+ `suggest` and `changelog` are backed by an agent that uses tools (read-only git,
149
+ file reads, and — for `changelog` — repo-scoped file writes) over several steps.
150
+
151
+ By default a run shows only a spinner and the final result. Two commands let you
152
+ see inside:
153
+
154
+ ```
155
+ messygit > changelog # generates/updates CHANGELOG.md
156
+ messygit > trace # expand what that run just did
157
+
158
+ ╭─ trace · changelog · 4 tool calls ─────────────╮
159
+ │ 1. run_git tag --sort=-creatordate │
160
+ │ └ v0.4.0 (+3 more lines) │
161
+ │ 2. run_git log v0.3.2..v0.4.0 │
162
+ │ └ commit a1b2c3 feat: … (+12 more lines) │
163
+ │ 3. read_file CHANGELOG.md │
164
+ │ └ ## [v0.3.2] - 2026-06-20 │
165
+ │ 4. edit_file CHANGELOG.md │
166
+ │ └ File edited successfully. │
167
+ ╰─────────────────────────────────────────────────╯
168
+ ```
169
+
170
+ Prefer to watch it happen live? Turn on `verbose` — the same steps stream as the
171
+ agent works (no spinner). The setting persists in `~/.messygit/config.json`:
172
+
173
+ ```
174
+ messygit > verbose on
175
+ Verbose on — agent runs will stream their steps live (no spinner)
176
+ ```
177
+
178
+ `changelog` requires at least one git tag; it documents the range between your two
179
+ most recent tags (or the latest tag to `HEAD` when only one exists).
180
+
181
+ ### Incremental suggestions
182
+
183
+ The first time you run `suggest` in a repo, the agent does a full scan and saves a
184
+ checkpoint — the current `HEAD` hash plus the list it produced — to
185
+ `~/.messygit/config.json`, keyed by repository. Every run after that is
186
+ **incremental**: instead of re-reading the whole tree, the agent is handed only the
187
+ `saved_hash..HEAD` delta (new commits + changed lines) alongside its previous
188
+ suggestions, and updates the list — dropping items the changes resolved, keeping
189
+ standing gaps, and adding follow-ups from what changed. Then it advances the
190
+ checkpoint. This makes repeat runs much cheaper and keeps the advice coherent
191
+ across runs instead of resetting each time.
192
+
193
+ Because delta-only analysis never re-reads untouched files, a standing issue in a
194
+ corner nothing has touched could otherwise drift out of view. Two things guard
195
+ against that:
196
+
197
+ - **Automatic re-audit** — after several incremental runs, `suggest` falls back to
198
+ a full scan on its own to refresh whole-repo coverage.
199
+ - **`suggest full`** — force a fresh full-repo review at any time.
200
+
201
+ `suggest` also falls back to a full scan automatically when there's no checkpoint
202
+ yet, or when the saved commit is no longer an ancestor of `HEAD` (after a rebase,
203
+ amend, squash, or branch switch), so a stale checkpoint never produces a nonsense
204
+ delta.
205
+
139
206
  ### Commit message style
140
207
 
141
208
  The model follows **Conventional Commits**: `type(scope): description`
@@ -144,7 +211,7 @@ Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`. Subj
144
211
 
145
212
  ### Token usage & cost
146
213
 
147
- messygit tracks the tokens used by AI commands (`commit`, `suggest`) for the current session and shows a running total after each call. Run `tokens` for a breakdown and a one-key jump to the Anthropic billing console:
214
+ messygit tracks the tokens used by AI commands (`commit`, `suggest`, `changelog`) for the current session and shows a running total after each call. Run `tokens` for a breakdown and a one-key jump to the Anthropic billing console:
148
215
 
149
216
  ```
150
217
  messygit > tokens
@@ -176,6 +243,35 @@ Switch anyway? [y/N]:
176
243
 
177
244
  Switching to a **more expensive** model prompts for confirmation first. The session cost estimate prices each request at the model used for it, so it stays accurate even if you switch mid-session.
178
245
 
246
+ ## Development & testing
247
+
248
+ Install the package with its dev dependencies (pytest), then run the suite:
249
+
250
+ ```bash
251
+ pip install -e ".[dev]"
252
+ pytest -q
253
+ ```
254
+
255
+ The tests live in `tests/` and are pure unit tests — no network calls and no
256
+ API key required (the Anthropic client is simulated). They cover:
257
+
258
+ | File | What it covers |
259
+ |------|----------------|
260
+ | `tests/config_test.py` | API-key resolution order (env → file), key save/load, theme/model/todo persistence, per-repo `suggest` checkpoints, malformed-config handling |
261
+ | `tests/suggest_test.py` | `suggest` mode selection — full-scan vs incremental, and the periodic auto re-audit cycle |
262
+ | `tests/git_test.py` | The diff parser — noise-file filtering and the compact changed-lines format |
263
+ | `tests/llm_test.py` | Insufficient-balance / billing-error detection and user messaging |
264
+ | `tests/tool_schema_test.py` | Agent tool schemas match the shape the Anthropic Messages API expects |
265
+ | `tests/agent_test.py` | The agent's tool-use loop, driven by a simulated Anthropic client with scripted responses |
266
+ | `tests/trace_test.py` | The `trace` renderer — step numbering, result truncation, empty state, and markup-safety of raw tool output |
267
+ | `tests/verbose_test.py` | The `verbose` setting, the toggle command, and `_drive` choosing live-stream vs. spinner |
268
+
269
+ ### Continuous integration
270
+
271
+ `.github/workflows/test.yml` runs `pytest` on every push to `main` and on every
272
+ pull request, across Python 3.10–3.13. No secrets are required because the tests
273
+ mock the Anthropic client.
274
+
179
275
  ## Publishing to PyPI
180
276
 
181
277
  This project uses GitHub Actions with [PyPI trusted publishing](https://docs.pypi.org/trusted-publishers/) — no API tokens needed in your repo.
@@ -1,15 +1,17 @@
1
1
  # messygit
2
2
 
3
- **messygit** is an interactive CLI that turns messy git workflows into clean Conventional Commits — stage, commit, push, and get AI-powered project suggestions, all from one interface powered by [Claude](https://www.anthropic.com/api).
3
+ **messygit** is an interactive CLI that turns messy git workflows into clean Conventional Commits — stage, commit, push, generate changelogs, and get AI-powered project suggestions, all from one interface powered by [Claude](https://www.anthropic.com/api).
4
4
 
5
5
  ## Why use it
6
6
 
7
7
  - **Interactive REPL** — one command drops you into a persistent session where you can stage, commit, push, and more without leaving.
8
8
  - **AI commit messages** — sends your staged diff to Claude and suggests a clean Conventional Commits subject line.
9
- - **Project suggestions** — an AI agent inspects your repo and recommends concrete next steps.
9
+ - **Project suggestions** — an AI agent inspects your repo and recommends concrete next steps. After the first run it only re-analyzes what changed (cheaper) while carrying its previous list forward, and periodically re-audits the whole repo on its own.
10
+ - **Changelog generation** — an agent reads the commits between your two latest tags, drills into unclear ones, categorizes the changes, and writes/updates `CHANGELOG.md`.
11
+ - **See what the agent did** — runs are clean by default; type `trace` to expand the last run's tool calls, or flip `verbose` on to stream each step live.
10
12
  - **Token usage & cost** — tracks the tokens each session uses and shows a rough cost estimate, with a one-command jump to billing.
11
13
  - **Themed UI** — a colored startup animation and prompt you can recolor with the `theme` command.
12
- - **Safe by default** — only the staged diff is sent to the model. Your API key is never printed in full.
14
+ - **Safe by default** — only the staged diff is sent for `commit`; agents use read-only git plus repo-scoped file tools that reject paths outside the repository. Your API key is never printed in full.
13
15
 
14
16
  ## Requirements
15
17
 
@@ -83,12 +85,16 @@ Commands are grouped on the `help` screen:
83
85
  | `add <file>` or `add .` | Stage files for commit |
84
86
  | `commit` | Generate an AI commit message from staged changes, then commit / cancel / edit |
85
87
  | `push` | Push commits to remote |
88
+ | `outbox` | Show commits made locally but not yet pushed to the upstream branch |
86
89
 
87
90
  **messyagent**
88
91
 
89
92
  | Command | Description |
90
93
  |---------|-------------|
91
- | `suggest` | Get AI-powered next-step suggestions for your project |
94
+ | `suggest` | Get AI-powered next-step suggestions for your project (incremental after the first run) |
95
+ | `suggest full` | Force a fresh full-repo review, ignoring the saved checkpoint |
96
+ | `changelog` | Generate or update `CHANGELOG.md` from the commits between your two latest tags (requires at least one tag) |
97
+ | `trace` | Show what the last agent run actually did — its tool calls and results |
92
98
 
93
99
  **account**
94
100
 
@@ -105,6 +111,7 @@ Commands are grouped on the `help` screen:
105
111
  |---------|-------------|
106
112
  | `todo` | Open your todo list in `$EDITOR` (saved to `~/.messygit/todo.md`) |
107
113
  | `theme` or `theme <name>` | Change the UI color (run `theme` to list presets) |
114
+ | `verbose` or `verbose on\|off` | Toggle live streaming of agent steps (persists; off by default) |
108
115
  | `help` | List available commands |
109
116
  | `quit` / `exit` | Exit messygit |
110
117
 
@@ -123,6 +130,66 @@ messygit > push
123
130
 
124
131
  > Tip: run `suggest` for AI next-step ideas, or `theme` to recolor the UI.
125
132
 
133
+ ### Agent commands & transparency
134
+
135
+ `suggest` and `changelog` are backed by an agent that uses tools (read-only git,
136
+ file reads, and — for `changelog` — repo-scoped file writes) over several steps.
137
+
138
+ By default a run shows only a spinner and the final result. Two commands let you
139
+ see inside:
140
+
141
+ ```
142
+ messygit > changelog # generates/updates CHANGELOG.md
143
+ messygit > trace # expand what that run just did
144
+
145
+ ╭─ trace · changelog · 4 tool calls ─────────────╮
146
+ │ 1. run_git tag --sort=-creatordate │
147
+ │ └ v0.4.0 (+3 more lines) │
148
+ │ 2. run_git log v0.3.2..v0.4.0 │
149
+ │ └ commit a1b2c3 feat: … (+12 more lines) │
150
+ │ 3. read_file CHANGELOG.md │
151
+ │ └ ## [v0.3.2] - 2026-06-20 │
152
+ │ 4. edit_file CHANGELOG.md │
153
+ │ └ File edited successfully. │
154
+ ╰─────────────────────────────────────────────────╯
155
+ ```
156
+
157
+ Prefer to watch it happen live? Turn on `verbose` — the same steps stream as the
158
+ agent works (no spinner). The setting persists in `~/.messygit/config.json`:
159
+
160
+ ```
161
+ messygit > verbose on
162
+ Verbose on — agent runs will stream their steps live (no spinner)
163
+ ```
164
+
165
+ `changelog` requires at least one git tag; it documents the range between your two
166
+ most recent tags (or the latest tag to `HEAD` when only one exists).
167
+
168
+ ### Incremental suggestions
169
+
170
+ The first time you run `suggest` in a repo, the agent does a full scan and saves a
171
+ checkpoint — the current `HEAD` hash plus the list it produced — to
172
+ `~/.messygit/config.json`, keyed by repository. Every run after that is
173
+ **incremental**: instead of re-reading the whole tree, the agent is handed only the
174
+ `saved_hash..HEAD` delta (new commits + changed lines) alongside its previous
175
+ suggestions, and updates the list — dropping items the changes resolved, keeping
176
+ standing gaps, and adding follow-ups from what changed. Then it advances the
177
+ checkpoint. This makes repeat runs much cheaper and keeps the advice coherent
178
+ across runs instead of resetting each time.
179
+
180
+ Because delta-only analysis never re-reads untouched files, a standing issue in a
181
+ corner nothing has touched could otherwise drift out of view. Two things guard
182
+ against that:
183
+
184
+ - **Automatic re-audit** — after several incremental runs, `suggest` falls back to
185
+ a full scan on its own to refresh whole-repo coverage.
186
+ - **`suggest full`** — force a fresh full-repo review at any time.
187
+
188
+ `suggest` also falls back to a full scan automatically when there's no checkpoint
189
+ yet, or when the saved commit is no longer an ancestor of `HEAD` (after a rebase,
190
+ amend, squash, or branch switch), so a stale checkpoint never produces a nonsense
191
+ delta.
192
+
126
193
  ### Commit message style
127
194
 
128
195
  The model follows **Conventional Commits**: `type(scope): description`
@@ -131,7 +198,7 @@ Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`. Subj
131
198
 
132
199
  ### Token usage & cost
133
200
 
134
- messygit tracks the tokens used by AI commands (`commit`, `suggest`) for the current session and shows a running total after each call. Run `tokens` for a breakdown and a one-key jump to the Anthropic billing console:
201
+ messygit tracks the tokens used by AI commands (`commit`, `suggest`, `changelog`) for the current session and shows a running total after each call. Run `tokens` for a breakdown and a one-key jump to the Anthropic billing console:
135
202
 
136
203
  ```
137
204
  messygit > tokens
@@ -163,6 +230,35 @@ Switch anyway? [y/N]:
163
230
 
164
231
  Switching to a **more expensive** model prompts for confirmation first. The session cost estimate prices each request at the model used for it, so it stays accurate even if you switch mid-session.
165
232
 
233
+ ## Development & testing
234
+
235
+ Install the package with its dev dependencies (pytest), then run the suite:
236
+
237
+ ```bash
238
+ pip install -e ".[dev]"
239
+ pytest -q
240
+ ```
241
+
242
+ The tests live in `tests/` and are pure unit tests — no network calls and no
243
+ API key required (the Anthropic client is simulated). They cover:
244
+
245
+ | File | What it covers |
246
+ |------|----------------|
247
+ | `tests/config_test.py` | API-key resolution order (env → file), key save/load, theme/model/todo persistence, per-repo `suggest` checkpoints, malformed-config handling |
248
+ | `tests/suggest_test.py` | `suggest` mode selection — full-scan vs incremental, and the periodic auto re-audit cycle |
249
+ | `tests/git_test.py` | The diff parser — noise-file filtering and the compact changed-lines format |
250
+ | `tests/llm_test.py` | Insufficient-balance / billing-error detection and user messaging |
251
+ | `tests/tool_schema_test.py` | Agent tool schemas match the shape the Anthropic Messages API expects |
252
+ | `tests/agent_test.py` | The agent's tool-use loop, driven by a simulated Anthropic client with scripted responses |
253
+ | `tests/trace_test.py` | The `trace` renderer — step numbering, result truncation, empty state, and markup-safety of raw tool output |
254
+ | `tests/verbose_test.py` | The `verbose` setting, the toggle command, and `_drive` choosing live-stream vs. spinner |
255
+
256
+ ### Continuous integration
257
+
258
+ `.github/workflows/test.yml` runs `pytest` on every push to `main` and on every
259
+ pull request, across Python 3.10–3.13. No secrets are required because the tests
260
+ mock the Anthropic client.
261
+
166
262
  ## Publishing to PyPI
167
263
 
168
264
  This project uses GitHub Actions with [PyPI trusted publishing](https://docs.pypi.org/trusted-publishers/) — no API tokens needed in your repo.
@@ -0,0 +1,90 @@
1
+ # Evals
2
+
3
+ Evals measure the **quality of real model output** — distinct from the unit
4
+ tests in `tests/`, which simulate the model and run offline. Evals call the live
5
+ API, so they cost tokens and need an `ANTHROPIC_API_KEY`. They are intentionally
6
+ **not** collected by `pytest`.
7
+
8
+ ## Run it
9
+
10
+ ```bash
11
+ export ANTHROPIC_API_KEY=sk-ant-... # or: messygit > config <key>
12
+ python -m evals.commit_eval # diff -> commit subject
13
+ python -m evals.suggest_eval # repo state -> next-steps list (agentic)
14
+ python -m evals.changelog_eval # tagged repo -> written CHANGELOG.md (agentic)
15
+ ```
16
+
17
+ The agentic evals (`suggest`, `changelog`) build a throwaway git repo per case,
18
+ run the real agent inside it, and grade both the output and the trace — so they
19
+ call the API many times over several iterations and take a few minutes each.
20
+
21
+ Each run writes a markdown report to `evals/results/<eval>/<timestamp>.md`
22
+ (one file per run, grouped by eval) — the terminal only prints the file path.
23
+ Exit code is `0` if the format-check pass rate ≥ `EVAL_PASS_BAR` (default `0.90`),
24
+ else `1` — so it can gate a CI job.
25
+
26
+ Env knobs:
27
+
28
+
29
+ | Var | Default | Meaning |
30
+ | ------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------- |
31
+ | `EVAL_JUDGE_MODEL` | `claude-haiku-4-5` | Model used for LLM-as-judge scoring (set a stronger one like `claude-sonnet-4-6` for more reliable grading) |
32
+ | `EVAL_PASS_BAR` | `0.9` | Fraction of applicable checks that must pass |
33
+
34
+
35
+ The model *under test* is whatever `model` is configured in messygit (default
36
+ Haiku) — switch it with `model <name>` to compare models on the same dataset.
37
+
38
+ ## How it's built
39
+
40
+
41
+ | File | Role |
42
+ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | `core.py` | The **generic harness**, shared by every eval: `run_eval`, `render`, the `ScoreResult`/`CaseResult` types, and `make_llm_judge`. Knows nothing about any specific eval. |
44
+ | `commit_eval.py` | **One self-contained eval**: the `CommitCase` dataset, the bespoke scorers, `generate()`, the judge rubric, and `main()`. The reference shape to copy. |
45
+
46
+
47
+ ## Adding a new eval — just write one file
48
+
49
+ Create `evals/<name>_eval.py` with four things and let `core` do the rest:
50
+
51
+ ```python
52
+ from .core import run_eval, write_report, make_llm_judge, ScoreResult, PASS_BAR
53
+
54
+ CASES = [...] # 1. objects with a `.name`
55
+ def generate(case) -> str: ... # 2. run the thing under test
56
+ SCORERS = [my_scorer, ...] # 3. (case, output) -> ScoreResult
57
+ judge = make_llm_judge(system, render_user) # 4. optional
58
+
59
+ def main():
60
+ results = run_eval(CASES, generate, SCORERS, judge=judge)
61
+ rate = write_report(results, eval_name="<name>") # writes results/<name>/<ts>.md
62
+ return 0 if rate >= PASS_BAR else 1
63
+ ```
64
+
65
+ The harness (running cases, catching generation errors, aggregating, the
66
+ scoreboard) is reused as-is. Only the dataset, `generate`, and scorers are
67
+ bespoke — which is inherent: each eval defines its own "what good looks like".
68
+
69
+ ## Adapting this to the agentic evals (`suggest` / `changelog`)
70
+
71
+ Same one-file shape; only two things grow:
72
+
73
+ 1. **Input/output.** Instead of a diff → subject line, an agentic case is a
74
+ *repo state + task* → the agent's effect (final text, files written, and the
75
+ `TraceStep` list the agent already records on `agent.steps`). Run the agent in
76
+ a throwaway git repo (see how `tests/` build temp repos) so file writes are
77
+ safe to inspect and discard.
78
+ 2. **Scorers get richer.** Beyond output-quality scorers, evaluate the *process*
79
+ using the trace:
80
+ - did it call the expected tools (e.g. `changelog` should `git log` a tag
81
+ range and `git show` at least one commit)?
82
+ - did it stay within `max_iterations` / a tool-call budget?
83
+ - did it avoid hallucinated numbers (assert no unverified figures appear) —
84
+ the exact failure the changelog prompt guardrail targets?
85
+ - did the written `CHANGELOG.md` parse, and prepend rather than clobber?
86
+
87
+ Keep deterministic scorers first (cheap, sharp), and reserve the LLM judge for
88
+ the genuinely subjective properties. Make the judge return structured JSON and
89
+ give it a rubric, as `scorers.llm_judge` does.
90
+
@@ -0,0 +1,11 @@
1
+ """Model-output evals for messygit.
2
+
3
+ Unlike the unit tests in `tests/` (which simulate the model and run offline),
4
+ evals call the REAL model and score its output. They cost tokens and need an
5
+ ANTHROPIC_API_KEY, so they are NOT part of the `pytest` run — launch them
6
+ explicitly with `python -m evals.commit_eval`.
7
+
8
+ `commit_eval` is the worked reference: a graded dataset, programmatic scorers,
9
+ an LLM-as-judge, and an aggregated scoreboard — the same shape you can reuse to
10
+ evaluate the agentic `suggest`/`changelog` commands.
11
+ """