Agentic Security Fleet Ops — an LLM-agent security department with a Security Orchestrator, built on pydantic-ai with a GitHub Copilot SDK provider.
Project description
asfops — Agentic Security Fleet Ops
An entire security department as a fleet of LLM agents. Give asfops any security-relevant input — a code change, a design doc, an incident description, a compliance question — and the Security Orchestrator decides which security specialists should weigh in, runs them in parallel, and composes their findings into a single comprehensive markdown report.
Built on pydantic-ai, with the GitHub Copilot SDK exposed as a first-class pydantic-ai provider (CopilotModel) — so the fleet runs on your GitHub Copilot subscription by default, or on any pydantic-ai model (OpenAI, Anthropic, …) you choose.
Install
pip install asfops
# or
uv add asfops
Quickstart
import asfops
result = asfops.assess_sync(
"Review this design: a public REST API that accepts file uploads "
"to S3 using presigned URLs, authenticated with long-lived API keys."
)
print(result.report_md) # the composed security report
print(result.triage.selected) # which specialists were engaged, and why
print(result.metadata) # per-agent model + token usage, per-model totals
Async, with configuration:
from asfops import Fleet, FleetConfig
fleet = Fleet(FleetConfig(
default_model="copilot:claude-sonnet-4.5", # any pydantic-ai model ref works too
model_overrides={"threat-model": "anthropic:claude-sonnet-4-5"},
fallback_models=("anthropic:claude-sonnet-4-5",), # retry here if the primary errors
force_roles=("grc",),
max_concurrency=5,
temperature=0.1, # steadier, more deterministic analysis
max_tokens=4000, # cap output length per agent
per_agent_token_limit=200_000, # hard budget guard; over-budget agents fail gracefully
))
result = await fleet.assess("...")
CLI
asfops assess "We're adding a webhook receiver that executes user-supplied templates"
asfops roster # meet the department
asfops run threat-model "..." # engage a single specialist
asfops models # check Copilot availability / list models
asfops dashboard # launch the Streamlit dashboard (needs the extra)
Dashboard
A Streamlit dashboard over your run history (~/.asfops/logs): browse past assessments, a findings explorer (filter by severity/role), per-run severity + token charts, the roster, and a form to launch a new assessment. Install the optional extra and launch it:
pip install "asfops[dashboard]"
asfops dashboard # opens http://localhost:8501
It reads the same structured logs the fleet already writes, so every assess run shows up automatically.
The fleet
17 specialists covering the modern security department: Product Security, Security Architecture, Threat Modeling, AppSec, Cloud Security, IAM, Pen Testing, Red Team, Bug Bounty, Vulnerability Management, Supply Chain Security, Threat Detection, SOC, Incident Response/DFIR, GRC & Compliance, Privacy, and CISO-level leadership framing. asfops roster shows each role's charter.
Authentication
By default the fleet runs on the GitHub Copilot runtime (bundled CLI, auto-downloaded). You need a GitHub Copilot subscription and one of:
- being logged in via
gh auth login/ Copilot CLI, or COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKENset.
No Copilot? Point the fleet at any pydantic-ai provider: FleetConfig(default_model="openai:gpt-5.2") or anthropic:claude-sonnet-4-5 with the corresponding API key.
Result metadata
Every FleetResult optionally includes (include_metadata=True, default):
- per-agent: role, resolved model id, input/output/cache token counts, duration
- totals per model, plus a grand total across the whole assessment
Logging
Two separate logs are written per run, under one timestamped directory in
~/.asfops/logs/ (created on first use; override the base with --log-dir or
the ASFOPS_HOME env var):
~/.asfops/logs/<UTC-timestamp>-<run_id>/
├── app.log # global application log (structlog JSON lines)
└── agents/
├── triage.json # each agent's ENTIRE context…
├── appsec.json # …full message history + model + usage + output
├── …
└── synthesis.json
app.log— application-wide lifecycle events (config, triage decision, per-agent start/finish/fail with token counts, synthesis, Copilot client start/stop, run totals), correlated by a fleet-levelrun_id.agents/<slug>.json— the complete context of one agent invocation (every specialist plus triage and synthesis): the full pydantic-ai message history (system prompt, user prompt, model response, retries) with a metadata header (model, token usage, duration, run_id, structured output).
Logging is on by default and configurable:
asfops assess "…" --log-dir ./logs --log-level DEBUG # custom location/verbosity
asfops assess "…" --no-logs # disable entirely
from pathlib import Path
from asfops import Fleet, FleetConfig, LoggingConfig
fleet = Fleet(FleetConfig(logging=LoggingConfig(base_dir=Path("./logs"), level="DEBUG")))
Logging auto-disables under pytest so test runs stay clean. asfops.get_logger(__name__) exposes the same structlog logger for your own code.
Development
uv sync --group dev
uv run pytest --cov=asfops
uv run ruff format --check . && uv run ruff check .
uv run mypy src tests
Releases are fully automated: every merge to main auto-bumps the patch version, tags it, builds, and publishes to PyPI via trusted publishing. The version comes from the git tag (hatch-vcs) — never hand-edited. See RELEASING.md.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asfops-0.2.4.tar.gz.
File metadata
- Download URL: asfops-0.2.4.tar.gz
- Upload date:
- Size: 182.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24708d1fb2fab6e8f4251793144727149849b78d657736ccea3772962c3af1e9
|
|
| MD5 |
922f4ce85382de8249af5c0649fe5ae4
|
|
| BLAKE2b-256 |
3c7d6a530a488c46d5683639fca67b0234351f7263d08bc8fe9dc64ccfede76c
|
Provenance
The following attestation bundles were made for asfops-0.2.4.tar.gz:
Publisher:
release.yml on brettbergin/agentic-security-fleet-ops
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asfops-0.2.4.tar.gz -
Subject digest:
24708d1fb2fab6e8f4251793144727149849b78d657736ccea3772962c3af1e9 - Sigstore transparency entry: 2083272496
- Sigstore integration time:
-
Permalink:
brettbergin/agentic-security-fleet-ops@f6c0b252a0db2b3da5af75b82cfc821d4f3bf6cf -
Branch / Tag:
refs/heads/main - Owner: https://github.com/brettbergin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c0b252a0db2b3da5af75b82cfc821d4f3bf6cf -
Trigger Event:
push
-
Statement type:
File details
Details for the file asfops-0.2.4-py3-none-any.whl.
File metadata
- Download URL: asfops-0.2.4-py3-none-any.whl
- Upload date:
- Size: 50.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
811c310e2308fbb70b826f4bdd6a1d035fd005567fcaba21f67d1c0cfedc7ea2
|
|
| MD5 |
3ff38e8473d0de38257d5b17a233f80d
|
|
| BLAKE2b-256 |
ec25535300cc9e38db23b000af865f3deb8791ec0794532a6e54d678e7a7f3a3
|
Provenance
The following attestation bundles were made for asfops-0.2.4-py3-none-any.whl:
Publisher:
release.yml on brettbergin/agentic-security-fleet-ops
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
asfops-0.2.4-py3-none-any.whl -
Subject digest:
811c310e2308fbb70b826f4bdd6a1d035fd005567fcaba21f67d1c0cfedc7ea2 - Sigstore transparency entry: 2083272518
- Sigstore integration time:
-
Permalink:
brettbergin/agentic-security-fleet-ops@f6c0b252a0db2b3da5af75b82cfc821d4f3bf6cf -
Branch / Tag:
refs/heads/main - Owner: https://github.com/brettbergin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c0b252a0db2b3da5af75b82cfc821d4f3bf6cf -
Trigger Event:
push
-
Statement type: