Files
pragent/README.md
T
Marcos 30d2a3d7da feat(factory): five review skills + a per-review cost model
Skills — the primary now loads conditionally (each one is input tokens), per a
load table in pragent.md:

- attention-tiering: classify every PR trivial/lite/full/oversized BEFORE
  reading anything, and cap file reads, linter runs and subagent fan-out per
  tier. This is the cost governor; the other skills defer to its budget.
- linter-playbook: per-ecosystem detect-and-run commands scoped to changed
  files, the never-install rule, and how to turn a diagnostic into a finding
  instead of pasting tool output.
- security-lens: the inline security checklist for when @security isn't worth
  delegating, built around a source -> sink test each finding must pass.
- malicious-change: hostile-PR detection — injection aimed at the reviewer,
  install/CI-time hooks, obfuscated payloads, dependency confusion, logic
  backdoors. Complements the runtime containment added in the previous commit:
  that stops the agent being hijacked, this makes it report the attempt.
- comment-craft: how to write problem/fix/suggestion so a maintainer can act in
  one read, and what to cut.

pilot/cost_model.py — prices a review against published Claude and OpenAI rates
(fetched 2026-08-18). Prompt sizes are measured from the factory files rather
than guessed; per-tier workloads come from the tiering budgets. The model is
explicit about the thing that actually dominates an agent loop: the whole
conversation is resent every step, so caching moves ~2.3x of the bill.

Blended over a 5/35/55/5 mix with caching on: ~$0.61/PR on Opus 5 or GPT-5.6
Sol, ~$0.24 on Sonnet 5 or Terra, ~$0.12 on Haiku 4.5, ~$0.02 on Luna. At 350
PRs/month that's ~$212 / ~$85 / ~$43 / ~$8.50.

Tests: 101 -> 122.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B11e8TZZxJyzHW7jj7KWUN
2026-08-18 04:53:49 +00:00

125 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# pragent
An extensible, forge-agnostic PR review framework. Not a product — a toolkit that teams
extend with their own review dimensions.
**Status:** design approved; framework build deferred. A **pilot** is live on
`glm-5.2:cloud` with two delivery paths:
- **Central webhook service** (preferred, least per-repo setup): a Gitea
user-level webhook posts PR events to an always-on in-cluster service that
gates on the `AI-REVIEW` label. Onboarding a repo = add `pragent-bot`
collaborator + create the label + label a PR. See
[`pilot/README-webhook.md`](pilot/README-webhook.md).
- **CI-step** (legacy): a per-repo Gitea Action fetches the reviewer script at
runtime. See [`pilot/README.md`](pilot/README.md).
The framework design remains at
[`docs/plans/2026-08-04-pragent-design.md`](docs/plans/2026-08-04-pragent-design.md);
the pilot is its bootstrap and will be superseded by `pragent review` when the
framework build resumes.
## What it is
`pragent` runs as a CI step. It reads a pull request, decides how much attention the
change deserves, runs the analyzers that apply, and posts ranked findings back to the
forge.
```
pragent init # one-time repo scan → .pragent/profile.yml (committed, reviewable)
pragent review # the CI step: tier → analyze → aggregate → publish
pragent explain # why did this PR get this tier / these findings?
pragent replay # re-run a past PR against a new prompt or model (the eval loop)
pragent doctor # config, credentials, and adapter health
```
## Why not CodeRabbit / Greptile / Qodo
Those are good products with fixed review dimensions and per-seat pricing. `pragent`
targets the case where a platform team needs to **add its own dimensions** — an internal
compliance rule, a service-catalog ownership check, a house performance idiom — without
forking a vendor's reviewer. Cost lands in the same range (~$25/dev/month at 350 PRs/mo
for 20 devs), but the analyzers, the data, and the analytics are yours.
## Attention tiers
Every PR is classified before any expensive work happens. Deterministic rules decide
first; an ambiguous case gets one cheap model call as tie-breaker.
| Tier | What it means | Cost/PR |
|---|---|---|
| `trivial` | lockfile bumps, generated code, docs typos | ~$0.005 |
| `lite` | small change, no risk paths | ~$0.08 |
| `full` | the default for real changes | ~$0.802.00 |
| `oversized` | too big to review whole; structural summary + deep pass on the hot subset | ~$5 ceiling |
Every tier decision records *why*, so a surprising outcome is explainable rather than
mysterious.
## What it costs
The pilot runs on `glm-5.2:cloud` through the on-network headroom proxy, so today it
bills nothing per token — but the token *work* is real, and `pilot/cost_model.py`
prices it against published API rates. The factory's prompt sizes are measured from
the files in this repo; the per-tier workloads come from the `attention-tiering`
budgets. Blended over a 5/35/55/5 tier mix, prompt caching on:
| Model | per PR | 350 PRs/month |
|---|---:|---:|
| Claude Opus 5 / GPT-5.6 Sol | ~$0.61 | ~$212 |
| Claude Sonnet 5 / GPT-5.6 Terra | ~$0.24 | ~$85 |
| Claude Haiku 4.5 | ~$0.12 | ~$43 |
| GPT-5.6 Luna | ~$0.02 | ~$8.5 |
Run `python3 pilot/cost_model.py --help` for other mixes and PR volumes. The
dominant cost is the agent loop resending its own context each step, not the diff —
turning prompt caching off multiplies the bill by ~2.3x, which is why the tiering
skill caps steps, file reads, and subagent fan-out per tier.
## Extension points
Five, all documented in the design doc. Teams override or add; nobody forks.
1. **Analyzers** — drop a YAML + prompt in `.pragent/analyzers/`, or install from npm
2. **Forge adapters** — Gitea, GitLab, GitHub, local diff
3. **Tier policy** — thresholds and the path risk map, per repo or per org
4. **Profile enrichers** — extend what `pragent init` learns about a repo
5. **Emitter sinks** — JSONL by default, OpenTelemetry, or your own
Org config can lock keys, so a repo cannot quietly disable the security analyzer.
## Design principles
- **Polyglot by construction.** Language knowledge lives in the repo profile, not in the
reviewer. A new language is a profile change, not a core change.
- **One shared prompt prefix.** All analyzers for a PR share a byte-identical cached
prefix. This is what makes fan-out affordable; it is enforced, not hoped for.
- **Everything is traceable.** Tier reasons, token counts, cost, latency, and finding
outcomes are recorded per run. False-positive rate is measurable per analyzer.
- **Fail open.** A budget ceiling or an analyzer crash yields a partial review with a
clear note, never a blocked pipeline with no explanation.
- **The reviewed code is untrusted input.** The reviewer runs an agent over a
branch anyone with PR access can write. So it holds no credentials in its
environment, the checkout is stripped of files an agent runtime would load as
instructions, PR-authored text is fenced as data, and reviewer config is read
from the base branch. See "Threat model" in
[`pilot/README-webhook.md`](pilot/README-webhook.md).
## Stack
TypeScript + Node, built on the [`pi`](https://github.com/badlogic/pi-mono) agent SDK.
Shipped as an npm package and an OCI image, so CI runners need no local Node install.
## Roadmap
1. Walking skeleton — local diff, one analyzer, rules-only tiering
2. Gitea end to end — adapter, Woodpecker step, PR comments, status checks
3. Profile + full tier — `pragent init`, shared-prefix caching, analyzer fan-out
4. Extensibility hardening — plugin loading, config layering, `explain` / `replay`
5. Second forge — GitLab adapter, Jenkins recipe
6. Analytics maturity — OTel export, feedback loop, eval harness
## License
TBD.