Claude Code Plugins

Community-maintained marketplace

Feedback

Retrieve plan and apply logs from Terraform Cloud runs. Use when examining TFC run output, debugging failed plans/applies, or reviewing infrastructure changes. Requires TFE_TOKEN environment variable.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

created Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time)
modified Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time)
reviewed Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time)
name tfc-run-logs
description Retrieve plan and apply logs from Terraform Cloud runs. Use when examining TFC run output, debugging failed plans/applies, or reviewing infrastructure changes. Requires TFE_TOKEN environment variable.
allowed-tools Bash, Read

Terraform Cloud Run Logs

Retrieve and display plan and/or apply logs from Terraform Cloud runs directly in the terminal.

Prerequisites

# Required environment variables
export TFE_TOKEN="your-api-token"        # User or team token (not organization token)
export TFE_ADDRESS="app.terraform.io"    # Optional, defaults to app.terraform.io

Core Workflow

Get Both Plan and Apply Logs

#!/bin/bash
set -euo pipefail

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="${1:?Usage: $0 <run-id>}"

# Get run with plan and apply relationships
RUN_DATA=$(curl -sf --header "Authorization: Bearer $TOKEN" \
  "$BASE_URL/runs/$RUN_ID?include=plan,apply")

# Extract IDs
PLAN_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.plan.data.id')
APPLY_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.apply.data.id // empty')

# Get and display plan logs
PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN" \
  "$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')

echo "=== PLAN OUTPUT ==="
curl -sf "$PLAN_LOG_URL" | sed 's/\x1b\[[0-9;]*m//g'  # Strip ANSI codes

# Get apply logs if exists
if [ -n "$APPLY_ID" ]; then
  APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN" \
    "$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')

  echo ""
  echo "=== APPLY OUTPUT ==="
  curl -sf "$APPLY_LOG_URL" | sed 's/\x1b\[[0-9;]*m//g'
fi

Get Plan Logs Only

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"

# Get plan ID from run
PLAN_ID=$(curl -sf --header "Authorization: Bearer $TOKEN" \
  "$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.plan.data.id')

# Get log URL and fetch logs
PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN" \
  "$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')

curl -sf "$PLAN_LOG_URL"

Get Apply Logs Only

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"

# Get apply ID from run
APPLY_ID=$(curl -sf --header "Authorization: Bearer $TOKEN" \
  "$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.apply.data.id')

if [ -n "$APPLY_ID" ] && [ "$APPLY_ID" != "null" ]; then
  # Get log URL and fetch logs
  APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN" \
    "$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')

  curl -sf "$APPLY_LOG_URL"
else
  echo "No apply for this run"
fi

Quick One-Liners

Plan Logs (with ANSI colors)

curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | xargs curl -sf

Plan Logs (clean text)

curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | \
  xargs curl -sf | sed 's/\x1b\[[0-9;]*m//g'

Important Notes

  • Log URLs are secrets: Archivist URLs contain embedded authentication - don't log them
  • URLs expire: Log URLs are valid for 25 hours
  • No auth needed for logs: Once you have the archivist URL, no bearer token is required
  • ANSI codes: Logs contain color codes; use sed to strip them for clean output
  • Rate limits: /runs endpoint is limited to 30 requests/minute

Common Errors

404 Not Found

  • Run ID doesn't exist OR you don't have permission
  • TFC returns 404 for both cases (security measure)

401 Unauthorized

  • Token is invalid or expired
  • Organization tokens cannot access run data - use user/team token

No Apply Logs

  • Run may be plan-only, not yet applied, or discarded
  • Check run status first

See Also

  • tfc-run-status: Quick status check for a run
  • tfc-list-runs: List recent runs in a workspace
  • tfc-plan-json: Get structured plan JSON output