Your Slack Script Just Shipped
The second team is the product threshold
Three weeks after the 857-line honesty machine, managers were running reports weekly. Slack carried forked copies with incompatible flags. Excel exports became the source of truth in staff meetings - and breakage was visible.
On 2026-06-01 at 09:32, commit 9d47215 refactored github-analysis into a uv-managed CLI with analyze, export, and run commands. This note is about recognizing when a personal script becomes team infrastructure.
Here's what this piece covers: the product threshold, what changed in the refactor, version as contract, and three lead actions.
Part of Field Notes: agentic delivery.
1. The leadership problem
Ad-hoc scripts spread via Slack. Everyone runs different flags. When the spreadsheet breaks mid-staff-meeting, you learn you never had an owner.
Wrong: "We refactored for cleanliness."
Right: "Jun 1 9d47215: monolith to github-analysis CLI because three managers were running incompatible exports."
The anti-pattern is the eternal personal script - no owner, no contract, no --help.
2. What the git history shows
| Date | Commit | State |
|---|---|---|
| 2026-04-10 | d52975b |
857-line single file + README |
| 2026-06-01 09:32 | 9d47215 |
Modular package, pyproject + uv, CLI entry point |
9d47215 - Refactor into modular CLI with uv, team summaries, and Excel export - touched the whole repo layout:
github_analysis/cli/commands/analyze.py
github_analysis/cli/commands/export.py
github_analysis/cli/commands/run.py
github_analysis/analysis/ github_analysis/export/
github_analysis/pipeline/
3. What changed in the refactor
Package layout - commands, analysis, export, pipeline separated. Tests could target modules instead of a god file.
Commands:
| Command | When to use | Output |
|---|---|---|
analyze |
PR timeline / person rollups for a window | TSV under analysis-results/ |
export |
Regenerate Excel from cached run | .xlsx via openpyxl optional group |
run |
Full pipeline - fetch, analyze, export | Run logs + artifacts |
Entry point as contract:
import click
@click.group()
@click.version_option("2.0.0")
def cli():
"""Engineering metrics - analyze, export, run."""
@cli.command()
@click.option("--since", required=True, help="Half-open window start (ISO).")
@click.option("--until", required=True, help="Half-open window end (ISO).")
def analyze(since: str, until: str):
"""PR timeline + person rollups for [since, until)."""
...Version pin (2.0.0) - signals contract to consumers. Legacy wrapper kept github_pr_timeline_report.py forwarding to analyze for one release cycle.
README as contract - foreshadow article 10. --help before new metrics.
The named pattern:
Script → product threshold - modular CLI, version pin, --help before new metrics when a second team depends on you.4. What broke / lessons
Refactor day is expensive - batch breaking changes when dependents are few. I waited until three managers depended on the script; I should have named an owner at two.
The afternoon of 2026-06-01 also shipped wrong person-summary metrics - three correction commits by 10:52 (article 09). Productizing without definitional discipline just scales bad numbers faster.
5. What I'd do as a lead
- Name an owner when the second team asks for the report. Not when the fifth team complains.
- Invest in
--helpand README before new metrics. Columns need definitions before staff meeting. - Keep a legacy entry point for one release cycle. Forks die slower than you hope.
Further reading
- An 857-line honesty machine -
d52975b· 2026-04-10 - Three wrong metrics same morning - later in series
- github-analysis: commit
9d47215· 2026-06-01 ·docs/architecture.md