code-mower 0.5.0b5__py3-none-any.whl

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 (185) hide show
  1. code_mower/__init__.py +3 -0
  2. code_mower/adapters/__init__.py +39 -0
  3. code_mower/adapters/_base.py +148 -0
  4. code_mower/adapters/cursor_bugbot.py +97 -0
  5. code_mower/adapters/gitar.py +111 -0
  6. code_mower/adapters/greptile.py +191 -0
  7. code_mower/adapters/qodo.py +140 -0
  8. code_mower/antigravity_cli_audit_pr.py +241 -0
  9. code_mower/audit_handoff_log.py +345 -0
  10. code_mower/audit_labeler_lib.py +311 -0
  11. code_mower/audit_progress.py +203 -0
  12. code_mower/blind_review_artifacts.py +562 -0
  13. code_mower/blind_review_coordinator.py +276 -0
  14. code_mower/bootstrap.py +524 -0
  15. code_mower/builder_experiment.py +539 -0
  16. code_mower/calibration/__init__.py +181 -0
  17. code_mower/calibration/arms.py +267 -0
  18. code_mower/calibration/auto_discovery.py +348 -0
  19. code_mower/calibration/commands.py +192 -0
  20. code_mower/calibration/context_inputs.py +199 -0
  21. code_mower/calibration/corpus.py +91 -0
  22. code_mower/calibration/evidence.py +20 -0
  23. code_mower/calibration/evidence_report.py +360 -0
  24. code_mower/calibration/identity.py +27 -0
  25. code_mower/calibration/metrics.py +18 -0
  26. code_mower/calibration/overlap.py +103 -0
  27. code_mower/calibration/planning.py +309 -0
  28. code_mower/calibration/policy.py +207 -0
  29. code_mower/calibration/results.py +315 -0
  30. code_mower/calibration/run_results.py +147 -0
  31. code_mower/calibration/run_status.py +64 -0
  32. code_mower/calibration/runner.py +360 -0
  33. code_mower/calibration/truth.py +188 -0
  34. code_mower/calibration/value_report.py +142 -0
  35. code_mower/checks.py +402 -0
  36. code_mower/claude_audit_pr.py +1126 -0
  37. code_mower/claude_cli_bounce.py +303 -0
  38. code_mower/claude_cli_environment.py +73 -0
  39. code_mower/clear_stale.py +374 -0
  40. code_mower/cli.py +537 -0
  41. code_mower/cloud.py +674 -0
  42. code_mower/cloud_client/__init__.py +173 -0
  43. code_mower/cloud_client/bundle.py +155 -0
  44. code_mower/cloud_client/doctor.py +206 -0
  45. code_mower/cloud_client/dogfood.py +78 -0
  46. code_mower/cloud_client/endpoints.py +114 -0
  47. code_mower/cloud_client/errors.py +7 -0
  48. code_mower/cloud_client/events.py +278 -0
  49. code_mower/cloud_client/export.py +272 -0
  50. code_mower/cloud_client/git_metadata.py +46 -0
  51. code_mower/cloud_client/manifest.py +39 -0
  52. code_mower/cloud_client/operations.py +448 -0
  53. code_mower/cloud_client/reports.py +45 -0
  54. code_mower/cloud_client/setup.py +205 -0
  55. code_mower/cloud_client/upload.py +97 -0
  56. code_mower/code_mower_calibration.py +598 -0
  57. code_mower/code_mower_context_packs.py +591 -0
  58. code_mower/code_mower_merge.py +227 -0
  59. code_mower/code_mower_telemetry.py +561 -0
  60. code_mower/coderabbit_cli_audit_pr.py +526 -0
  61. code_mower/codex_audit_env_preflight.py +220 -0
  62. code_mower/codex_audit_pr.py +1738 -0
  63. code_mower/codex_audit_schema_smoke.py +160 -0
  64. code_mower/codex_audit_verdict.schema.json +44 -0
  65. code_mower/config.py +655 -0
  66. code_mower/doctor.py +161 -0
  67. code_mower/doctor_checks/__init__.py +104 -0
  68. code_mower/doctor_checks/cloud.py +129 -0
  69. code_mower/doctor_checks/common.py +215 -0
  70. code_mower/doctor_checks/github.py +128 -0
  71. code_mower/doctor_checks/github_actions.py +11 -0
  72. code_mower/doctor_checks/github_actions_cost.py +99 -0
  73. code_mower/doctor_checks/github_actions_cost_summary.py +111 -0
  74. code_mower/doctor_checks/github_actions_failure_annotations.py +27 -0
  75. code_mower/doctor_checks/github_actions_failure_models.py +47 -0
  76. code_mower/doctor_checks/github_actions_failure_scan.py +200 -0
  77. code_mower/doctor_checks/github_actions_failure_selection.py +63 -0
  78. code_mower/doctor_checks/github_actions_failures.py +103 -0
  79. code_mower/doctor_checks/github_actions_permissions.py +55 -0
  80. code_mower/doctor_checks/github_api.py +79 -0
  81. code_mower/doctor_checks/github_branch.py +56 -0
  82. code_mower/doctor_checks/github_config.py +25 -0
  83. code_mower/doctor_checks/github_provider.py +61 -0
  84. code_mower/doctor_checks/github_repo.py +120 -0
  85. code_mower/doctor_checks/groups.py +36 -0
  86. code_mower/doctor_checks/models.py +96 -0
  87. code_mower/doctor_checks/output.py +86 -0
  88. code_mower/doctor_checks/presets.py +64 -0
  89. code_mower/doctor_checks/privacy.py +20 -0
  90. code_mower/doctor_checks/provider_api_model.py +138 -0
  91. code_mower/doctor_checks/provider_api_model_openai.py +29 -0
  92. code_mower/doctor_checks/provider_api_model_profiles.py +137 -0
  93. code_mower/doctor_checks/provider_env.py +113 -0
  94. code_mower/doctor_checks/provider_env_required.py +56 -0
  95. code_mower/doctor_checks/provider_env_tokens.py +100 -0
  96. code_mower/doctor_checks/provider_local_cli.py +162 -0
  97. code_mower/doctor_checks/provider_local_cli_commands.py +47 -0
  98. code_mower/doctor_checks/provider_local_cli_probe_config.py +70 -0
  99. code_mower/doctor_checks/provider_probe.py +20 -0
  100. code_mower/doctor_checks/provider_probe_auth.py +52 -0
  101. code_mower/doctor_checks/provider_probe_evaluation.py +109 -0
  102. code_mower/doctor_checks/provider_probe_json.py +45 -0
  103. code_mower/doctor_checks/provider_probe_remediation.py +39 -0
  104. code_mower/doctor_checks/providers.py +159 -0
  105. code_mower/doctor_checks/registry.py +69 -0
  106. code_mower/doctor_checks/runner.py +188 -0
  107. code_mower/doctor_checks/runtime.py +89 -0
  108. code_mower/doctor_checks/runtime_github_auth.py +148 -0
  109. code_mower/gemini_cli_audit_pr.py +897 -0
  110. code_mower/hermes_cli_audit_pr.py +436 -0
  111. code_mower/init.py +888 -0
  112. code_mower/lane_configs/__init__.py +37 -0
  113. code_mower/lane_configs/aider.py +32 -0
  114. code_mower/lane_configs/antigravity_cli.py +35 -0
  115. code_mower/lane_configs/claude.py +35 -0
  116. code_mower/lane_configs/codex.py +32 -0
  117. code_mower/lane_configs/devin.py +33 -0
  118. code_mower/lane_configs/gemini_cli.py +35 -0
  119. code_mower/lane_configs/hermes_cli.py +35 -0
  120. code_mower/lane_configs/local_llm.py +31 -0
  121. code_mower/local_llm_audit_pr.py +1364 -0
  122. code_mower/local_llm_bakeoff.py +458 -0
  123. code_mower/local_llm_calibration.py +441 -0
  124. code_mower/local_llm_profiles.py +66 -0
  125. code_mower/migration.py +508 -0
  126. code_mower/migration_install.py +292 -0
  127. code_mower/migration_mirror.py +392 -0
  128. code_mower/migration_readiness.py +237 -0
  129. code_mower/migration_rehearsal.py +718 -0
  130. code_mower/next_steps.py +441 -0
  131. code_mower/package.py +673 -0
  132. code_mower/package_content.py +444 -0
  133. code_mower/package_manifest.py +452 -0
  134. code_mower/package_paths.py +53 -0
  135. code_mower/package_rendering.py +90 -0
  136. code_mower/package_static.py +585 -0
  137. code_mower/prompts.py +267 -0
  138. code_mower/provider_registry.py +469 -0
  139. code_mower/provider_runners/__init__.py +60 -0
  140. code_mower/provider_runners/comments.py +31 -0
  141. code_mower/provider_runners/git.py +46 -0
  142. code_mower/provider_runners/github_auth.py +61 -0
  143. code_mower/provider_runners/github_pr.py +120 -0
  144. code_mower/provider_runners/process.py +58 -0
  145. code_mower/provider_runners/repo_paths.py +23 -0
  146. code_mower/provider_runners/text_schema.py +41 -0
  147. code_mower/provider_runners/verdict_artifacts.py +103 -0
  148. code_mower/provider_runners/workspace.py +57 -0
  149. code_mower/release_readiness.py +549 -0
  150. code_mower/reviewer_metrics.py +389 -0
  151. code_mower/saas_reviewer_labeler.py +809 -0
  152. code_mower/secrets.py +89 -0
  153. code_mower/templates/builder-experiment.example.json +55 -0
  154. code_mower/templates/calibration-corpus.example.json +129 -0
  155. code_mower/templates/calibration-corpus.json +129 -0
  156. code_mower/templates/code-mower.example.yml +423 -0
  157. code_mower/templates/context-packs.example.json +150 -0
  158. code_mower/templates/lane_prompts/base-audit.md +22 -0
  159. code_mower/templates/lane_prompts/calibration-policy.md +21 -0
  160. code_mower/templates/lane_prompts/context-driven-quality.md +21 -0
  161. code_mower/templates/lane_prompts/docs-design.md +12 -0
  162. code_mower/templates/lane_prompts/generic-programming.md +21 -0
  163. code_mower/templates/lane_prompts/operability.md +22 -0
  164. code_mower/templates/lane_prompts/package-runtime.md +12 -0
  165. code_mower/templates/lane_prompts/security-threat-model.md +22 -0
  166. code_mower/templates/product-support/code_mower +216 -0
  167. code_mower/templates/product-support/code_mower_standalone_pin.env +7 -0
  168. code_mower/templates/product-support/code_mower_standalone_shadow.sh +151 -0
  169. code_mower/templates/product-support/run_claude_audit_pr.sh +32 -0
  170. code_mower/templates/product-support/run_codex_audit_pr.sh +32 -0
  171. code_mower/templates/product-support/safe_gh_comment.py +96 -0
  172. code_mower/templates/providers.yml +454 -0
  173. code_mower/templates/reviewer-spend.example.json +28 -0
  174. code_mower/templates/reviewer-value-report.example.md +20 -0
  175. code_mower/templates/workflows/private-standalone-shadow.yml.j2 +106 -0
  176. code_mower/templates/workflows/review-clear-stale.yml.j2 +83 -0
  177. code_mower/trailer_comment_labeler.py +207 -0
  178. code_mower/versioning.py +32 -0
  179. code_mower-0.5.0b5.dist-info/METADATA +302 -0
  180. code_mower-0.5.0b5.dist-info/RECORD +185 -0
  181. code_mower-0.5.0b5.dist-info/WHEEL +5 -0
  182. code_mower-0.5.0b5.dist-info/entry_points.txt +2 -0
  183. code_mower-0.5.0b5.dist-info/licenses/LICENSE +202 -0
  184. code_mower-0.5.0b5.dist-info/licenses/NOTICE +10 -0
  185. code_mower-0.5.0b5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env python3
