Score a repo’s enterprise readiness, open quality-filtered GitOps PRs, and let humans merge so Argo CD deploys.
Built for OpenShift + Argo GitOps platform engineers who want Assess → Scan → Deliver PR → merge → Argo → reassess — without silent cluster mutations or catalog dump PRs.
Fleet — portfolio scores, GitOps sync state, open PRs, Scan.
- Demo
- Who it’s for
- How it works
- Portal highlights
- Quick start
- Honest scope (Phase A)
- Works on plain Kubernetes?
- Deploy to OpenShift
- Architecture
- Docs
- License
CLI happy path (no cluster, no LLM) — score the checked-in sample app:
uv sync --extra dev
uv run agentit assess ./examples/sample-app --no-llm --format terminalStatic frame (SVG): docs/assets/readme/cli-assess.svg · Sample write-up: examples/sample-assessment.md
Portal dogfood (internal OpenShift Route; OpenShift SSO — not a public sandbox):
https://agentit-agentit.apps.aws-jb-acsacm-1.dev05.red-chesterfield.com
Screenshots below were taken against that environment at tip 9604e9dc (Health → Deployed commit). To refresh media later: oc port-forward -n agentit pod/<portal-pod> 18080:8080 and capture /fleet, /ledger, /schedules, /decisions, /health (app port bypasses oauth-proxy).
| You… | AgentIT helps you… |
|---|---|
| Run OpenShift + Argo CD for many apps | See fleet scores, sync state, and open remediation PRs in one place |
| Own platform standards (security, probes, GitOps, SLOs) | Assess repos with seven dimensions + detect skills |
| Want automation without surprise applies | Get finding-tied PRs; you merge; Argo syncs |
- Assess — clone a repo, run analyzers +
mode: detectskills → scores and findings - Scan — SkillEngine matches findings → remediations (SSA dry-run + clear-evidence gate)
- Deliver PR — open GitOps / source PRs that are finding-tied (Phase A
finding_gate) - Human merge — never auto-merge (ADR 0001)
- Argo operate — ApplicationSet / Application syncs after merge
- Reassess — cadence + watchers (drift, vulns, SLOs) feed the next loop
flowchart LR
A["Repo"] --> B["Assess"]
B --> C["Scan / generate"]
C --> D["Gate"]
D --> E["Open PRs"]
E --> F["Human merge"]
F --> G["Argo sync"]
G --> H["Reassess / learn"]
| Step | What happens |
|---|---|
| Assess | 7 dimensions → findings + scores |
| Scan / generate | Skills match findings; Scan/onboard produces remediations |
| Gate | Finding-tied PRs only on auto delivery and manual /deliver. Manual also mirrors auto’s file filter, wrong-layer strip, per-cluster file cap, and clear-evidence (blocks Hello-World #31/#32-class catalog dumps; refuses octocat/Hello-World probes; refuses theater audit stubs even when middleware is wired — pinky #12). SSA dry-run + clear-evidence also refuse destructive Containerfile rewrites / root-only audit.py. dockerfile_pin is path-bound (pinning one Dockerfile cannot clear :latest on others — pulse-agent#2); USER/HEALTHCHECK/UBI clear via additive harden on that path. SBOM clears via CI generation (sbom-ci), not static files. Validate/fix/retry runs per finding-cluster, after partitioning — one cluster's unfixable failure (e.g. no live scale target for autoscaling) can never discard an unrelated, individually-valid cluster's files (pulse-agent #gitops); every per-cluster refusal is a real, visible event, not just a log line. |
| Operate | Human merges on GitHub; Argo CD deploys. Awaiting verification only when a PR was actually opened |
| Learn | Watchers surface drift/CVEs/SLOs; Decisions audit LLM approve/reject; repeated theater cools down. Security-analyzer fixtures use short EXAMPLE… placeholders + # notsecret; historical hex allowlisted via root .gitleaks.toml top-level [allowlist].regexes (InfoSec / PwnedAlert Generic Secret FP; never real credentials). |
Fleet apps land under apps/{app}/ in the gitops repo (ApplicationSet). AgentIT itself deploys from this repo’s Helm chart/ via Application agentit.
Real dogfood UI (not mockups):
| Surface | What you see |
|---|---|
| Fleet | Portfolio scoreboard — scores, deploy/GitOps badges, open PRs, Scan |
| Assessment | Dimension scores, Assessed → Onboarded → Merged → Monitored |
| Ledger | PRs waiting for your approval — Merge / Close (HITL) |
| Fleet SLOs | Availability / error-rate / latency across apps |
| Schedules | Re-assess cadence + platform CronJobs + onboarding manifests |
| Decisions | LLM decide-point audit (approve / reject / gate) |
| Health | Tekton pipeline, Argo Synced/Healthy, deployed tip SHA |
Assessment Detail — score, dimension bars, lifecycle stepper.
Ledger — quality-gated PR with Merge PR (human-in-the-loop).
More screenshots — Fleet SLOs, Schedules, Decisions, Health
Fleet SLOs — breached vs met across the portfolio.
Schedules — reassess cadence + live platform CronJobs.
Decisions — LLM approve/reject/gate audit trail.
Health — CI PipelineRun, Argo Synced/Healthy, tip 9604e9dc.
Primary spine: Fleet → Assessment Detail → Ledger. Operate surfaces (menu): Health, Insights, Events, Decisions, DLQ, Schedules. See docs/portal-experience-design-language.md and ADR 0007.
Requires Python ≥ 3.12 and uv.
git clone https://github.com/alimobrem/AgentIT.git
cd AgentIT
uv sync --extra dev
# 1) Score a repo (no cluster)
uv run agentit assess https://github.com/some-org/some-app --format terminal
# 2) Assess + generate hardening manifests locally
uv run agentit onboard https://github.com/some-org/some-app --output-dir ./out
# 3) Local portal (needs Postgres: AGENTIT_DB_DSN)
uv run agentit portal --port 8080
# open http://localhost:8080Useful commands: self-assess, watch, learn, test-skill, activate-skill, clear-skill-cooldown. Full list: uv run agentit --help.
Scoring details: docs/score-methodology.md. Shareable badge: GET /badge/{app}.svg.
Environment variables
| Variable | Purpose |
|---|---|
AGENTIT_DB_DSN |
Postgres DSN (required for portal / fleet / watchers) |
AGENTIT_TEST_PG_DSN |
Throwaway Postgres for pytest / capability-scout tests-pass (never the fleet DB — fixtures truncate). Chart sidecar default; CI sets its own. |
ANTHROPIC_API_KEY or Vertex (ANTHROPIC_VERTEX_PROJECT_ID + CLOUD_ML_REGION) |
Optional LLM |
GITHUB_TOKEN |
PR create / infra-repo / webhooks |
AGENTIT_KAFKA_BOOTSTRAP |
Kafka (optional; no-op if unset) |
AGENTIT_EXTERNAL_URL |
Public base URL for outbound registrations |
AGENTIT_AGENT_MODE |
local (default) or kubernetes Jobs |
AGENTIT_OFFLINE |
1 — hard-stop kube client (tests/review) |
AgentIT is a GitOps assistant, not an auto-apply bot.
- No catalog dumps — auto delivery and manual
/deliveronly open finding-tied PRs (finding_gate) - Honest refuse UX — when Phase A refuses (“No open findings / score delta”), Onboard Results does not promise “will open N PRs” or offer Retry Scan delivery; green Assessment Detail Scan CTAs / empty Open PRs copy do not promise PRs either
- Capability-gated cluster packs — Scan probes cluster GVKs (Tekton Task/Pipeline, Kyverno Policy, PDB, HPA, ResourceQuota, …). Missing CRD / Not Found and Forbidden (RBAC) skip those files — they do not count as auto-validation converge failure. Source-layer remediations (Containerfile pin, CI SBOM workflow, app audit, …) are never blocked because cluster dry-run failed. Onboard Results shows skip/refuse reasons instead of “will open N PRs” when nothing opened (pulse-agent class / #192 extended)
- No half-onboarded Fleet apps — every app is GitOps-registered (or self-managed) or removed. Not-registered rows show Register GitOps / Delete only — never a Scan-for-PR CTA. Demo forks you cannot deliver to (e.g.
octocat/Spoon-Knife) belong off Fleet, not in “Not GitOps-registered” limbo (dogfood:octocat/Spoon-Kniferemoved — undeliverable; Fleet is pinky + AgentIT only) - Bring your own GitOps repo — Assess / Register-for-GitOps accept an optional GitOps Infra Repo URL. Supplied and already accessible → used as-is. Supplied but missing → created empty (org-aware:
/orgs/{owner}/reposfor an org,/user/reposonly when the owner is the authenticated token's own account — never silently redirected elsewhere) in the exact org/owner the URL specifies, then GitOps-registered the same way. Supplied but AgentIT lacks push access → hard refusal, never a silently substituted repo. Blank → unchanged existing default (shared{token-account}/agentit-gitops). Either way, the fleet-wideagentit-managed-appsApplicationSet gets an additional Git generator entry for the new repo — it never replaces another app's already-registered repo (github_pr.ensure_applicationset()) - Fleet deploy badges for ApplicationSet apps — enrichment looks up
managed-{app}first (then literal name), same asgitops_registered, so Synced/Healthy apps like pinky /managed-pinkyshow synced — not a false “not deployed” - Human merge required — AgentIT opens PRs; it does not merge them
- No silent cluster applies for app remediations — path is PR → merge → Argo
- Clear-evidence gate — refuses theater stubs, root-only
audit.pywithout package wire-up, destructive Containerfile rewrites, SLSA/hermetic prose without a realcosign signTask (image_signing→cosign-sign-task), staticsbom.cdx.json/ bare Tektonsbom-taskfor compliancesbom(clears only via CI generation:sbom→sbom-ci/anchore/sbom-actionor Pipelinesbom-generate), Kyverno-only health policies without probes in repo YAML (health→workload-health-probes), PDB as a fake clear for single-replica (replicas→workload-replicas), otel-collector as a fake clear for app tracing (detect-only), shallow migrations (SELECT 1/ emptyupgrade()/ comment-onlyop.execute), empty or:latestimage-scan Tasks, Grafana ConfigMaps withoutgrafana_dashboard+ panels, PDB/ServiceMonitor selectors that match no live Services/workloads, and empty Argo CD Applications / bogusdeploy/paths when the tree is missing. Intent matrix:docs/checks-remediations-intent-audit.md - Awaiting verification only when a delivery actually produced a
pr_url - Async GitHub push webhooks —
/api/webhook/github-pushreturns 202 immediately and assesses in the background (GitHub’s ~10s timeout). Webhook claims stay incomplete until success; hard failure / busy exhaustion / TTL (~15m) releases the claim so retries work. Portal assess concurrency + 1Gi memory from #189 unchanged - Webhook → gated auto delivery — remediable findings from push re-assessment (and
/api/webhook/finding) enter the sameauto_validate_and_deliverpath as Scan/onboard (finding_gate+ clear-evidence + caps). Human gate remains PR merge — never auto-apply / catalog dumps - Coverage: "Also included" companions — generated content that doesn't map to the open finding's exact clearing skill no longer gets silently thrown away when it's otherwise safe to ship (same delivery layer, not narrative/secret-blocked, not on that finding's
refuse_companionsdenylist). Rides along in the same PR under a distinct "Also included" section — never claimed to clear anything itself; a companion with no room in any same-layer PR is dropped, never spun into its own always-refused PR attempt - Real image digest pinning —
containerfindings pin to the base image's actual current digest (target registry's own v2 Manifest API), not just a slightly-less-floating:1major-stream tag, when the registry is reachable; falls back to:1per-image otherwise, never blocks delivery - Deterministic fields, generalized — Tekton
Pipeline/PipelineRunrepo-url/image-refparams are force-set to the real values after generation, same as ArgoApplicationrepoURL— an LLM is never trusted with a value this codebase already knows for certain - CodeChangeAgent no longer touches
dockerfile/container/secrets— the legacy onboarding agent's deterministic and LLM paths did a blindaction: "create"full-file overwrite with no knowledge of the existing file, bypassing every guardrail the skill-enginecontainerfilepath has. Confirmed live onPulseSRE/pulse-agent#2(deletedRUN pip install+CMD) andPulseSRE/pulse-ui#39(swapped nginx→nodejs base image family, left:latestunpinned, deletedENTRYPOINT, fabricated a generic.env.exampleover a real one).dockerfile/containerfindings are now exclusively owned by the skill engine's pin/harden path;secretsis contractually detect-only (SOLUTION_CONTRACTS) and no longer auto-PR'd at all.is_destructive_dockerfile_rewrite()also gained CMD/ENTRYPOINT/EXPOSE token tracking and a base-image-family-swap guard as defense in depth CodeChangeAgentremoved entirely (no Python onboarding agent remains) — after the fix above, its remaining categories (health,gitignore,logging/structured,otel/tracing/instrumentation) were audited and found to either duplicate an already-guarded skill (health—workload-health-probesclears the finding via K8s probes without an unwired app-code stub) or violate their own detect-only contract (logging/tracing/instrumentation—SOLUTION_CONTRACTSauto_pr=False, "human wires/instruments";gitignorewas unreachable dead code, no analyzer emits that category). Deletedagents/codechange.py+ itsagents/codechange.mdregistration;AGENT_CLASSESis now always empty. Skills own every remediation domain- Migration scaffolding requires a real database —
db-migration-tooling(and themigrationfinding itself) used to fire for any repo lacking formal migration tooling, regardless of whether the app has a database at all. Confirmed live:PulseSRE/pulse-ui#40invented aschema_migrations_baselinetable for a database-less React UI repo.analyzers/data_governance.py::has_database_dependency()(reusingstack_detector.DB_PATTERNS) now gates the finding; the generator independently refuses whenreport.stack.databasesis empty - Treat outputs as drafts until you validate against your sources of record (cluster, GitHub, Argo)
Quality rules: docs/plan-quality-helpful-prs.md. Product contract: docs/release-notes.md.
| Capability | OpenShift (supported) | Plain Kubernetes |
|---|---|---|
agentit assess / local CLI |
Yes | Yes — no cluster needed |
| Portal + Postgres store | Yes (bundled chart) | Possible with your own Postgres; chart targets OpenShift |
Browser auth (auth.enabled) |
OpenShift oauth-proxy + Route | Not the same path — bring your own ingress/IdP |
| GitOps deploy | Argo CD Application / ApplicationSet | Argo CD works; chart assumes OpenShift-friendly defaults |
Self-deploy (Rollouts, Tekton agentit-ci, ImageStreams) |
Hard-requires OpenShift Pipelines / Rollouts as charted | Degrades — use your own CI promote path |
| Watchers (drift, vuln, SLO, self-health) | Designed for this stack | Partial — kube client works; OpenShift-only APIs/CRDs skip or warn |
Bottom line: scoring and local generation are cluster-agnostic. Full operate loop (portal, Scan → PR → Argo, watchers) is built and tested for OpenShift.
Helm chart in chart/ + Argo CD Application in argocd/application.yaml. Argo is the deployer: merge to main alone does not move the portal — Tekton agentit-ci builds, smokes, then pins image.tag. Confirm rollout via Health → deploy-status (or AGENTIT_IMAGE_TAG on the portal pod) matching the tip SHA — green GitHub Actions alone is not a deploy.
Ops: docs/deployment.md. Merge gate + post-merge tip: docs/ci-deploy.md (scripts/ci-merge-gate.sh — never merge on queued checks). Topology: docs/architecture.md.
Portal memory defaults to 1Gi with in-process assess concurrency 1 (chart/values.yaml resources + assessConcurrency) so concurrent GitHub push webhooks cannot stack clone+assess working sets and OOMKill the pod (busy callers get HTTP 503 and can retry).
Tip promote under node pressure: Tekton run-tests / build-image / self-assess CPU requests stay modest (100m) so pods schedule instead of Pending ExceededNodeResources; burst via limits. Drift-detector memory defaults to 512Mi–1Gi (agents.driftDetector.resources).
flowchart TB
subgraph Operator["Platform engineer"]
Portal["Portal / CLI"]
end
subgraph AgentIT["AgentIT"]
Assess["Assess"]
Scan["Scan + gate"]
PRs["Open PRs"]
end
subgraph Git["GitHub"]
Code["App / source repo"]
Gitops["GitOps repo apps/{app}/"]
end
subgraph Cluster["OpenShift"]
Argo["Argo CD"]
Apps["Fleet apps"]
end
Portal --> Assess --> Scan --> PRs
PRs --> Code
PRs --> Gitops
Code -->|"human merge"| Argo
Gitops -->|"human merge"| Argo
Argo --> Apps
Apps -.->|"reassess / watchers"| Portal
Full diagrams: docs/architecture.md · Self-managed vs fleet: docs/architecture-agentit-vs-fleet-gitops.md.
| Doc | Role |
|---|---|
docs/score-methodology.md |
Score dimensions, weights, PR impact |
docs/architecture.md |
System diagrams, Scan pipeline |
docs/ci-deploy.md |
Merge gate + post-merge Tekton/rollout tip |
docs/plan-quality-helpful-prs.md |
Quality PR rules (finding-tied, no theater) |
docs/checks-remediations-intent-audit.md |
Intent vs detect vs skill audit (verify before/after) |
docs/adr/ |
Architecture Decision Records (HITL, Postgres, …) |
docs/release-notes.md |
Product contract (Scan HITL, portal IA) |
docs/portal-experience-design-language.md |
Portal EDL |
docs/deployment.md |
OpenShift / Argo / Tekton ops |
CHANGELOG.md |
Version history |
docs/README.md |
Docs index |
docs/history/ |
Session notes (not product truth) |
Issues and PRs welcome on GitHub. Prefer small, focused changes; run uv run pytest before opening a PR. Maintainers use docs/ci-deploy.md before merging to main.








