Deployment guide¶
This guide covers the CI/CD pipeline, Docker containerization, environment variable configuration for production, security hardening, and observability setup for the agentic-runtime-platform monorepo.
CI/CD pipeline¶
The primary CI workflow is defined in .github/workflows/ci.yml. It runs on every push to main and on all pull requests targeting main. A superseded PR run is cancelled when a newer commit is pushed; runs for pushes to main are never cancelled.
Pipeline jobs¶
The ci.yml workflow contains the jobs below, all on ubuntu-latest. On pull requests, a changes job classifies the changed files and the heavier jobs are skipped (reporting as skipped, which satisfies a required check) when the PR cannot affect them -- for example docs-only PRs. lint is never skipped, pushes to main always run everything, and the gates fail open if changes itself fails. Path gating is job-level only: never add workflow-level paths: to a workflow that provides a required check, and never rename a required job.
| Job | What it does |
|---|---|
changes |
PR-only path classification (backend / UI / wire-format surfaces) that drives the job-level gates below |
python-smoke |
Installs all three packages, verifies critical imports and combined runtime + eval test collection, and runs the swe_ab tool tests and tools/tests (the runtime unit suite runs in test-coverage and no-llm-smoke) |
frontend-build |
npm ci, the production build (tsc -b && vite build), then the vitest unit suite with the coverage floors (npm run test:coverage) |
lint |
Ruff on agentic_v2/ and tests/ (and a final check that ruff check --fix would change nothing), the suppression ratchet, pydocstyle on core/ and contracts/, workflow-definition validation, protocol/ADR and local-reference drift checks, generated homepage-stat drift, Dockerfile pip install constraint pins, and ci-constraints.txt vs uv.lock drift. Each check is its own step so one failure does not hide the others (the autofix check only runs when ruff itself passed, and the checks that need the pip install are skipped if it failed) |
typecheck-core-contracts |
Strict mypy on agentic_v2/engine and agentic_v2/contracts (--disallow-untyped-defs --warn-return-any) |
test-coverage |
Unit suite with coverage on agentic_v2, then enforces the 80% gate in a dedicated coverage report --fail-under=80 step; on pushes to main it also runs a whole-repo coverage pass and uploads the report for visibility |
ek-delegation-tests (check name: EK step-delegation (approval-gate) tests) |
Installs the optional claude, ek and eval extras together and runs the suites that module-skip everywhere else: the Claude subscription backend, the ExecutionKit approval-gate regressions, the EvalKit bridge, and scoring without the legacy evaluation package |
wire-format-drift |
Regenerates JSON schemas and TypeScript types from the Pydantic contracts and fails on any diff |
e2e-streaming |
Runs the full Playwright e2e suite once with AGENTIC_NO_LLM=1; repeat-run flake detection (full suite 5x, streaming spec 50x) runs in nightly.yml |
no-llm-smoke |
Validates and runs a deterministic workflow plus the full unit suite with AGENTIC_NO_LLM=1 and zero API keys |
A single job failure blocks the merge. There are no bypass mechanisms for CI failures.
Additional workflow files¶
The other workflows in .github/workflows/:
| File | Purpose |
|---|---|
codeql.yml |
CodeQL static analysis on push, PR and weekly; markdown/image/LICENSE/proofs-only PRs skip the analysis steps but the check still reports |
dependabot-auto-merge.yml |
Auto-merges passing Dependabot PRs |
dependency-audit.yml |
pip-audit (Python packages) and npm audit (UI) CVE scans |
dependency-review.yml |
Dependency license and vulnerability review on PRs |
deploy.yml |
Release pipeline, triggered on version tags (v*); also runs as a build check on PRs that touch packaging inputs |
devcontainer-validate.yml |
Validates the devcontainer on changes to its inputs (.devcontainer/, the Dockerfile, the pyproject files, ci-constraints.txt, the UI package files) |
docs.yml |
Builds and deploys the docs site to GitHub Pages (the only Pages publisher; also regenerates and verifies the load report from load/results/*.json) |
eval-package-ci.yml |
Isolated CI for the agentic-v2-eval package |
infra-deploy.yml |
Reference infrastructure deployment workflow (manual dispatch only; never run automatically) |
nightly.yml |
Nightly E2E reliability run (scheduled): the streaming spec 50x feeding the flake-rate gate, the first-span SLO sample, the SLO-data publish, then the full Playwright suite 5x |
pr-agent.yml |
Open-source PR-Agent on Ollama Cloud: auto-reviews new same-repo PRs and answers /review, /describe, /improve, /ask comments from the owner or collaborators (needs the OLLAMA_API_KEY secret) |
sbom.yml |
SBOM generation on release and weekly |
weekly-telemetry-snapshot.yml |
Weekly CI-run statistics (and optional repository traffic) appended to a rolling ledger issue; never a PR check |
windows-workflows-ci.yml |
Windows workflow verification |
Pre-commit hooks¶
Pre-commit hooks run automatically before every local commit. CI does not run pre-commit directly — the lint job in ci.yml enforces the same ruff rules, and pre-commit run --all-files is a required local gate before opening a PR (see .claude/rules/ci.md).
| Hook | Tool | Purpose |
|---|---|---|
black |
Black | Python code formatting (line-length 88) |
ruff |
Ruff | Linting and import sorting (replaces Flake8/pylint/pycodestyle/isort) |
docformatter |
docformatter | Docstring formatting |
mypy |
mypy | Strict type checking of agentic-v2-eval/src |
strip-ai-coauthors |
local script | Strips AI-assistant author trailers at the commit-msg stage |
detect-secrets |
detect-secrets | Secret and credential leak prevention |
Install hooks: pre-commit install
Run all hooks manually: pre-commit run --all-files
Security scanning¶
SAST — bandit¶
bandit scans Python source for common security anti-patterns (hardcoded passwords, unsafe use of subprocess, SQL injection sinks, etc.). It is not currently wired into a CI job — run it manually during security audits:
The -ll flag reports issues at MEDIUM severity and above. LOW severity findings should still be reviewed during security audits.
Dependency audit — pip-audit¶
pip-audit checks installed package versions against the OSV database for known CVEs. It runs in the dependency-audit.yml workflow on every push and PR (alongside npm audit for the UI), and the audit results JSON is retained as a build artifact.
Secret detection — detect-secrets¶
detect-secrets scans file content for patterns matching API keys, tokens, passwords, and other credentials before every commit. A .secrets.baseline file in the repository root contains approved false positives.
Docker builds¶
Backend image¶
Build:
The production target installs the repo-root agentic-tools package plus
agentic-workflows-v2 with [server,tracing,langchain] extras, pinned to
ci-constraints.txt, and starts the FastAPI application factory on port 8010.
Frontend image¶
Build:
The frontend target runs npm ci && npm run build and serves the resulting
SPA from a non-root nginx container on port 8080. Production ingress must route
same-origin /api and /ws traffic to the backend.
Full stack with Docker Compose¶
The docker-compose.yml starts four services:
backend— FastAPI server on port 8010 (uvicorn with--reload)frontend— Vite dev server on port 5173, proxying API calls tobackendotel-collector— OpenTelemetry Collector (OTLP gRPC on 4317, HTTP on 4318)jaeger— Jaeger all-in-one for trace viewing (UI on 16686)
Environment variable reference (production)¶
Set these in your deployment environment (Kubernetes secrets, cloud provider secrets manager, or .env file for Docker Compose).
LLM provider keys¶
Configure at least one of the following:
| Variable | Description |
|---|---|
GITHUB_TOKEN |
GitHub Models access token; availability and limits depend on the current account |
OPENAI_API_KEY |
OpenAI GPT-4o, GPT-4.1, o-series |
ANTHROPIC_API_KEY |
Anthropic Claude 3/4 family |
GEMINI_API_KEY |
Google Gemini 2.5 family |
AZURE_OPENAI_API_KEY_0 |
Azure OpenAI key (supports _0–_n for failover) |
AZURE_OPENAI_ENDPOINT_0 |
Azure OpenAI endpoint URL |
Server security¶
| Variable | Description | Production requirement |
|---|---|---|
AGENTIC_API_KEY |
Bearer token for all /api/ routes. Both Authorization: Bearer <key> and X-API-Key: <key> headers are accepted. Token comparison uses secrets.compare_digest to prevent timing attacks. |
Mandatory |
AGENTIC_CORS_ORIGINS |
Comma-separated list of allowed CORS origins. Example: https://app.example.com,https://admin.example.com |
Mandatory — restrict to actual frontend origins |
AGENTIC_FILE_BASE_DIR |
Base directory for all file operations via the file_ops built-in tool. When set, all file paths are resolved relative to this directory and any attempt to traverse outside it is rejected. Example: /app/data |
Strongly recommended — prevents path traversal |
AGENTIC_BLOCK_PRIVATE_IPS |
Default ON (1). Blocks HTTP tool requests to private/loopback/link-local/reserved IPs, performs DNS resolution to catch hostname-based SSRF, and re-validates each redirect hop. Set to 0 only when workflows need internal network access and you have applied compensating controls. |
Default ON — opt out with 0 only with explicit justification |
Agent configuration¶
| Variable | Description |
|---|---|
AGENTIC_EXTERNAL_AGENTS_DIR |
Path to a directory of additional agent definition files. Allows custom agents without modifying the package. |
AGENTIC_MEMORY_PATH |
File path for the persistent memory store. When unset, memory is in-process only and lost on restart. |
AGENTIC_MODEL_TIER_1 |
Override the tier-1 (fast, low-cost) model name used by the router. |
AGENTIC_MODEL_TIER_2 |
Override the tier-2 (capable) model name. |
AGENTIC_JUDGE_MODEL |
Model used by the LLM-as-judge scorer. Defaults to tier-2 if unset. |
OpenTelemetry¶
| Variable | Description | Default |
|---|---|---|
AGENTIC_TRACING |
Set to 1 to enable OTEL span export. |
disabled |
AGENTIC_TRACE_SENSITIVE |
Set to 1 to include prompt text, LLM outputs, and tool arguments in spans. Do not enable in environments subject to data retention or PII regulations. |
excluded |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP collector endpoint. For gRPC: http://collector:4317. For HTTP: http://collector:4318/v1/traces |
http://localhost:4317 |
OTEL_EXPORTER_OTLP_PROTOCOL |
grpc or http/protobuf |
grpc |
Windows AI (optional)¶
| Variable | Description |
|---|---|
PHI_SILICA_LAF_FEATURE_ID |
Windows AI (Phi Silica) LAF feature identifier |
PHI_SILICA_LAF_TOKEN |
Phi Silica LAF token |
PHI_SILICA_LAF_ATTESTATION |
Phi Silica attestation string |
Port configuration¶
| Service | Port | Protocol | Configuration |
|---|---|---|---|
| FastAPI backend | 8010 | HTTP / WebSocket | uvicorn --port 8010 |
| Vite dev server | 5173 | HTTP | Configured in vite.config.ts |
| Vite hot-module reload | 5183 | WebSocket | Development only; configured in vite.config.ts |
| OTLP gRPC | 4317 | gRPC | OTEL_EXPORTER_OTLP_ENDPOINT |
| OTLP HTTP | 4318 | HTTP/protobuf | Use with OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf |
| Jaeger UI | 16686 | HTTP | Docker Compose jaeger service |
Production configuration checklist¶
Before deploying to a production or shared environment, verify the following:
Authentication and network¶
-
AGENTIC_API_KEYis set to a strong random value (minimum 32 characters) -
AGENTIC_CORS_ORIGINSis restricted to the actual frontend origin(s) -
AGENTIC_BLOCK_PRIVATE_IPS=1is set if thehttp_opstool is enabled - TLS termination is in place upstream of the FastAPI server (nginx, ALB, etc.)
- The backend is not publicly accessible on port 8010 without TLS
File and path safety¶
-
AGENTIC_FILE_BASE_DIRis set to an appropriate restricted directory - The directory specified in
AGENTIC_FILE_BASE_DIRdoes not contain sensitive system files - Workflow definitions have been reviewed for tool allowlists — high-risk tools (
shell_ops,git_ops,file_delete) require explicit per-step allowlisting
LLM provider keys¶
- All API keys are stored in a secrets manager or environment injection — never in source code or Docker images
- Unused provider keys are not configured (reduces attack surface)
- Azure failover keys (
_1,_2, ...) are configured if using Azure OpenAI under load
Observability¶
-
AGENTIC_TRACING=1with OTEL collector configured for production trace ingestion -
AGENTIC_TRACE_SENSITIVEis NOT set (or explicitly reviewed) in environments subject to PII regulations - Server logs are routed to a centralized log aggregator
- Health check endpoint (
GET /api/health) is monitored by the load balancer or orchestrator
Persistence¶
-
AGENTIC_MEMORY_PATHis set to a persistent volume mount if cross-restart memory is needed - The
runs/directory is either mounted on persistent storage or backed up — it contains all run result JSON files
Coverage gates summary¶
| Package | Tool | Gate |
|---|---|---|
agentic-workflows-v2 |
pytest + coverage | 80% on agentic_v2 — CI collects coverage without --cov-fail-under and enforces the gate in a dedicated coverage report --fail-under=80 step (pytest-cov 7.x does not propagate the failure exit code reliably) |
agentic-v2-eval |
pytest + coverage | 80% on src/agentic_v2_eval (--cov-fail-under=80 in eval-package-ci.yml) |
agentic-tools |
pytest | No per-package gate — included in the whole-repo coverage report for visibility only |
agentic-workflows-v2/ui |
Vitest | 60% threshold (configured in ui/vitest.config.ts) |