2
+ """Generic labeler for trailer-comment audit lanes.
3
+
4
+ Codex, Devin, and Local LLM audit comments all use the same state machine:
5
+ trusted comment author -> final verdict trailer/prose -> reviewed head check ->
6
+ terminal or needs label. Lane-specific values live in tools/lane_configs/.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import os
14
+ import re
15
+ import sys
16
+ from pathlib import Path
17
+ from typing import Any, Dict, Optional, Sequence
18
+
19
+ if __package__ and __package__.startswith("code_mower"):
20
+ from .audit_labeler_lib import (
21
+ LaneConfig,
22
+ LabelDecision,
23
+ apply_label_decision,
24
+ extract_reviewed_sha,
25
+ fetch_pull_request,
26
+ load_json,
27
+ sha_matches_reviewed_head,
28
+ )
29
+ from .lane_configs import load_lane_config
30
+ else:
31
+ try:
32
+ from tools.audit_labeler_lib import (
33
+ LaneConfig,
34
+ LabelDecision,
35
+ apply_label_decision,
36
+ extract_reviewed_sha,
37
+ fetch_pull_request,
38
+ load_json,
39
+ sha_matches_reviewed_head,
40
+ )
41
+ from tools.lane_configs import load_lane_config
42
+ except ImportError: # pragma: no cover - direct `python tools/foo.py` execution
43
+ from audit_labeler_lib import (
44
+ LaneConfig,
45
+ LabelDecision,
46
+ apply_label_decision,
47
+ extract_reviewed_sha,
48
+ fetch_pull_request,
49
+ load_json,
50
+ sha_matches_reviewed_head,
51
+ )
52
+ from lane_configs import load_lane_config
53
+
54
+
55
+ HEAD_CHANGED_PATTERN = re.compile(
56
+ r"HEAD_CHANGED_DURING_REVIEW\s*:\s*reviewed\b",
57
+ flags=re.IGNORECASE,
58
+ )
59
+
60
+
61
+ def classify_audit_comment(body: str, config: LaneConfig) -> Optional[str]:
62
+ """Return "done", "blocked", "needs", or None for a lane comment body."""
63
+ trailers = list(config.trailer_pattern().finditer(body))
64
+ if trailers:
65
+ label = trailers[-1].group(1).lower()
66
+ if label == config.done_label:
67
+ return "done"
68
+ if label == config.blocked_label:
69
+ return "blocked"
70
+ return "needs"
71
+
72
+ if HEAD_CHANGED_PATTERN.search(body):
73
+ return "needs"
74
+
75
+ if any(pattern.search(body) for pattern in config.pass_patterns):
76
+ return "done"
77
+ if config.label_state_fallbacks and _has_label_fallback(body, config.done_label):
78
+ return "done"
79
+
80
+ if any(pattern.search(body) for pattern in config.blocked_patterns):
81
+ return "blocked"
82
+ if config.label_state_fallbacks and _has_label_fallback(body, config.blocked_label):
83
+ return "blocked"
84
+
85
+ return None
86
+
87
+
88
+ def _has_label_fallback(body: str, label: str) -> bool:
89
+ escaped = re.escape(label)
90
+ return bool(
91
+ re.search(
92
+ rf"\**(?:Intended\s+|Expected\s+)?Label state:\**\s*`?\b{escaped}\b",
93
+ body,
94
+ flags=re.IGNORECASE,
95
+ )
96
+ or re.search(
97
+ rf"(?:Intended|Expected)\s+labels?:\s*(?:add\s+)?`?\b{escaped}\b",
98
+ body,
99
+ flags=re.IGNORECASE,
100
+ )
101
+ )
102
+
103
+
104
+ def resolve_label_decision(
105
+ event: Dict[str, Any],
106
+ *,
107
+ current_head_sha: Optional[str],
108
+ config: LaneConfig,
109
+ ) -> tuple[Optional[LabelDecision], str]:
110
+ if event.get("action") != "created":
111
+ return None, f"unsupported action: {event.get('action')}"
112
+
113
+ issue = event.get("issue") or {}
114
+ if "pull_request" not in issue:
115
+ return None, "comment is not on a pull request"
116
+
117
+ comment = event.get("comment") or {}
118
+ author = (comment.get("user") or {}).get("login", "")
119
+ if author.lower() not in config.comment_authors():
120
+ return None, f"ignored comment author: {author}"
121
+
122
+ body = comment.get("body") or ""
123
+ status = classify_audit_comment(body, config)
124
+ if status is None:
125
+ return None, f"comment is not a final {config.display_name} audit result"
126
+
127
+ issue_number = int(issue["number"])
128
+ reviewed_sha = extract_reviewed_sha(body)
129
+ if status != "needs" and not reviewed_sha:
130
+ return None, "audit result is missing Head SHA"
131
+ if reviewed_sha and current_head_sha and not sha_matches_reviewed_head(reviewed_sha, current_head_sha):
132
+ return LabelDecision(
133
+ issue_number=issue_number,
134
+ add_label=config.needs_label,
135
+ remove_labels=(config.done_label, config.blocked_label),
136
+ reviewed_sha=reviewed_sha,
137
+ reason=f"reviewed SHA {reviewed_sha} does not match current head {current_head_sha}",
138
+ ), "label needs audit"
139
+
140
+ if status == "needs":
141
+ return LabelDecision(
142
+ issue_number=issue_number,
143
+ add_label=config.needs_label,
144
+ remove_labels=(config.done_label, config.blocked_label),
145
+ reviewed_sha=reviewed_sha,
146
+ reason="audit reported head changed during review",
147
+ ), "label needs audit"
148
+
149
+ if status == "done":
150
+ return LabelDecision(
151
+ issue_number=issue_number,
152
+ add_label=config.done_label,
153
+ remove_labels=(config.needs_label, config.blocked_label),
154
+ reviewed_sha=reviewed_sha,
155
+ reason="audit passed",
156
+ ), "label done"
157
+
158
+ return LabelDecision(
159
+ issue_number=issue_number,
160
+ add_label=config.blocked_label,
161
+ remove_labels=(config.needs_label, config.done_label),
162
+ reviewed_sha=reviewed_sha,
163
+ reason="audit blocked or incomplete",
164
+ ), "label blocked"
165
+
166
+
167
+ def main(argv: Optional[Sequence[str]] = None) -> int:
168
+ parser = argparse.ArgumentParser()
169
+ parser.add_argument("--lane", required=True, help="Trailer audit lane from tools/lane_configs/.")
170
+ args = parser.parse_args(argv)
171
+ config = load_lane_config(args.lane)
172
+
173
+ event_path = Path(os.environ["GITHUB_EVENT_PATH"])
174
+ repo = os.environ["GITHUB_REPOSITORY"]
175
+ event = load_json(event_path)
176
+
177
+ current_head_sha = os.environ.get("DRY_RUN_HEAD_SHA")
178
+ tokens = config.github_tokens_from_env()
179
+ if not os.environ.get("DRY_RUN"):
180
+ if not tokens:
181
+ token_names = " or ".join(config.token_env_vars)
182
+ print(f"error: {token_names} is required", file=sys.stderr)
183
+ return 1
184
+ issue = event.get("issue") or {}
185
+ issue_number = int(issue.get("number", 0))
186
+ if issue_number and "pull_request" in issue:
187
+ current_head_sha = fetch_pull_request(repo, issue_number, tokens=tokens)["head"]["sha"]
188
+
189
+ decision, reason = resolve_label_decision(event, current_head_sha=current_head_sha, config=config)
190
+ if decision is None:
191
+ print(f"skip: {reason}")
192
+ return 0
193
+
194
+ if os.environ.get("DRY_RUN"):
195
+ print(json.dumps({"decision": decision.__dict__, "reason": reason}, sort_keys=True))
196
+ return 0
197
+
198
+ apply_label_decision(repo, decision, tokens=tokens)
199
+ print(
200
+ f"applied: add {decision.add_label}; remove {', '.join(decision.remove_labels)} "
201
+ f"on {repo}#{decision.issue_number} ({decision.reason})"
202
+ )
203
+ return 0
204
+
205
+
206
+ if __name__ == "__main__":
207
+ raise SystemExit(main())
@@ -0,0 +1,32 @@
1
+ """Version and public package-spec helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+
7
+
8
+ PUBLIC_REPO_URL = "https://github.com/codemower-ai/code-mower"
9
+ STAGE_TAG_NAMES = {
10
+ "a": "alpha",
11
+ "b": "beta",
12
+ "rc": "rc",
13
+ }
14
+
15
+
16
+ def release_tag_for_version(version: str) -> str:
17
+ match = re.fullmatch(
18
+ r"(?P<base>\d+\.\d+\.\d+)(?:(?P<stage>a|b|rc)(?P<num>\d+))?",
19
+ version,
20
+ )
21
+ if not match:
22
+ return f"v{version}"
23
+ base = match.group("base")
24
+ stage = match.group("stage")
25
+ number = match.group("num")
26
+ if not stage or not number:
27
+ return f"v{base}"
28
+ return f"v{base}-{STAGE_TAG_NAMES[stage]}.{number}"
29
+
30
+
31
+ def public_package_spec(version: str, repo_url: str = PUBLIC_REPO_URL) -> str:
32
+ return f"git+{repo_url}.git@{release_tag_for_version(version)}"
@@ -0,0 +1,302 @@
1
+ Metadata-Version: 2.4
2
+ Name: code-mower
3
+ Version: 0.5.0b5
4
+ Summary: Multi-reviewer AI code audit orchestration
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ License-File: NOTICE
10
+ Requires-Dist: PyYAML>=6.0
11
+ Dynamic: license-file
12
+
13
+ # Code Mower
14
+
15
+ Code Mower helps teams set up AI peer-programmer and reviewer lanes on real
16
+ GitHub pull requests, then measure which builders and reviewers are useful on
17
+ their actual codebase.
18
+
19
+ The short version:
20
+
21
+ - create safe, manual-first reviewer lanes for Codex, Claude, Gitar, and other
22
+ AI review tools;
23
+ - run setup diagnostics before a lane can surprise you with spend, source
24
+ exposure, or GitHub Actions churn;
25
+ - generate local reviewer value reports from known-clean and known-blocked PRs;
26
+ and
27
+ - optionally share sanitized metadata with [CodeMower.com](https://codemower.com)
28
+ for private team dashboards today and aggregate benchmarks as that dataset
29
+ becomes useful.
30
+
31
+ Code Mower is local-first. The OSS tool works without the hosted service.
32
+ Default cloud bundles exclude source code, raw diffs, raw model transcripts,
33
+ raw stdout/stderr, auth output, and secrets.
34
+
35
+ ## Design Principles
36
+
37
+ Code Mower should feel like an engineering tool, not a demo harness:
38
+
39
+ - **Local first:** install, diagnose, audit, and report without a hosted
40
+ account.
41
+ - **Manual first:** new reviewer lanes start explicit and observable before
42
+ they can affect merge policy.
43
+ - **Evidence first:** promote lanes from real calibration data on your
44
+ repository, not from generic benchmark claims.
45
+ - **Privacy first:** cloud sharing is opt-in metadata by default, with source,
46
+ diffs, transcripts, auth output, and secrets excluded.
47
+ - **Composable by design:** providers, lenses, context packs, calibration, and
48
+ cloud upload stay separate so teams can adopt only the parts they trust.
49
+
50
+ ## What It Looks Like
51
+
52
+ `code-mower doctor --preflight` is the first useful command. It checks your
53
+ runtime, GitHub setup, provider CLIs, token posture, optional cloud setup, and
54
+ private-repo Actions cost traps. `--preflight` is the friendly name for the
55
+ versioned v0.5 first-run preset, so `doctor --v05` remains equivalent for
56
+ scripts.
57
+
58
+ Example, shortened:
59
+
60
+ ```text
61
+ $ code-mower doctor --preflight
62
+ PASS config.validate config validates
63
+ PASS profile.select selected profile: codex, claude_audit, gitar
64
+ PASS runtime.python Python 3.12 satisfies Code Mower requirements
65
+ PASS runtime.github_auth GitHub CLI auth probe succeeded
66
+ PASS runtime.local_cli codex codex found
67
+ PASS runtime.local_cli claude claude auth smoke probe succeeded
68
+ WARN env.tokens codex missing CODEX_AUDIT_LABEL_TOKEN or GITHUB_TOKEN
69
+ WARN github.actions_cost private repo has high-frequency metadata workflows
70
+ PASS cloud.token optional Code Mower Cloud token file is configured
71
+
72
+ Summary: warn, 20 checks, 0 failures, 5 warnings
73
+ Next: fix token warnings, keep paid lanes manual, then generate a value report.
74
+ ```
75
+
76
+ The warnings are the point: Code Mower should make setup, cost, and trust
77
+ boundaries visible before you promote any reviewer lane.
78
+
79
+ See a fuller static transcript: [docs/first-run-transcript.md](docs/first-run-transcript.md).
80
+
81
+ ## See The Value Shape First
82
+
83
+ If you want to understand the product before installing anything, start with
84
+ the checked-in demo calibration package:
85
+
86
+ - [examples/demo-calibration/README.md](examples/demo-calibration/README.md)
87
+ - [examples/demo-calibration/reviewer-value-report.md](examples/demo-calibration/reviewer-value-report.md)
88
+ - [docs/first-user-demo-transcript.md](docs/first-user-demo-transcript.md)
89
+
90
+ The example is intentionally tiny and synthetic: one known-clean control, one
91
+ known-blocked control, and three reviewer lanes. It shows the decision Code
92
+ Mower is built to support: which AI reviewers are useful, noisy, expensive,
93
+ fast, or eligible for stronger merge policy on your actual codebase.
94
+
95
+ ## Try It First
96
+
97
+ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
98
+
99
+ ```bash
100
+ python3.12 --version
101
+ pipx install --python python3.12 "git+https://github.com/codemower-ai/code-mower.git@v0.5.0-beta.5"
102
+ code-mower --version
103
+ ```
104
+
105
+ From the repository you want to pilot:
106
+
107
+ ```bash
108
+ code-mower init --easy
109
+ code-mower doctor --preflight
110
+ code-mower checks detect --json
111
+ ```
112
+
113
+ When those look sane, write the generated setup to a reviewable folder and
114
+ produce the starter local report:
115
+
116
+ ```bash
117
+ code-mower init --easy --apply --output-dir .code-mower.generated
118
+ code-mower calibration value-report .code-mower.generated/calibration-corpus.json \
119
+ --output .code-mower/reviewer-value-report.md
120
+ ```
121
+
122
+ The generated starter corpus proves the command path. To bootstrap a draft from
123
+ your repository history:
124
+
125
+ ```bash
126
+ code-mower calibration auto-discover \
127
+ --repo OWNER/REPO \
128
+ --last-n 20 \
129
+ --output .code-mower/draft-calibration-corpus.json
130
+ ```
131
+
132
+ Auto-discovery uses recent merged PR metadata, structured audit trailers, and
133
+ review-request signals to propose known-clean and known-blocked cases. Review
134
+ every disposition before using it for lane promotion or merge policy.
135
+
136
+ Full walkthrough: [docs/try-in-10-minutes.md](docs/try-in-10-minutes.md).
137
+ First-time command map: [docs/launch-command-surface.md](docs/launch-command-surface.md).
138
+
139
+ ## Why Not Just Run Codex Or Claude Yourself?
140
+
141
+ You should, at first. Code Mower is not a replacement for a good local agent or
142
+ reviewer CLI.
143
+
144
+ Code Mower adds the operating layer around those tools:
145
+
146
+ - consistent reviewer lanes on real pull requests;
147
+ - setup checks for auth, Python, GitHub permissions, private-repo Actions cost,
148
+ provider CLIs, and cloud-token posture;
149
+ - calibration against known-clean and known-blocked PRs instead of vibes;
150
+ - evidence-gated lane promotion: informational, selective, or merge-gating;
151
+ - spend/latency/usefulness reporting across providers and lenses; and
152
+ - privacy boundaries for optional metadata sharing.
153
+
154
+ The goal is to learn which AI builders and reviewers are worth trusting on your
155
+ actual codebase, at what cost, and under which merge policy.
156
+
157
+ ## Optional Cloud Sharing
158
+
159
+ Code Mower Cloud currently provides private team dashboards from opt-in
160
+ metadata. Cross-team cohort benchmarking is a roadmap feature that becomes
161
+ valuable only as enough teams contribute sanitized data. The local OSS path
162
+ stays useful without the hosted service.
163
+
164
+ The cloud value loop is:
165
+
166
+ 1. run local Code Mower reports;
167
+ 2. inspect the metadata-only bundle or dogfood preview;
168
+ 3. upload only with `--yes`; and
169
+ 4. use [CodeMower.com](https://codemower.com) to see repo rollups, provider/lens
170
+ signal, cost/latency, noisy lanes, and next-lane recommendations over time.
171
+
172
+ Start with a dry run:
173
+
174
+ ```bash
175
+ code-mower cloud dogfood --json
176
+ ```
177
+
178
+ Nothing uploads unless you pass `--yes`.
179
+
180
+ To connect to [CodeMower.com](https://codemower.com), sign in at
181
+ [https://codemower.com/login](https://codemower.com/login), create or receive a
182
+ team token, then run:
183
+
184
+ ```bash
185
+ code-mower cloud setup \
186
+ --token-stdin \
187
+ --team-id "YOUR_TEAM_SLUG" \
188
+ --install-id "your-laptop" \
189
+ --out ~/.config/code-mower/tokens/your-laptop.env
190
+ ```
191
+
192
+ Cloud sharing details, historical catch-up, and repo-sync commands live in
193
+ [docs/cloud-sharing.md](docs/cloud-sharing.md).
194
+
195
+ ## Provider Posture
196
+
197
+ The first recommended lanes are local/manual:
198
+
199
+ | Lane | Default role | Merge posture |
200
+ | --- | --- | --- |
201
+ | Codex audit | structured local peer audit | merge-gating eligible after setup |
202
+ | Claude audit | structured local peer audit | merge-gating eligible after setup |
203
+ | Gitar | advisory third signal | informational until calibrated |
204
+
205
+ Everything else starts manual or informational until your own calibration data
206
+ proves it is useful: Antigravity/Gemini, Hermes, CodeRabbit CLI, Cursor BugBot,
207
+ Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
208
+
209
+ Provider details: [docs/provider-matrix.md](docs/provider-matrix.md).
210
+ Setup/auth fixes: [docs/troubleshooting.md](docs/troubleshooting.md).
211
+
212
+ ## Road To v1.0
213
+
214
+ The v1.0 bar is not "every provider works." The v1.0 bar is that a fresh senior
215
+ engineer can:
216
+
217
+ 1. install Code Mower in a clean repo;
218
+ 2. understand the local/cloud trust boundary;
219
+ 3. run `init --easy` and `doctor --preflight`;
220
+ 4. detect and run the repo's native lint/test/build surface instead of assuming
221
+ every project uses the same tools;
222
+ 5. produce a local value report from known PR outcomes;
223
+ 6. decide which lanes should stay informational, selective, or merge-gating;
224
+ and
225
+ 7. optionally upload sanitized metadata to CodeMower.com and see useful team
226
+ dashboard signal.
227
+
228
+ Future builder/orchestrator experiments extend the same loop from "who reviews
229
+ best?" to "which AI builder plus reviewer loop ships best on this product?" See
230
+ [docs/builder-experiments.md](docs/builder-experiments.md) and
231
+ [docs/authoring-intelligence.md](docs/authoring-intelligence.md).
232
+
233
+ ## Installation Status
234
+
235
+ The current public beta is `v0.5.0-beta.5` from
236
+ [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower). PyPI
237
+ distribution builds now run from GitHub Releases. Publishing to PyPI remains
238
+ off by default until trusted publishing is configured, so use the tagged GitHub
239
+ install command above for this beta.
240
+
241
+ For source checkout development and release rehearsal, use:
242
+
243
+ ```bash
244
+ scripts/dev-python
245
+ scripts/dev-python -m venv .venv
246
+ .venv/bin/python -m pip install -e . ruff
247
+ ```
248
+
249
+ The wrapper resolves Python 3.12+ and refuses stale or old system Python shims.
250
+
251
+ ## Known Limitations
252
+
253
+ - PyPI distribution builds exist, but publishing is gated until trusted
254
+ publishing is configured; use the tagged GitHub install command. See
255
+ [docs/pypi-release.md](docs/pypi-release.md) for the TestPyPI/PyPI
256
+ activation path.
257
+ - GitHub is the primary supported forge. GitLab, Bitbucket, and ACP bridges are
258
+ roadmap items.
259
+ - Hosted/SaaS reviewers start informational or manual until calibration data
260
+ supports promotion.
261
+ - `calibration auto-discover` is a bootstrap tool, not an adjudicator. It
262
+ proposes a draft corpus from PR history; humans still confirm the ground truth.
263
+ - CodeMower.com currently provides private team dashboards; cohort benchmarks
264
+ are roadmap work and should not be treated as live product value yet.
265
+ - Self-service cloud data deletion/export basics are live. Retention remains
266
+ conservative and team-controlled while automated retention jobs are roadmap
267
+ work.
268
+ - Advanced/provider/operator commands remain available behind
269
+ `code-mower --help-all`. The default help path stays focused on `init`,
270
+ `doctor`, calibration, value reports, and optional cloud export/upload.
271
+
272
+ ## Docs Map
273
+
274
+ - [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md)
275
+ - [Quickstart](docs/quickstart.md)
276
+ - [First Run Transcript](docs/first-run-transcript.md)
277
+ - [First-User Demo Transcript](docs/first-user-demo-transcript.md)
278
+ - [First-User Install Rehearsal](docs/first-user-install-rehearsal.md)
279
+ - [Launch Command Surface](docs/launch-command-surface.md)
280
+ - [Demo Calibration Example](examples/demo-calibration/README.md)
281
+ - [PyPI Release Runbook](docs/pypi-release.md)
282
+ - [Sample Doctor Output](docs/sample-doctor-output.md)
283
+ - [Architecture](docs/architecture.md)
284
+ - [Provider Matrix](docs/provider-matrix.md)
285
+ - [GitHub Setup](docs/github-setup.md)
286
+ - [Cloud Sharing](docs/cloud-sharing.md)
287
+ - [Cloud Data Contract](docs/cloud-data-contract.md)
288
+ - [Privacy And Threat Model](docs/privacy-threat-model.md)
289
+ - [Current State And Roadmap](docs/current-state-and-roadmap.md)
290
+ - [Public Release Checklist](docs/public-release-checklist.md)
291
+ - [Changelog](CHANGELOG.md)
292
+ - [Contributing](CONTRIBUTING.md)
293
+ - [Support](SUPPORT.md)
294
+ - [Security Policy](SECURITY.md)
295
+ - [Code of Conduct](CODE_OF_CONDUCT.md)
296
+
297
+ ## License
298
+
299
+ The Code Mower open-source core is licensed under Apache-2.0. Hosted
300
+ benchmarking and reporting, managed integrations, private telemetry and
301
+ benchmark data products, enterprise controls, and support are commercial
302
+ surfaces unless licensed otherwise.