Files
pragent/docs/architecture.md
T

82 lines
3.8 KiB
Markdown

# pragent current architecture
Status: pilot implementation, September 2026.
## System shape
```text
Gitea pull_request webhook
│ signed HTTP
webhook_server ── trusted base config ──► review_config
│ bounded worker
review_pr facade/orchestrator
├── entrypoints/gitea fetch diff, reviews, config; publish review
├── diff_compress reduce prompt context
├── opencode review orchestration seam
│ ├── opencode_workspace archive, sanitization, brief, factory
│ ├── opencode_lens_config reviewer configuration and selection
│ └── opencode_synthesis normalization, deduplication, summaries
├── review/budget trusted limits and cumulative accounting
├── review parsing normalize findings + validate anchors
├── feedback persist reactions and derive scores
└── langfuse_trace usage, cost, evaluation telemetry
```
## Seams and responsibilities
The external seam is `ai_review.review_pr(...)`: one call represents one review
attempt and returns success/skip status. The top-level module and
`review/ai_review.py` are compatibility facades; the current implementation is
implemented by `review/pipeline.py`, with pure transforms and adapters split
into the neighboring modules.
The internal seams are deliberately narrower:
- `review_config.repo_enabled(get, ...)` owns the security-sensitive opt-in
decision. It receives a transport function, so malformed configuration and
failure behavior are deterministic in tests.
- `entrypoints/gitea.request()` and `GiteaClient` own HTTP authentication, JSON
request encoding, timeout, and Gitea URL construction.
- `model_client.complete()` owns the legacy Anthropic-compatible request shape.
`opencode` is the preferred agent adapter and keeps Gitea I/O out of the
autonomous process. Its sibling modules provide internal seams for workspace
preparation, lens policy, and synthesis without expanding the caller-facing
interface.
- `review/analysis`, `review/output`, `review/configuration`, and
`review/adapters` keep prompt construction, finding parsing, config filtering,
rendering, and publishing in focused modules.
pure transformations. Their callers do not need to know how model or Gitea
transport works.
- `langfuse_trace` is an optional sink. It is fail-open and cannot change the
review result.
- `review/budget` owns deployment and repository resource limits. The runner
streams model events and terminates the subprocess after a completed step
crosses a step, token, duration, or equivalent-cost limit. Cap status is
retained in review output and Langfuse metadata.
## Trust model
The review config is read from the PR base branch, never the PR head. The agent
checkout is treated as hostile: instruction files are removed, credentials are
not inherited, and the agent only returns text to the Python publisher. Python
validates finding paths and post-change line anchors before sending comments.
## Observability
Langfuse is the operational analytics surface. A trace groups runs by
`owner/repo#PR`; generations carry usage and cost basis; evaluation scores and
human-feedback scores are attached later. The former SQLite-backed dashboard
was removed. SQLite remains only as the feedback/evaluation ingestion store.
## Removed surface
The dashboard server, dashboard data module, dashboard tests, dashboard README,
and dashboard Kubernetes manifest are intentionally gone. Operators use the
Langfuse UI for review trends and cost analysis, and Gitea for review details
and configuration changes.
Historical design/implementation plans under `docs/plans/` describe the
earlier TypeScript framework proposal and are not the runtime architecture.