Skip to main content

AgentGuard

AgentGuard is a static analysis CLI for AI agent codebases. It finds reliability, cost, and security bugs in agent graphs, tool calls, retries, and LLM calls before an agent runs.

The project ships the normalized Agent IR, generic/LangGraph/CrewAI/AutoGen adapters, the plugin system, 15 documented reliability/cost/security rules, SARIF and autofix support, and the Phase 5 graph, OWASP, triage, and trace plugins.

Development setup

AgentGuard requires Python 3.10+ and uses uv for environments and dependencies. CI targets Python 3.10, 3.11, 3.12, and 3.13. The bootstrap uses uv 0.13.0 and GNU Make.

If you just installed uv and the shell cannot find it, open a new terminal or add its default install directory to your current shell's path:

export PATH="$HOME/.local/bin:$PATH"

WSL users should keep the virtual environment outside a Windows-mounted project directory and use copy mode for dependency links:

export UV_LINK_MODE=copy
export UV_PROJECT_ENVIRONMENT="$HOME/.venvs/agentguard"
uv sync --locked --all-extras

Install the locked environment and run the complete local check suite with:

uv sync --locked --all-extras
make check

make install also installs the locked dependencies, using the same environment as the check targets. The Makefile exports both WSL settings; export them in your shell as above when running uv directly. All check targets include the development dependencies automatically.

Keep uv.lock in version control. For intentional dependency updates, run uv lock --upgrade, review the lockfile changes, and run make check.

Quick start

Check the installed version:

uv run --locked agentguard --version
uv run --locked python -m agentguard --version

Scan the bundled examples without failing the shell command on findings:

uv run --locked agentguard scan examples/ --fail-on never

The support bot and plain Python agent intentionally contain findings. The clean agent should produce no findings:

uv run --locked agentguard scan examples/clean_agent --format json --fail-on never

List the built-in rules or read a rule's remediation guidance:

uv run --locked agentguard rules
uv run --locked agentguard explain AG003
uv run --locked agentguard plugins list
uv run --locked agentguard baseline create examples/ --output baseline.json
uv run --locked agentguard graph examples/langgraph_support_bot
uv run --locked agentguard trace path/to/local-trace.json

Useful scan options include:

agentguard scan [PATHS...] --format text|json
    --select AG001,AG00* --ignore AG003
    --min-severity info|warning|error
    --min-confidence low|medium|high
    --fail-on error|warning|never
    --jobs N --output FILE --no-cache

Phase 5 commands:

agentguard graph PATH [--output FILE]                 # Mermaid normalized IR
agentguard trace TRACE.json [--output FILE]           # loops and cost spikes
agentguard triage --input FINDINGS.json               # explicit provider needed
    --source-root PROJECT --provider module:factory
    [--cache FILE]

agentguard triage can send redacted source snippets to arbitrary provider code, so use it only with a provider you trust. It never runs during scan and does not change finding severity.

The scanner parses source without importing or executing it. A syntax error is reported as a warning and the remaining files continue to scan. Findings are deterministically sorted and can be suppressed inline:

requests.get(url)  # agentguard: ignore[AG003] reason: gateway adds timeout

See the architecture guide and the individual pages in docs/rules/ for the IR pipeline and rule-specific guidance. See the CI guide for GitHub and pre-commit integration, and the autofix guide for safe dry-run and apply behavior. See the distribution guide for bundled and standalone installation profiles. Do not install both profiles into the same environment.

Phase 6 platform development

The hosted platform is split from the offline analyzer. The server package is packages/agentguard-server and uses FastAPI, SQLAlchemy 2, psycopg 3, and Alembic. The core CLI does not import the server or require PostgreSQL.

Start everything with Docker Compose

Docker Compose is the recommended local platform setup. It starts PostgreSQL, applies the Alembic migrations, and starts the FastAPI service. The database is stored in the named agentguard-postgres volume and the API is exposed on port 8000. PostgreSQL is exposed on port 5432 so local integration tests can use the same database.

cp .env.example .env
docker compose up --build

Verify the services from a second terminal:

curl -fsS http://localhost:8000/healthz
curl -fsS http://localhost:8000/readyz
curl -fsS http://localhost:8000/openapi.json > /tmp/agentguard-openapi.json

Expected health output is:

{"status":"ok","service":"agentguard-server"}

Open the interactive API contract at http://localhost:8000/docs. Stop the services without deleting the database with:

docker compose down

Use docker compose down -v only when intentionally resetting the local database. The web dashboard is a separate process and is started below.

Run the dashboard

The Next.js dashboard lives under web/ and reads the backend URL from AGENTGUARD_API_URL:

cd web
npm ci
AGENTGUARD_API_URL=http://localhost:8000 npm run dev

Open http://localhost:3000. The dashboard has repository, scan, and finding views plus explicit loading, empty, API-unavailable, forbidden, and error states. Its API client forwards only the incoming Authorization and Cookie headers; authorization remains a backend responsibility.

Run dashboard checks from web/:

npm test       # strict TypeScript check
npm run build  # production Next.js build
npm start      # serve the production build

Run the API with an existing PostgreSQL instance

Docker is not required if you already have PostgreSQL. Set the connection URL in the shell, apply migrations, and start Uvicorn:

export AGENTGUARD_DATABASE_URL='postgresql+psycopg://USER:PASSWORD@HOST:5432/DB'
export AGENTGUARD_CORS_ORIGINS='http://localhost:3000'

uv run --locked --all-extras --package agentguard-server alembic \
  -c packages/agentguard-server/alembic.ini upgrade head

uv run --locked --all-extras --package agentguard-server uvicorn \
  agentguard_server.main:app --host 127.0.0.1 --port 8000

