Agentic Security Team for Resourceful Optimization
___ ___ ___ ___ ___
/\ \ /\ \ /\ \ /\ \ /\ \
/::\ \ /::\ \ \:\ \ /::\ \ /::\ \
/:/\:\ \ /:/\ \ \ \:\ \ /:/\:\ \ /:/\:\ \
/::\~\:\ \ _\:\~\ \ \ /::\ \ /::\~\:\ \ /:/ \:\ \
/:/\:\ \:\__\ /\ \:\ \ \__\ /:/\:\__\ /:/\:\ \:\__\ /:/__/ \:\__\
\/__\:\/:/ / \:\ \:\ \/__/ /:/ \/__/ \/_|::\/:/ / \:\ \ /:/ /
\::/ / \:\ \:\__\ /:/ / |:|::/ / \:\ /:/ /
/:/ / \:\/:/ / \/__/ |:|\/__/ \:\/:/ /
/:/ / \::/ / |:| | \::/ /
\/__/ \/__/ \|__| \/__/
______________________________________________________________________
ASTRO turns AI agents into an extension of the security engineer.
Most AI in security stops at analyzing output.
ASTRO goes further—agents use memory, documentation, and real tools to execute workflows the way engineers actually work.
ASTRO is an agentic execution layer for security workflows.
It enables agents to:
- Build context from prior findings (memory)
- Apply knowledge from documentation and past analysis
- Execute real tools via MCP/API abstractions
- Iterate like an engineer through investigation loops
This isn’t just AI summarizing results—
it’s AI doing security work.
Security work is a loop:
- Recall context (What have I seen before?)
- Research & reason (What does this mean?)
- Execute tools (Validate, explore, exploit)
ASTRO replicates this loop.
Most systems:
- Ingest scan results
- Summarize findings
- Generate reports
ASTRO:
- operates tools
- chains workflows
- maintains context across runs
Agents don’t just read output—they work the problem.
flowchart LR
subgraph client["Your machine"]
CLI["astro CLI"]
end
subgraph compose["Docker Compose"]
API["FastAPI :8000\n(ASTRO API)"]
DB["PostgreSQL\n+ pgvector"]
Tools["Tools service\n:7001"]
end
CLI -->|HTTP| API
API -->|SQL| DB
API -->|tool calls| Tools
Data flow: CLI talks to the API over HTTP. The API persists state in PostgreSQL (with pgvector) and runs agent tool calls against the tools service.
| Component | Role |
|---|---|
| api | Agent orchestration, workflow execution, LLM coordination, DB migrations |
| db | Persistent memory + vector context (pgvector) |
| tools | MCP/API-exposed tooling for agent execution |
| redis | Message broker/result backend for Celery |
| celery | Background worker that executes scheduled stack runs |
| celery-beat | Scheduler that dispatches due stack schedules |
| cli | Local interface to run workflows and interact with agents |
- Tools are exposed via MCP or API interfaces
- Agents can invoke them like functions
- Memory + documentation provide context
- Workflows emerge as execution loops, not scripts
ASTRO separates how tools are used from where they run
while keeping execution grounded in real environments.
The bundled tools/ service ships with the core stack. To publish and host your own tool namespaces outside that deployment, start from the astro-toolset-template repository.
The template follows the same layout as ASTRO’s tools/ package:
| Path | Description |
|---|---|
tools/api.py |
FastAPI app, JWT middleware, router registration |
tools/src/<namespace>/ |
One package per namespace (e.g. dns, web) |
tools/src/<namespace>/tools.py |
Tool definitions and registry |
tools/src/<namespace>/__init__.py |
APIRouter with GET /tools and POST /exec |
Each namespace is mounted at http://<host>:7001/<namespace> and exposes the same list/exec contract agents expect from the bundled tools service.
Authentication: External toolsets use Bearer JWT (HS256, signed with JWT_SECRET on the tool host). Register the toolset in ASTRO with auth required, auth type bearer, and the JWT as the credential token. ASTRO sends Authorization: Bearer <token> on tool calls. The bundled astro/tools service uses internal HMAC signing instead—do not mix the two models on the same host without understanding the difference.
Typical workflow:
- Copy
tools/src/example/to a new namespace in the template and define tools with the@tool(...)decorator. - Wire the router in
tools/api.py(protected prefix +include_router). - Run locally or via Docker Compose (default port 7001).
- Register the toolset URL in ASTRO (CLI or API), e.g.
http://your-host:7001/<namespace>.
For JWT issuance, namespace setup, and run instructions, see the template README.
From the repository root:
chmod +x deploy.sh
./deploy.shThis will:
- Create
.envfrom.env.exampleif missing, and generate secure values for any secrets that aren't set yet (SECRET_KEYandCREDENTIAL_ENCRYPTION_KEY). - Build and start the services:
- API (runs database migrations on startup)
- Tools service
- Database (PostgreSQL + pgvector)
- Redis, Celery worker, and Celery beat (scheduled runs)
- Install the CLI via pipx or local venv
deploy.sh generates these automatically, but you can set them yourself in .env:
SECRET_KEY— signs JWTs. Can be rotated freely.python3 -c 'import secrets; print(secrets.token_urlsafe(48))'CREDENTIAL_ENCRYPTION_KEY— encrypts stored credentials (a Fernet key). Rotating it invalidates existing credentials unless you re-encrypt first:python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())' # To rotate, from the api container: # python -m src.scripts.reencrypt_credentials --old-key <OLD_KEY>
- API → http://localhost:8000
- CLI →
astro initthenastro --help
./deploy.sh prints the command for obtaining the credentials for the default stack user. Run astro init to set the API URL, log in, create your permanent account, and set your password in one flow.
Copy:
cp .env.example .envUpdate values like:
DB_URLDEFAULT_TOOLS_BASE_URL
The schema is managed with Alembic (api/migrations/). The api container runs
alembic upgrade head on startup (see api/entrypoint.sh), so migrations are applied
automatically and Celery waits for the API to become healthy before starting.
To add a schema change:
# 1. Edit the SQLModel models in api/src/db/models.py
# 2. Generate a migration (from the api container)
docker compose exec api alembic revision --autogenerate -m "describe change"
# 3. Review the generated file in api/migrations/versions/, then commit itInstances deployed before this release built their schema directly from the SQLModel
metadata (no alembic_version table) and encrypted credentials with a key derived from
SECRET_KEY. Two things need attention when upgrading; do both before exposing the
new version to traffic, and back up the database first.
1. Schema. The baseline migration is a full-schema snapshot with existence guards, so
you do not need to alembic stamp anything. When the api container starts it runs
alembic upgrade head, which creates only the objects your database is missing (the new
stack_schedule* tables and the message uniqueness constraint) and leaves existing
tables untouched.
If the
messagetable already contains duplicate(stack_id, position)rows, theuq_message_stack_positionconstraint can't be created and the migration will fail. De-duplicate those rows first, then restart theapicontainer.
2. Credentials. Stored credentials were previously encrypted with a key derived from
SECRET_KEY; they must be re-encrypted with the new CREDENTIAL_ENCRYPTION_KEY or they
will fail to decrypt. Derive the legacy key from your existing SECRET_KEY, then run the
re-encryption script (idempotent, safe to re-run):
# Derive the old key from the SECRET_KEY the credentials were encrypted with
# (run in the container so it reads the same SECRET_KEY from .env):
OLD_KEY=$(docker compose exec -T api python -c 'import base64, os; s = os.environ["SECRET_KEY"].encode(); print(base64.urlsafe_b64encode(s[:32].ljust(32, b"0")).decode())')
# Re-encrypt every credential to CREDENTIAL_ENCRYPTION_KEY (the new-key default):
docker compose exec api python -m src.scripts.reencrypt_credentials --old-key "$OLD_KEY"Set CREDENTIAL_ENCRYPTION_KEY in .env to a stable value before upgrading (deploy.sh
generates one if it's empty — pin it so it doesn't change on the next deploy).
Interactive setup (recommended on first install):
astro initNon-interactive (URL only):
astro init --url http://localhost:8000 --skip-login -yView or change settings later:
astro config show
astro config url http://localhost:8000Environment variables override the config file:
ASTRO_API_URLASTRO_API_TOKEN
| Area | Examples |
|---|---|
| Setup | astro init |
| Config | astro config show, astro config url |
| Auth | astro auth login |
| Agents | astro agent list |
| Tools | astro tool list |
| LLMs | astro llm list |
| Stacks | astro stacks list, astro stacks exec |
| Scheduled runs | astro stacks schedule create, astro stacks schedule runs, astro stacks schedule run |
| Docs | astro docs |
| Path | Description |
|---|---|
api/ |
Core backend, orchestration, agent logic |
client/ |
CLI interface (astro) |
tools/ |
Tool execution service |
docker-compose.yaml |
Runtime services |
- Vulnerability triage and prioritization
- Offensive security workflows (recon → validation → exploitation)
- Detection and response investigations
- Security automation with real tool execution
ASTRO is built on a simple belief:
AI should not replace security engineers.
It should extend how they already work.
MIT — see LICENSE
