Running the Full Agentic Deployment Pipeline: Scaffold to Live CloudFront

Published: (March 16, 2026 at 04:45 PM EDT)
5 min read
Source: Dev.to

Source: Dev.to

Phase 4 — Agentic Infrastructure

Building a Live AWS Deployment Pipeline with Claude Code

Phases 1‑3 built the foundation: a verified environment, a project‑aware agent, and four reusable Skills. Phase 4 uses that foundation to run the complete deployment pipeline—from an empty Terraform directory to a live static website on AWS CloudFront. This post documents every step, command, and output.

Execution Steps

#CommandTypeOutput
1/scaffold-terraformSkill4 Terraform files generated
2terraform initManualProviders downloaded
3/tf-planSkillPlan: 4 create, 0 destroy
4/tf-applySkill4 AWS resources provisioned
5/deploySkillSite live on CloudFront

Generated Terraform Files

Claude read template-spec.md and generated the complete Terraform configuration in the terraform/ directory.

terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── providers.tf

main.tf (excerpt)

# S3 bucket — versioning enabled, public access blocked
resource "aws_s3_bucket" "site" {
  bucket = var.bucket_name
  tags   = var.tags
}

resource "aws_s3_bucket_versioning" "site" {
  bucket = aws_s3_bucket.site.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_public_access_block" "site" {
  bucket                  = aws_s3_bucket.site.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# CloudFront origin access control
resource "aws_cloudfront_origin_access_control" "oac" {
  name                              = "${var.bucket_name}-oac"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

# CloudFront distribution
resource "aws_cloudfront_distribution" "site" {
  enabled             = true
  default_root_object = "index.html"
  price_class         = "PriceClass_200" # Africa + Europe coverage

  origin {
    domain_name              = aws_s3_bucket.site.bucket_regional_domain_name
    origin_id                = "S3Origin"
    origin_access_control_id = aws_cloudfront_origin_access_control.oac.id
  }

  default_cache_behavior {
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "S3Origin"

    forwarded_values {
      query_string = false
      cookies { forward = "none" }
    }
  }

  restrictions {
    geo_restriction { restriction_type = "none" }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

# Bucket policy — CloudFront access only
resource "aws_s3_bucket_policy" "site_policy" {
  bucket = aws_s3_bucket.site.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "cloudfront.amazonaws.com" }
      Action    = "s3:GetObject"
      Resource  = "${aws_s3_bucket.site.arn}/*"
      Condition = {
        StringEquals = {
          "AWS:SourceArn" = aws_cloudfront_distribution.site.arn
        }
      }
    }]
  })
}

providers.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "af-south-1"
}

Initialising Terraform

cd terraform/
terraform init

Output (truncated):

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.x.x...
- Installed hashicorp/aws v5.x.x (signed by HashiCorp)

Terraform has been successfully initialized!

Note: terraform init is intentionally not automated inside a Skill because it downloads provider plugins and sets up the backend—decisions that merit manual confirmation.

Planning

The Skill ran terraform validate, then terraform plan -out=tfplan.binary, and scanned the output for destructions.

Plan Summary

ChangeCountResources
Create4aws_s3_bucket, aws_cloudfront_distribution, aws_cloudfront_origin_access_control, aws_s3_bucket_policy
Modify0
Destroy0

Zero destructions were detected, so the plan was deemed safe and presented for review before proceeding.

Applying

terraform apply tfplan.binary

Result (excerpt):

aws_cloudfront_origin_access_control.oac: Creating...
aws_s3_bucket.site: Creating...
aws_s3_bucket.site: Creation complete
aws_s3_bucket_versioning.site: Creating...
aws_s3_bucket_public_access_block.site: Creating...
aws_cloudfront_origin_access_control.oac: Creation complete
aws_cloudfront_distribution.site: Creating...
aws_cloudfront_distribution.site: Still creating... [10m elapsed]
aws_cloudfront_distribution.site: Creation complete

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

CloudFront propagation note: The distribution takes 8‑12 minutes to propagate globally after the apply finishes. While propagating, the status shows InProgress; it changes to Deployed when ready. The site is accessible only after the status is Deployed.

Deploying Site Content

The Skill read the Terraform outputs for the bucket name and distribution ID, then executed:

# Sync site files
aws s3 sync ./site s3:/// --delete

# Trigger CloudFront cache invalidation
aws cloudfront create-invalidation \
  --distribution-id  \
  --paths '/*'

Output (excerpt):

upload: site/index.html to s3:///index.html
upload: site/styles.css to s3:///styles.css

{
    "Location": "...",
    "Invalidation": {
        "Id": "...",
        "Status": "InProgress"
    }
}

The site was confirmed live at the CloudFront URL.

Verification Checklist

CheckResult
Terraform files generated in terraform/Passed
terraform validate — no errorsPassed
Plan: 4 to create, 0 to destroyPassed
S3 bucket created in af-south-1Passed
CloudFront distribution status: DeployedPassed
Site files served correctlyPassed

Deployment Checks

StepStatus
Synced via AWS S3 syncPassed
CloudFront invalidation triggeredPassed
Site accessible via CloudFront URL in browserPassed

Deployment Summary

The deployment itself was the least stressful part of this project. That is because the three preceding phases did the real work:

  1. Phase 1 – Verify the environment
    No ambiguous tool errors during deployment.

  2. Phase 2 – Load project memory
    The agent knew the architecture, region, and conventions without prompting.

  3. Phase 3 – Define the Skills
    Each step followed the same procedure, with the same checks, as designed.

A well‑structured pipeline is not one that merely handles problems well; it is one that makes certain categories of problem impossible.

Live site:

0 views
Back to Blog

Related posts

Read more »

Travigo

Travel as fast as you speak with Gemini! Where live agents meet immersive storytelling & 3D navigation. This project was created for entering the Gemini Live Ag...

Micro games

Hey Gamers! 👾 As part of the Rapid Games Prototyping module, we are tasked with reviewing a peer's game. The challenge is to analyse a prototype built in just...