APO (from Greek apothiki — "storehouse") is an Engineering Evidence Platform.
This repository ships the first analyzer: Repository Hygiene.
apo scans a local Git repository (or a remote Git URI) and collects objective engineering hygiene evidence — documentation, local development controls, testing gates, security/supply-chain signals, delivery automation, and collaboration practices.
Rules emit evidence only. A separate policy layer turns those observations into category and overall scores. APO does not grade “code quality” or run your tests; it reports whether engineering controls are observable in the repository.
cargo install apocargo install --git https://github.com/thanos/apo
# or from a checkout:
cargo install --path .Prebuilt binaries for Linux, macOS, and Windows are attached to GitHub Releases on each v* tag (with SHA256SUMS).
# Local checkout
apo analyze .
apo analyze . --format json
apo analyze . --output report.md
apo analyze . --format both --output ./out
# Remote Git URI (shallow-cloned to a temp dir, then cleaned up)
apo analyze https://github.com/thanos/ex_arrow
apo analyze git@github.com:thanos/ex_arrow.git --format both
# LLM remediation prompt (paste into Cursor/ChatGPT/etc. to close gaps)
apo analyze . --llm-prompt
apo prompt .
apo prompt https://github.com/thanos/ex_arrow --output ./outDefault artifacts:
- Local targets: written next to the analyzed repository
- Remote URIs: written to the current working directory
Files:
{repo}-repository-hygiene.md{repo}-repository-hygiene.json(when--format jsonorboth){repo}-repository-hygiene-prompt.md(when--llm-promptorapo prompt)
{repo} is the repository directory name (local) or the remote repo basename (e.g. ex_arrow from https://github.com/thanos/ex_arrow).
apo prompt / --llm-prompt generates a paste-ready instructions file for an LLM coding agent. It includes:
- Repository identity and current weighted score
- Rubric priorities
- Controls already satisfied (do not redo)
- Enumerated gaps (
Missing/Partial/Unknown) with remediations and evidence - Constraints and a required changelog deliverable mapping files → APO rule ids
Example:
apo prompt . > /tmp/fix-hygiene.md # also writes {repo}-repository-hygiene-prompt.md
# then paste into your LLM agent against the repo checkoutRepository → Discovery → Hygiene Rules → Evidence → Policy/Scoring → Markdown + JSON
- Discovery — walk the tree (respecting
.gitignore), index files, detect ecosystem signals (Cargo.toml,package.json, CI workflows, etc.), and sample recent Git history. - Rules — each rule inspects paths, file contents, CI workflow text, and/or commit metadata and emits one finding.
- Policy — maps finding statuses to numeric weights, averages them per category, then applies the weighted rubric for the overall score.
- Report — writes Markdown and/or JSON with summary, scores, findings, gaps, and recommendations.
APO v0.1 runs 35 rules across 6 categories. Every finding includes:
| Field | Meaning |
|---|---|
rule |
Stable id, e.g. documentation.readme |
category |
One of the six hygiene categories |
status |
Observational outcome (see below) |
confidence |
High / Medium / Low how sure the observation is |
summary |
Short description of what was observed |
evidence |
Paths and/or detail strings backing the finding |
remediation |
Optional guidance when the control looks weak or missing |
| Status | Meaning | Policy weight |
|---|---|---|
Enforced |
Control present and appears actively applied (e.g. keywords in docs, CI steps) | 100 |
Present |
Control artifact exists | 80 |
Partial |
Weak or incomplete signal | 45 |
Unknown |
Cannot decide from a local clone alone (or insufficient Git history) | 25 |
Missing |
No evidence found | 0 |
NotApplicable |
Control does not apply (excluded from averages) | — |
Category score = average status weight of that category’s findings (excluding NotApplicable).
Overall score = weighted average of category scores using the v0.1 rubric below. If a category has no scorable findings, its weight is redistributed proportionally among the remaining categories.
| Category | Weight | Notes |
|---|---|---|
| Documentation & Onboarding | 20% | Foundation |
| Development Hygiene | 15% | Daily developer experience |
| Quality Assurance | 20% | Code health |
| Security & Supply Chain | 15% | Risk reduction |
| Automation & Delivery | 15% | Velocity + reliability |
| Project Management & Collaboration | 15% | Process maturity |
Gaps (Missing, Partial, Unknown) appear under Missing controls and feed Recommendations when a remediation string is set.
Both Markdown and JSON include:
| Section | Contents |
|---|---|
| Header / metadata | APO version, analyzer name (repository-hygiene), repository label, optional source_uri / checkout_path, timestamp |
| Executive summary | Overall score and counts of enforced / present / gap findings |
| Category scores | Per-category score plus counts of each status |
| Findings | All 35 rule results with evidence |
| Missing controls | Rule ids with gap status |
| Recommendations | Remediation text derived from gap findings |
| Evidence appendix (Markdown) | Compact table of rule → status → evidence paths |
| Rule id | What APO looks for |
|---|---|
documentation.readme |
README.md (or common variants). Enforced if content mentions quickstart/install/usage-style keywords. |
documentation.contributing |
CONTRIBUTING.md (root, .github/, or docs/). |
documentation.security |
SECURITY.md (root, .github/, or docs/). |
documentation.license |
LICENSE / LICENCE / COPYING (and common extensions). |
documentation.architecture |
ARCHITECTURE.md, DESIGN.md, or docs paths containing “architecture”. |
documentation.adrs |
ADR directories (docs/adr, adr, …) or ADR markdown files. |
documentation.runbooks |
Paths/dirs containing “runbook”. |
documentation.codeowners |
CODEOWNERS (root, .github/, docs/, .gitlab/). |
documentation.issue_templates |
.github/ISSUE_TEMPLATE/ or issue template files. |
documentation.pr_templates |
Pull request template files (e.g. .github/pull_request_template.md). |
| Rule id | What APO looks for |
|---|---|
local_development.gitignore |
.gitignore |
local_development.editorconfig |
.editorconfig |
local_development.formatter |
Formatter configs (rustfmt.toml, Prettier, Black/Ruff in pyproject.toml, .clang-format, etc.) or format-related package.json signals. |
local_development.linter |
Linter configs (Clippy, ESLint, Ruff, golangci-lint, Flake8, Pylint, …) or lint scripts in package.json. |
local_development.type_checker |
tsconfig.json / MyPy / Pyright, or a strongly typed toolchain (Cargo.toml, go.mod). |
local_development.pre_commit_hooks |
.pre-commit-config.yaml, Husky, Lefthook, or related package.json deps. |
local_development.dev_environment |
Dev containers, Docker/Compose, Makefile/Justfile, or setup scripts. Partial if only CONTRIBUTING exists without setup automation. |
| Rule id | What APO looks for |
|---|---|
testing.framework |
Test dirs (tests/, spec/, __tests__/, …), test file naming patterns, or framework config (package.json test runners, pytest, Cargo tests). |
testing.coverage_config |
Coverage configs (codecov.yml, .coveragerc, …), coverage tooling in manifests, or coverage mentions in CI. |
testing.coverage_enforcement |
CI/config signals that coverage is gated (thresholds, --fail-under, codecov targets). Partial if tooling exists but enforcement is unclear. |
testing.static_analysis_ci |
Linters/SAST invoked in CI (Clippy, ESLint, Ruff, CodeQL, Semgrep, Sonar, …). |
testing.type_checking_ci |
Typecheck/compile steps in CI (tsc, MyPy, cargo check/build, go build/vet, …). |
| Rule id | What APO looks for |
|---|---|
security.dependency_scanning |
Audit/deny configs or CI steps (cargo audit/deny, npm audit, Snyk, OSV, Trivy, CodeQL paths, …). |
security.secret_scanning |
Gitleaks / TruffleHog / detect-secrets configs or CI mentions; .secrets.baseline. |
security.policy |
Security policy document (SECURITY.md, etc.) — scored in the security category. |
security.dependency_updates |
Dependabot or Renovate configuration. |
| Rule id | What APO looks for |
|---|---|
delivery.ci_workflows |
CI configs: .github/workflows/*.yml, GitLab CI, CircleCI, Azure Pipelines, Jenkinsfile, Travis, Buildkite, … |
delivery.release_workflows |
Release/publish workflows (by name or body: release, publish, goreleaser, cargo/npm publish, …) or release-tooling configs. |
delivery.branch_protection |
Policy-as-code hints (e.g. .github/settings.yml). Unknown when nothing is checked in — platform branch protection cannot be verified from a local clone. |
delivery.required_status_checks |
CI presence plus optional settings-as-code for required checks. Unknown if workflows exist but platform enforcement cannot be verified locally. |
| Rule id | What APO looks for |
|---|---|
collaboration.commit_convention |
Commitlint / convention docs, and/or Conventional Commits patterns in sampled commit subjects (≥70% → Enforced, some adoption → Partial). |
collaboration.issue_linkage |
Issue refs in commit messages (#123, PROJ-1) and/or PR templates that ask for issue linkage. |
collaboration.codeowners |
Same CODEOWNERS paths as documentation, scored under collaboration. |
collaboration.review_configuration |
PR templates, CODEOWNERS, settings-as-code, or auto-assign/reviewer configs. |
collaboration.maintenance_activity |
Age of latest commit from Git history: ≤30 days Enforced, ≤90 Present, ≤180 Partial, older Missing. Unknown if the repo has no commits or Git metadata is unavailable. |
For collaboration rules, APO samples up to commit_sample_limit commits from HEAD (default 100; also used as shallow-clone --depth for remote URIs) and records:
- Days since last commit
- Share of subjects matching Conventional Commits
- Share of commits referencing an issue id
- A small sample of recent commit subjects (as evidence detail)
- One crate, one binary (
apo) - Rules produce evidence; policy computes scores
- Detect tools rather than hard-code a single ecosystem
- Local-clone limits: branch protection and required checks on the hosting platform are reported as
Unknownunless policy-as-code is checked in - No AI required for v0.1
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --all -- --check
cargo deny check
cargo run -- analyze . --format bothSee CONTRIBUTING.md for PR and release workflow details. See CHANGELOG.md for release notes.
MIT — see LICENSE.