Skip to content

Agent DevOps Pattern

This document describes the reusable pattern for agent-driven infrastructure operations.

Overview

Infrastructure operations in ClearlyOps follow a consistent pattern that is safe for AI agents to execute:

  • Config-driven: one TOML file per subsystem
  • Idempotent: safe to run multiple times
  • Plan/Apply: preview changes before applying
  • Auditable: JSON receipts for every operation

Contract

Every agent-facing infra tool follows this interface:

<tool> plan   [--config PATH] [--format json|text]
<tool> apply  [--config PATH] --confirm RESOURCE [--format json|text]
<tool> status [--config PATH] [--format json|text]

Commands

Command Description Mutates?
plan Show what would change (dry-run) No
apply Apply changes with confirmation Yes
status Show current resource state No

Safety

  • Default is read-only: plan and status are the default
  • Explicit confirmation: apply requires --confirm <resource> to prevent accidental mutations
  • No secrets in output: tokens are redacted; never written to disk or logs

Output

All tools emit structured output:

{
  "timestamp": "2026-01-17T18:30:00Z",
  "command": "apply",
  "config_path": "deploy/infra/docs.toml",
  "changes": [
    {
      "resource_type": "pages_project",
      "resource_id": "abc123",
      "action": "create",
      "details": {"name": "clearlyops-docs-public"}
    }
  ],
  "errors": []
}

Use --format json for machine-readable output.

Directory Structure

deploy/
  infra/
    docs.toml           # Docs hosting config
    docs.example.toml   # Example with placeholders
    api.toml            # (future) API deployment config
    ...

scripts/
  setup_docs_infra.py   # Docs infra tool
  ops/                  # (future) Additional ops tools
    api_deploy.py
    ...

Secrets

Secrets are never stored in the repo or in GitHub Secrets:

  1. Source of truth: GCP Secret Manager
  2. CI access: GitHub OIDC → GCP Workload Identity → Secret Manager
  3. Local access: gcloud secrets versions access ...

Tools fetch secrets at runtime and redact them from all output.

Example: Docs Infrastructure

Config (deploy/infra/docs.toml)

[gcp]
project_id = "clearlyops-prod"
secret_cloudflare_api_token = "cloudflare-pages-api-token"

[cloudflare]
account_id = "abc123"
zone_id = "def456"

[docs.public]
pages_project_name = "clearlyops-docs-public"
custom_domain = "docs.clearlyops.com"

[docs.internal]
pages_project_name = "clearlyops-docs-internal"
custom_domain = "docs-internal.clearlyops.com"
preview_deployments = "disabled"

[access]
allowed_emails = ["[email protected]"]

Usage

# Preview changes
python scripts/setup_docs_infra.py plan

# Apply (requires confirmation)
python scripts/setup_docs_infra.py apply --confirm docs-internal.clearlyops.com

# Get JSON receipt
python scripts/setup_docs_infra.py status --format json

Extending the Pattern

To add a new infrastructure tool:

  1. Create config: deploy/infra/<subsystem>.toml
  2. Create tool: scripts/setup_<subsystem>_infra.py or scripts/ops/<subsystem>.py
  3. Implement commands: plan, apply, status
  4. Ensure idempotency: check if resources exist before creating
  5. Emit receipts: use the standard JSON receipt format
  6. Fetch secrets from GCP: use gcloud secrets versions access ...

Receipt Format

@dataclass
class ResourceChange:
    resource_type: str   # e.g., "pages_project", "dns_record"
    resource_id: str     # Unique identifier
    action: str          # "create", "update", "no_change"
    details: dict        # Resource-specific details

@dataclass
class InfraReceipt:
    timestamp: str       # ISO 8601
    command: str         # "plan", "apply", "status"
    config_path: str     # Path to config file
    changes: list[ResourceChange]
    errors: list[str]    # Error messages (if any)

Agent Workflow

Agents should follow this workflow:

  1. Read config: load deploy/infra/<subsystem>.toml
  2. Plan first: always run plan before apply
  3. Review changes: check the receipt for expected changes
  4. Apply with confirmation: run apply --confirm <resource>
  5. Verify: run status to confirm state
  6. Store receipt: save JSON receipt for audit trail

Example Agent Prompt

You are managing infrastructure for ClearlyOps.

To update docs hosting:
1. Run: python scripts/setup_docs_infra.py plan
2. Review the output for expected changes
3. If changes look correct, run: python scripts/setup_docs_infra.py apply --confirm docs-internal.clearlyops.com
4. Verify with: python scripts/setup_docs_infra.py status --format json

Future Tools

Planned agent-facing infra tools:

Tool Config Purpose
setup_docs_infra.py docs.toml Docs hosting (Cloudflare Pages + Access)
setup_api_infra.py api.toml API deployment (Cloud Run)
setup_db_infra.py db.toml Database provisioning (Cloud SQL)
setup_dns_infra.py dns.toml DNS records

All follow the same plan/apply/status + JSON receipt pattern.

Comparison: Script vs Terraform

Aspect Script Terraform
Setup Minimal (Python only) Requires state backend
Learning curve Low Medium
Drift detection Manual (via status) Automatic
State management Stateless (idempotent checks) Stateful
Agent compatibility Excellent (simple CLI) Good (after setup)
Best for Early stage, fast iteration Multi-env, complex infra

Current approach: scripts with Terraform-like semantics (plan/apply). If infra complexity grows, migrate to Terraform while keeping the same agent-facing interface.