Files
small-scripts/specs/auto-draft.spec.md

123 lines
6.0 KiB
Markdown

# auto-draft
## Purpose
Scan the writing dossiers for AI-pipeline work and schedule jobs in priority order, using only the "spare" capacity of the current subscription window. Designed to be run from a cron job (hourly) so that it picks up work as spare capacity appears.
The script is **dryrun-only** in this revision: it shows the spare capacity and the three priority queues, but does not execute any jobs. Job execution is a later stage.
## Usage
```
auto-draft --provider <provider> --threshold <pct> --polish-score <0-10> [OPTIONS]
Required:
--provider PROVIDER Subscription provider to draw capacity from: anthropic or minimax
--threshold PERCENT Maximum subscription utilisation allowed over the period, as a
percentage (e.g. 50 = use up to 50% of the weekly allowance).
The script computes the linear limit at the current point in the
period and reports the spare capacity.
--polish-score N Paragraph score below which a paragraph is queued for polishing
(e.g. 7 means "polish any paragraph with score < 7").
Options:
--base-dir PATH Root directory to scan for dossier files. Defaults to ".".
Recurses into subdirectories.
-n, --dryrun Show capacity and queues without executing. This is the default
behaviour for this revision; the flag is explicit so the cron
command line is self-documenting.
-h, --help Show this help message and exit.
```
## Behaviour
1. Probe the live subscription for the given provider. The script shells out to `agent-subscriptions --output json` and reads the relevant provider's `seven_day` window.
2. Compute the spare capacity against the supplied threshold:
- `last_renewed = reset_at - 7 days` (the weekly window is treated as a rolling 7-day period)
- `period_seconds = 7 * 86400`
- `elapsed_seconds = max(0, now - last_renewed)`
- `limit_pct = elapsed_seconds / period_seconds * threshold` (the linear allowance at this point in the period)
- `spare_pct = limit_pct - utilization_pct` (positive = under budget, negative = over budget)
3. Discover titles by scanning for `*.overview.md` source files under `--base-dir` (recursively). Each title is the stem of the source file (e.g. `01-ai-is-an-amplifier`); the numeric ID is the leading digits before the first `-`.
4. Build three priority queues, in priority order:
- **Polish queue (highest priority)** — for every title whose `*.ai_score.<provider>.md` exists, parse the file and find paragraphs with `score < polish_score` and not marked exempt. If any such paragraph exists, the whole title is queued for polish.
- **Scoring queue (second priority)** — for every title whose `*.ai_generated.<provider>.md` exists but whose `*.ai_score.<provider>.md` does not. The job is to score the generated file.
- **Generation queue (lowest priority)** — for every title whose `*.ai_generated.<provider>.md` does not exist. The job is to generate the draft from the source brief.
5. Sort each queue by numeric ID ascending (titles without a numeric ID sort last).
6. Print the spare capacity and the three sorted queues.
## Score file format
The `*.ai_score.<provider>.md` files embed per-paragraph scores and an exempt marker as inline HTML comments after each paragraph:
```markdown
This is a great paragraph with polish. <!-- score: 9 -->
This is a middling paragraph. <!-- score: 6 -->
This is already reviewed and acceptable. <!-- score: 5 --><!-- exempt: true -->
```
Regex patterns:
- Score: `<!--\s*score:\s*(\d+)\s*-->`
- Exempt: `<!--\s*exempt:\s*true\s*-->`
A paragraph is queued for polish if it has a score comment with a value below `polish-score` AND does not have an exempt comment. Paragraphs without a score comment are not eligible for polishing (they are skipped), even if the file contains other scored paragraphs.
## Spare capacity output
```
[auto-draft] Spare capacity for Anthropic
Reset at: 2026-08-07T23:00:00+00:00
Renewed at: 2026-07-31T23:00:00+00:00
Elapsed: 16h 18m of 7d (9.7%)
Threshold: 50.0%
Linear limit: 4.9%
Current usage: 41.2%
Spare capacity: -36.4% (over budget; do not queue any work)
```
For a healthy budget:
```
Spare capacity: 23.5% (under budget)
```
## Queue output
```
[auto-draft] Polish queue (priority 1) — 3 items
01-ai-is-an-amplifier 2 paragraphs below 7 (of 4 scored)
02-five-layers-of-an-agent-harness 1 paragraph below 7
05-the-compound-engineering-loop 3 paragraphs below 7
[auto-draft] Scoring queue (priority 2) — 1 item
03-shadow-agents-are-the-new-shadow-it
[auto-draft] Generation queue (priority 3) — 8 items
04-risk-proportionate-delivery
06-backpressure-is-coming-for-your-ci
07-tests-are-law-llms-are-not-the-judge
...
```
## Edge cases
- If the provider probe fails (`available: false`), print a warning and skip the capacity section. Still build and print the queues.
- If the seven-day `reset_at` is missing, skip the capacity section (cannot compute `last_renewed`). Still build and print the queues.
- If a title has no numeric ID prefix, sort it last in every queue.
- If the base directory contains no source files, print all three queues as empty.
- If a source file's directory also contains the `ai_score` and `ai_generated` files, the title is in the polish queue (or none, if all paragraphs pass). Otherwise scoring or generation.
- Exit 0 unless the CLI args are invalid. The script is informational; one bad provider probe should not fail the cron.
## Dryrun behaviour
This revision is dryrun-only. The script always prints the capacity and queues. Job execution is out of scope until the design is approved.
## Examples
```sh
auto-draft --provider anthropic --threshold 50 --polish-score 7
auto-draft --provider anthropic --threshold 50 --polish-score 7 --base-dir /home/paul/dev/claude/writing/oreillyconsulting
auto-draft --provider minimax --threshold 70 --polish-score 8 --dryrun
```