API reference¶
Generated from the apogee-ai-ops source with mkdocstrings. Every symbol below is exported from apogee_ai_ops, so it is part of the supported public surface.
Application · DTOs¶
AlertDTO
dataclass
¶
BenchDTO
dataclass
¶
DeployDTO
dataclass
¶
DeployDTO(name: str, image: str = '', deployer: str = 'dry_run', replicas: int = 1, env: dict[str, str] = dict())
HealthDTO
dataclass
¶
Application · Use cases¶
AlertOnFailUseCase
¶
AlertOnFailUseCase(checker, sink, severity_when_unhealthy: AlertSeverity = ERROR)
Runs a healthcheck and emits an alert if not healthy.
Source code in apogee_ai_ops/application/use_cases/alert_on_fail_use_case.py
execute
async
¶
Source code in apogee_ai_ops/application/use_cases/alert_on_fail_use_case.py
async def execute(self, target: str, source: str = "ops") -> bool:
health = await self._checker.check(target)
if health.status is HealthStatus.HEALTHY:
return True
await self._sink.emit(Alert(
title=f"{target} is {health.status.value}",
message=health.message or "no message",
severity=self._severity,
source=source,
metadata={"latency_ms": f"{health.latency_ms:.1f}"},
))
return False
BenchOpsUseCase
¶
execute
async
¶
Source code in apogee_ai_ops/application/use_cases/bench_ops_use_case.py
async def execute(self, deployments: int) -> dict[str, float]:
if deployments <= 0:
raise ValueError("deployments must be positive")
deployer = DryRunDeployer()
use_case = DeployUseCase(deployer)
start = time.perf_counter()
for i in range(deployments):
await use_case.execute(Deployment(
name=f"bench-{i:04d}", image="apogee/echo:0.1",
))
elapsed = (time.perf_counter() - start) * 1000.0
return {
"deployments": float(deployments),
"elapsed_ms": elapsed,
"deployments_per_second": (deployments / elapsed * 1000.0) if elapsed > 0 else 0.0,
}
DeployUseCase
¶
Source code in apogee_ai_ops/application/use_cases/deploy_use_case.py
execute
async
¶
execute(deployment: Deployment) -> Deployment
HealthcheckUseCase
¶
Source code in apogee_ai_ops/application/use_cases/healthcheck_use_case.py
execute
async
¶
execute(target: str) -> ServiceHealth
RollbackUseCase
¶
Source code in apogee_ai_ops/application/use_cases/rollback_use_case.py
execute
async
¶
RunRunbookUseCase
¶
Executes a Runbook step-by-step with on_failure semantics.
step_dispatch is a callable that receives a step name + action and
returns a coroutine. Failures honour step.on_failure: stop, continue,
or rollback (which re-runs the step's action prefixed with 'rollback:').
Source code in apogee_ai_ops/application/use_cases/run_runbook_use_case.py
execute
async
¶
execute(runbook: Runbook) -> dict
Source code in apogee_ai_ops/application/use_cases/run_runbook_use_case.py
async def execute(self, runbook: Runbook) -> dict:
executed: list[str] = []
failed: list[str] = []
for step in runbook.steps:
try:
await self._dispatch(step.name, step.action)
executed.append(step.name)
except Exception as exc: # noqa: BLE001
failed.append(step.name)
if step.on_failure == "stop":
return {
"executed": executed,
"failed": failed,
"stopped_at": step.name,
"error": str(exc),
}
if step.on_failure == "rollback":
try:
await self._dispatch(step.name, f"rollback:{step.action}")
except Exception: # noqa: BLE001
pass
return {
"executed": executed,
"failed": failed,
"rolled_back_at": step.name,
"error": str(exc),
}
# on_failure == "continue"
return {"executed": executed, "failed": failed}
Domain¶
Alert
dataclass
¶
Alert(title: str, message: str, severity: AlertSeverity = WARNING, source: str = 'apogee-ai-ops', timestamp_s: float = time(), metadata: dict[str, str] = dict())
AlertSeverity
¶
Deployment
dataclass
¶
Deployment(name: str, image: str = '', command: tuple[str, ...] = (), env: dict[str, str] = dict(), replicas: int = 1, status: DeploymentStatus = PENDING, metadata: dict[str, str] = dict())
metadata
class-attribute
instance-attribute
¶
DeploymentStatus
¶
Bases: str, Enum
HealthStatus
¶
Bases: str, Enum
Runbook
dataclass
¶
Runbook(name: str, description: str = '', steps: tuple[RunbookStep, ...] = ())
RunbookStep
dataclass
¶
ServiceHealth
dataclass
¶
ServiceHealth(name: str, status: HealthStatus = UNKNOWN, latency_ms: float = 0.0, message: str = '', metadata: dict[str, str] = dict())
metadata
class-attribute
instance-attribute
¶
Domain · Enums¶
DeployerKind
¶
Domain · Exceptions¶
DeploymentError
¶
OpsError
¶
Bases: Exception
Base for apogee-ai-ops errors.
Domain · Protocols (ports)¶
IAlertSink
¶
IDeployer
¶
Bases: Protocol
deploy
async
¶
deploy(deployment: Deployment) -> Deployment
rollback
async
¶
status
async
¶
status(name: str) -> Deployment
IHealthcheck
¶
Bases: Protocol
check
async
¶
check(target: str) -> ServiceHealth
IRunbookRunner
¶
Infrastructure¶
CompositeHealthcheck
¶
Aggregates multiple healthchecks against multiple targets in parallel.
Source code in apogee_ai_ops/infrastructure/health/composite_healthcheck.py
check
async
¶
check(target: str = 'composite') -> ServiceHealth
Source code in apogee_ai_ops/infrastructure/health/composite_healthcheck.py
async def check(self, target: str = "composite") -> ServiceHealth:
results = await asyncio.gather(
*[checker.check(t) for checker, t in self._members]
)
if all(r.is_healthy for r in results):
status = HealthStatus.HEALTHY
elif any(r.status is HealthStatus.UNHEALTHY for r in results):
status = HealthStatus.UNHEALTHY
else:
status = HealthStatus.DEGRADED
avg_latency = sum(r.latency_ms for r in results) / len(results)
return ServiceHealth(
name=target,
status=status,
latency_ms=avg_latency,
metadata={"members": str(len(results))},
)
ConsoleAlertSink
¶
DeployerRegistry
¶
DockerDeployer
¶
Lazy Docker SDK adapter — install via extras=docker.
Source code in apogee_ai_ops/infrastructure/deployers/docker_deployer.py
deploy
async
¶
deploy(deployment: Deployment) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/docker_deployer.py
async def deploy(self, deployment: Deployment) -> Deployment:
self._ensure_client()
if not deployment.image:
raise DeploymentError(deployment.name, "image required")
try:
container = self._client.containers.run( # type: ignore[union-attr]
deployment.image,
command=list(deployment.command) or None,
environment=dict(deployment.env),
detach=True,
name=deployment.name,
)
except Exception as exc: # pragma: no cover
raise DeploymentError(deployment.name, str(exc)) from exc
self._containers[deployment.name] = container.id
return replace(deployment, status=DeploymentStatus.RUNNING)
rollback
async
¶
Source code in apogee_ai_ops/infrastructure/deployers/docker_deployer.py
async def rollback(self, name: str) -> None:
self._ensure_client()
cid = self._containers.get(name)
if cid is None:
raise DeploymentError(name, "not deployed")
try:
container = self._client.containers.get(cid) # type: ignore[union-attr]
container.stop(timeout=5)
container.remove()
except Exception as exc: # pragma: no cover
raise DeploymentError(name, str(exc)) from exc
status
async
¶
status(name: str) -> Deployment
DryRunDeployer
¶
Deployer that records calls without performing real actions.
CI-safe — never touches docker, k8s or processes.
Source code in apogee_ai_ops/infrastructure/deployers/dry_run_deployer.py
deploy
async
¶
deploy(deployment: Deployment) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/dry_run_deployer.py
rollback
async
¶
Source code in apogee_ai_ops/infrastructure/deployers/dry_run_deployer.py
status
async
¶
status(name: str) -> Deployment
HttpHealthcheck
¶
Source code in apogee_ai_ops/infrastructure/health/http_healthcheck.py
check
async
¶
check(target: str) -> ServiceHealth
Source code in apogee_ai_ops/infrastructure/health/http_healthcheck.py
async def check(self, target: str) -> ServiceHealth:
start = time.perf_counter()
status, message = await asyncio.to_thread(self._check_sync, target)
latency = (time.perf_counter() - start) * 1000.0
if status == self._expected:
return ServiceHealth(
name=target, status=HealthStatus.HEALTHY,
latency_ms=latency, metadata={"http_status": str(status)},
)
if 200 <= status < 500:
return ServiceHealth(
name=target, status=HealthStatus.DEGRADED,
latency_ms=latency, message=message,
metadata={"http_status": str(status)},
)
return ServiceHealth(
name=target, status=HealthStatus.UNHEALTHY,
latency_ms=latency, message=message,
metadata={"http_status": str(status)},
)
JsonFileAlertSink
¶
Appends one JSON object per line to a file. Atomic per-line writes.
Source code in apogee_ai_ops/infrastructure/alerts/json_file_alert_sink.py
emit
async
¶
emit(alert: Alert) -> None
Source code in apogee_ai_ops/infrastructure/alerts/json_file_alert_sink.py
async def emit(self, alert: Alert) -> None:
payload = {
"title": alert.title,
"message": alert.message,
"severity": alert.severity.value,
"source": alert.source,
"timestamp_s": alert.timestamp_s,
"metadata": dict(alert.metadata),
}
with self._path.open("a", encoding="utf-8") as fh:
fh.write(json.dumps(payload) + "\n")
K8sDeployer
¶
Lazy Kubernetes adapter — install via extras=k8s.
Source code in apogee_ai_ops/infrastructure/deployers/k8s_deployer.py
deploy
async
¶
deploy(deployment: Deployment) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/k8s_deployer.py
async def deploy(self, deployment: Deployment) -> Deployment:
self._ensure_client()
from kubernetes import client # type: ignore
body = client.V1Deployment(
metadata=client.V1ObjectMeta(name=deployment.name),
spec=client.V1DeploymentSpec(
replicas=deployment.replicas,
selector=client.V1LabelSelector(
match_labels={"app": deployment.name}
),
template=client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(labels={"app": deployment.name}),
spec=client.V1PodSpec(containers=[
client.V1Container(
name=deployment.name,
image=deployment.image,
command=list(deployment.command) or None,
env=[client.V1EnvVar(name=k, value=v)
for k, v in deployment.env.items()],
)
]),
),
),
)
try:
self._apps.create_namespaced_deployment( # type: ignore[union-attr]
namespace=self._namespace, body=body
)
except Exception as exc: # pragma: no cover
raise DeploymentError(deployment.name, str(exc)) from exc
return replace(deployment, status=DeploymentStatus.RUNNING)
rollback
async
¶
Source code in apogee_ai_ops/infrastructure/deployers/k8s_deployer.py
status
async
¶
status(name: str) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/k8s_deployer.py
async def status(self, name: str) -> Deployment:
self._ensure_client()
try:
d = self._apps.read_namespaced_deployment( # type: ignore[union-attr]
name=name, namespace=self._namespace
)
except Exception as exc: # pragma: no cover
raise DeploymentError(name, str(exc)) from exc
ready = (d.status.ready_replicas or 0) >= (d.spec.replicas or 1)
return Deployment(
name=name,
image=d.spec.template.spec.containers[0].image or "",
replicas=d.spec.replicas or 1,
status=DeploymentStatus.SUCCEEDED if ready else DeploymentStatus.PENDING,
)
ProcessDeployer
¶
Spawns deployments as local subprocesses. Useful for dev/stub agents.
Source code in apogee_ai_ops/infrastructure/deployers/process_deployer.py
deploy
async
¶
deploy(deployment: Deployment) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/process_deployer.py
async def deploy(self, deployment: Deployment) -> Deployment:
if not deployment.command:
raise DeploymentError(
deployment.name, "command required for process deployer"
)
env = {**os.environ, **deployment.env}
try:
proc = await asyncio.create_subprocess_exec(
*deployment.command,
env=env,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
except (OSError, FileNotFoundError) as exc:
raise DeploymentError(deployment.name, str(exc)) from exc
self._processes[deployment.name] = proc
deployed = replace(deployment, status=DeploymentStatus.RUNNING)
self._state[deployment.name] = deployed
return deployed
rollback
async
¶
Source code in apogee_ai_ops/infrastructure/deployers/process_deployer.py
async def rollback(self, name: str) -> None:
proc = self._processes.get(name)
if proc is None:
raise DeploymentError(name, "not deployed")
if proc.returncode is None:
try:
proc.send_signal(signal.SIGTERM)
except ProcessLookupError:
pass
try:
await asyncio.wait_for(proc.wait(), timeout=5.0)
except asyncio.TimeoutError:
proc.kill()
await proc.wait()
self._state[name] = replace(
self._state[name], status=DeploymentStatus.ROLLED_BACK
)
status
async
¶
status(name: str) -> Deployment
Source code in apogee_ai_ops/infrastructure/deployers/process_deployer.py
async def status(self, name: str) -> Deployment:
if name not in self._state:
raise DeploymentError(name, "not deployed")
proc = self._processes.get(name)
if proc is not None and proc.returncode is not None:
current = (
DeploymentStatus.SUCCEEDED if proc.returncode == 0 else DeploymentStatus.FAILED
)
self._state[name] = replace(self._state[name], status=current)
return self._state[name]
SlackAlertSink
¶
Lazy slack-sdk adapter — install via extras=slack.
Source code in apogee_ai_ops/infrastructure/alerts/slack_alert_sink.py
emit
async
¶
emit(alert: Alert) -> None
Source code in apogee_ai_ops/infrastructure/alerts/slack_alert_sink.py
async def emit(self, alert: Alert) -> None:
self._ensure_client()
emoji = _SEVERITY_EMOJI.get(alert.severity.value, ":bell:")
text = f"{emoji} *{alert.title}*\n{alert.message}\n_source: {alert.source}_"
try:
await self._client.chat_postMessage( # type: ignore[union-attr]
channel=self._channel, text=text,
)
except Exception as exc: # pragma: no cover
raise AlertDeliveryError(str(exc)) from exc
TcpHealthcheck
¶
Pings host:port via asyncio sockets.
Source code in apogee_ai_ops/infrastructure/health/tcp_healthcheck.py
check
async
¶
check(target: str) -> ServiceHealth
Source code in apogee_ai_ops/infrastructure/health/tcp_healthcheck.py
async def check(self, target: str) -> ServiceHealth:
if ":" not in target:
return ServiceHealth(
name=target, status=HealthStatus.UNKNOWN,
message="target must be host:port",
)
host, _, port_str = target.rpartition(":")
try:
port = int(port_str)
except ValueError:
return ServiceHealth(
name=target, status=HealthStatus.UNKNOWN,
message=f"invalid port: {port_str!r}",
)
start = time.perf_counter()
try:
reader, writer = await asyncio.wait_for(
asyncio.open_connection(host, port), timeout=self._timeout,
)
except (OSError, asyncio.TimeoutError) as exc:
return ServiceHealth(
name=target, status=HealthStatus.UNHEALTHY,
latency_ms=(time.perf_counter() - start) * 1000.0,
message=str(exc),
)
writer.close()
try:
await writer.wait_closed()
except Exception: # noqa: BLE001
pass
return ServiceHealth(
name=target, status=HealthStatus.HEALTHY,
latency_ms=(time.perf_counter() - start) * 1000.0,
)