Never put a real password, token, private key, or webhook secret in the repository. Use environment variables, a local secret manager, or Docker secrets. .env.example contains placeholders only.

Submit and query a scan

The JSON ingestion endpoint is idempotent by scan_key. Repeating the same request returns the existing scan rather than inserting duplicate findings.

curl -X POST http://localhost:8000/api/v1/scans \
  -H 'Content-Type: application/json' \
  -d '{
    "scan_key": "local-scan-1",
    "repository": {"provider": "github", "full_name": "acme/demo"},
    "branch": "main",
    "commit": {"sha": "abc123"},
    "analyzer_version": "0.1.0",
    "findings": []
  }'

Useful read endpoints are:

GET /api/v1/repositories?page=1&page_size=50
GET /api/v1/repositories/{repository_id}
GET /api/v1/repositories/{repository_id}/scans?page=1&page_size=20
GET /api/v1/scans/{scan_id}
GET /api/v1/scans?page=1&page_size=50

SARIF uploads use the same persistence and idempotency path. The repository, branch, commit, analyzer version, and scan key are explicit query parameters:

curl -X POST \
  'http://localhost:8000/api/v1/scans/sarif?scan_key=ci-123&repository=acme%2Fdemo&branch=main&commit_sha=abc123&analyzer_version=0.1.0' \
  -H 'Content-Type: application/json' \
  --data-binary @results.sarif

The server validates repository identifiers, relative source paths, finding severity/confidence, source ranges, field lengths, duplicate fingerprints, and the declared request size before persisting data.

Configure development authentication

Authentication is optional for local development. To require bearer tokens:

export AGENTGUARD_AUTH_REQUIRED=true
export AGENTGUARD_API_TOKENS='ci-token=ci;read|write;acme/demo'

The token format is:

token=subject;scope1|scope2;repository1|repository2

Then call protected endpoints with:

curl http://localhost:8000/api/v1/repositories \
  -H 'Authorization: Bearer ci-token'

read and write scopes are enforced, and repository scopes provide tenant isolation. Cross-repository access returns a generic 404 rather than revealing whether another repository exists. The service adds an X-Request-ID response header, limits declared request size, rate-limits clients, and stores redacted audit details. The default rate limiter and audit fallback are process-local development implementations; production replicas need shared operational services.

GitHub webhooks and badges

Configure a webhook secret before enabling the GitHub endpoint:

export AGENTGUARD_GITHUB_WEBHOOK_SECRET='replace-with-a-secret'

POST /api/v1/github/webhook accepts signed GitHub pull_request events for opened, synchronize, and reopened. It verifies X-Hub-Signature-256, claims delivery IDs to reject replays, and creates one queued scan tied to the pull-request head commit. A background worker that executes queued scans and publishes Check Runs is not included in this foundation.

Badges require both AGENTGUARD_PUBLIC_BADGES=true and the repository's badge_public flag. They expose only aggregate risk state and severity counts:

GET /api/v1/badges/{repository_id}.svg
GET /api/v1/badges/{repository_id}.json

Private repositories return 404, and public responses use deterministic ETags and cache headers without source snippets or finding messages.

Run tests and migrations

Install all locked Python workspace dependencies:

uv sync --locked --all-extras --all-packages

Run the complete Python check suite:

make check

make check runs Ruff lint/format checks, strict mypy, the root tests, and the server tests. PostgreSQL-specific tests run when AGENTGUARD_TEST_DATABASE_URL is set; otherwise only those integration tests are skipped:

export AGENTGUARD_TEST_DATABASE_URL='postgresql+psycopg://agentguard:agentguard@localhost:5432/agentguard'
make server-test

Apply or inspect migrations directly:

AGENTGUARD_DATABASE_URL='postgresql+psycopg://USER:PASSWORD@HOST:5432/DB' \
  uv run --locked --all-extras --package agentguard-server alembic \
  -c packages/agentguard-server/alembic.ini upgrade head

uv run --locked --all-extras --package agentguard-server alembic \
  -c packages/agentguard-server/alembic.ini current

The current migration head is 0004_audit_records.

Package and release checks

Build the root CLI and standalone server distributions outside the repository:

uv build --out-dir /tmp/omnirush/agentguard-build-root
uv build --directory packages/agentguard-server \
  --out-dir /tmp/omnirush/agentguard-build-server

The supported Python CI matrix is 3.10, 3.11, 3.12, and 3.13. GitHub Actions also runs the PostgreSQL-backed server suite and the dashboard TypeScript and production-build checks. See docs/server.md for the full server contract, docs/distribution.md for package profiles, and web/README.md for the dashboard contract.

License

AgentGuard is released under the MIT license. See LICENSE.

Metadata

Release files for agentguard-linter 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentguard-linter 0.1.0
File Size Uploaded
agentguard_linter-0.1.0.tar.gz 385.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agentguard-linter 0.1.0
File Interpreter ABI Platform
agentguard_linter-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 482.7 kB

Release files / agentguard_linter-0.1.0.tar.gz

Download URL agentguard_linter-0.1.0.tar.gz
Size 385.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5ae1602b827ef2066ed8c9bff76a67224bfe785e429375eb47be762ddff765d8
BLAKE2b-256 checksum
How to use checksums
f1b2100df8150114ef85a847df2022497fa8184295f345bb40ff1c41d9cde671
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / agentguard_linter-0.1.0-py3-none-any.whl

Download URL agentguard_linter-0.1.0-py3-none-any.whl
Size 97.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
001af75b1113dde6e891a85dba946ea878dbdedb8e2c01b65ad3396ec3492691
BLAKE2b-256 checksum
How to use checksums
ed4fccd3c89b8892493a8163b262f180e2c25d3d5e0ea14519129a327af554ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page