feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard. Lanes: a durable unit of parallel agent work, one per working directory, tracked across session restarts. Managed lanes are git worktrees the dashboard provisions and can reset or remove behind a three-check destroy guard and a counted preflight; adopted lanes are directories you already own and are never destroyable. Pipelines: a lane moves through pipeline stages. A stage the agent declares with evidence renders green; a stage inferred from the tool-event stream renders dashed amber and never counts as done. Detection is forward-only within a 30-minute window, and never writes the declared stage. Workspace: one page at /run with a lane grid, the selected lane's pipeline, and a full Claude console behind a disclosure.
This commit is contained in:
@@ -0,0 +1,602 @@
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# OCI Provider – Full implementation for Claude Code Agent Monitor
|
||||
#
|
||||
# Architecture:
|
||||
# VCN → Container Instances (blue/green) → File Storage Service
|
||||
# → Flexible Load Balancer → OCI Monitoring & Notifications
|
||||
#
|
||||
# OCI Container Instances provide a serverless container runtime.
|
||||
# File Storage Service (FSS) delivers NFS for SQLite persistence.
|
||||
# Flexible Load Balancer supports WebSocket, SSL, and weighted backends.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
provider "oci" {
|
||||
region = var.region
|
||||
}
|
||||
|
||||
# ── Data sources ────────────────────────────────────────────────────────────
|
||||
|
||||
data "oci_identity_availability_domains" "ads" {
|
||||
compartment_id = var.compartment_id
|
||||
}
|
||||
|
||||
data "oci_identity_tenancy" "current" {
|
||||
tenancy_id = var.tenancy_id
|
||||
}
|
||||
|
||||
# ── Locals ──────────────────────────────────────────────────────────────────
|
||||
|
||||
locals {
|
||||
name_prefix = lower(replace("${var.project_name}-${var.environment}", "_", "-"))
|
||||
ad_name = data.oci_identity_availability_domains.ads.availability_domains[0].name
|
||||
|
||||
common_tags = {
|
||||
"project" = var.project_name
|
||||
"environment" = var.environment
|
||||
"managed_by" = "terraform"
|
||||
"cloud_provider" = "oci"
|
||||
"repository" = "Claude-Code-Agent-Monitor"
|
||||
}
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# VCN (Virtual Cloud Network)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_core_vcn" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
cidr_blocks = [var.vpc_cidr]
|
||||
display_name = "${local.name_prefix}-vcn"
|
||||
dns_label = replace(substr(local.name_prefix, 0, 15), "-", "")
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
|
||||
lifecycle {
|
||||
prevent_destroy = false
|
||||
}
|
||||
}
|
||||
|
||||
# Internet Gateway
|
||||
resource "oci_core_internet_gateway" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-igw"
|
||||
enabled = true
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
# NAT Gateway
|
||||
resource "oci_core_nat_gateway" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-nat"
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
# Service Gateway
|
||||
resource "oci_core_service_gateway" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-sgw"
|
||||
|
||||
services {
|
||||
service_id = data.oci_core_services.all.services[0].id
|
||||
}
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
data "oci_core_services" "all" {
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["All .* Services In Oracle Services Network"]
|
||||
regex = true
|
||||
}
|
||||
}
|
||||
|
||||
# ── Route tables ────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_core_route_table" "public" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-public-rt"
|
||||
|
||||
route_rules {
|
||||
network_entity_id = oci_core_internet_gateway.main.id
|
||||
destination = "0.0.0.0/0"
|
||||
destination_type = "CIDR_BLOCK"
|
||||
}
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_core_route_table" "private" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-private-rt"
|
||||
|
||||
route_rules {
|
||||
network_entity_id = oci_core_nat_gateway.main.id
|
||||
destination = "0.0.0.0/0"
|
||||
destination_type = "CIDR_BLOCK"
|
||||
}
|
||||
|
||||
route_rules {
|
||||
network_entity_id = oci_core_service_gateway.main.id
|
||||
destination = data.oci_core_services.all.services[0].cidr_block
|
||||
destination_type = "SERVICE_CIDR_BLOCK"
|
||||
}
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
# ── Security lists ──────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_core_security_list" "public" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-public-sl"
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "6" # TCP
|
||||
source = "0.0.0.0/0"
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = 443
|
||||
max = 443
|
||||
}
|
||||
}
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "6"
|
||||
source = "0.0.0.0/0"
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = 80
|
||||
max = 80
|
||||
}
|
||||
}
|
||||
|
||||
egress_security_rules {
|
||||
protocol = "all"
|
||||
destination = "0.0.0.0/0"
|
||||
destination_type = "CIDR_BLOCK"
|
||||
}
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_core_security_list" "private" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
display_name = "${local.name_prefix}-private-sl"
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "6"
|
||||
source = var.vpc_cidr
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = var.app_port
|
||||
max = var.app_port
|
||||
}
|
||||
}
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "6"
|
||||
source = var.vpc_cidr
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = var.mcp_port
|
||||
max = var.mcp_port
|
||||
}
|
||||
}
|
||||
|
||||
# NFS (FSS)
|
||||
ingress_security_rules {
|
||||
protocol = "6"
|
||||
source = var.vpc_cidr
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = 2048
|
||||
max = 2050
|
||||
}
|
||||
}
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "6"
|
||||
source = var.vpc_cidr
|
||||
source_type = "CIDR_BLOCK"
|
||||
tcp_options {
|
||||
min = 111
|
||||
max = 111
|
||||
}
|
||||
}
|
||||
|
||||
ingress_security_rules {
|
||||
protocol = "17" # UDP
|
||||
source = var.vpc_cidr
|
||||
source_type = "CIDR_BLOCK"
|
||||
udp_options {
|
||||
min = 111
|
||||
max = 111
|
||||
}
|
||||
}
|
||||
|
||||
egress_security_rules {
|
||||
protocol = "all"
|
||||
destination = "0.0.0.0/0"
|
||||
destination_type = "CIDR_BLOCK"
|
||||
}
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
# ── Subnets ─────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_core_subnet" "public" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
cidr_block = var.public_subnet_cidrs[0]
|
||||
display_name = "${local.name_prefix}-public"
|
||||
dns_label = "pub"
|
||||
route_table_id = oci_core_route_table.public.id
|
||||
security_list_ids = [oci_core_security_list.public.id]
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_core_subnet" "private" {
|
||||
compartment_id = var.compartment_id
|
||||
vcn_id = oci_core_vcn.main.id
|
||||
cidr_block = var.private_subnet_cidrs[0]
|
||||
display_name = "${local.name_prefix}-private"
|
||||
dns_label = "priv"
|
||||
route_table_id = oci_core_route_table.private.id
|
||||
security_list_ids = [oci_core_security_list.private.id]
|
||||
prohibit_public_ip_on_vnic = true
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# File Storage Service (FSS) – NFS for SQLite
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_file_storage_file_system" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
availability_domain = local.ad_name
|
||||
display_name = "${local.name_prefix}-data"
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
|
||||
lifecycle {
|
||||
prevent_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "oci_file_storage_mount_target" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
availability_domain = local.ad_name
|
||||
subnet_id = oci_core_subnet.private.id
|
||||
display_name = "${local.name_prefix}-mt"
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_file_storage_export_set" "main" {
|
||||
mount_target_id = oci_file_storage_mount_target.main.id
|
||||
display_name = "${local.name_prefix}-exports"
|
||||
max_fs_stat_bytes = var.storage_size_gb * 1073741824 # GiB → bytes
|
||||
}
|
||||
|
||||
resource "oci_file_storage_export" "main" {
|
||||
export_set_id = oci_file_storage_export_set.main.id
|
||||
file_system_id = oci_file_storage_file_system.main.id
|
||||
path = "/appdata"
|
||||
|
||||
export_options {
|
||||
source = var.private_subnet_cidrs[0]
|
||||
access = "READ_WRITE"
|
||||
identity_squash = "NONE"
|
||||
require_privileged_source_port = false
|
||||
}
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Container Instances (Blue / Green)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_container_instances_container_instance" "blue" {
|
||||
compartment_id = var.compartment_id
|
||||
availability_domain = local.ad_name
|
||||
display_name = "${local.name_prefix}-blue"
|
||||
|
||||
shape = "CI.Standard.E4.Flex"
|
||||
shape_config {
|
||||
ocpus = var.cpu / 1000.0
|
||||
memory_in_gbs = var.memory / 1024.0
|
||||
}
|
||||
|
||||
vnics {
|
||||
subnet_id = oci_core_subnet.private.id
|
||||
is_public_ip_assigned = false
|
||||
}
|
||||
|
||||
containers {
|
||||
display_name = "app"
|
||||
image_url = var.app_container_image
|
||||
|
||||
environment_variables = var.environment_variables
|
||||
|
||||
health_checks {
|
||||
health_check_type = "HTTP"
|
||||
port = var.app_port
|
||||
path = var.health_check_path
|
||||
interval_in_seconds = 30
|
||||
timeout_in_seconds = 5
|
||||
}
|
||||
|
||||
resource_config {
|
||||
vcpus_limit = var.cpu / 1000.0
|
||||
memory_limit_in_gbs = var.memory / 1024.0
|
||||
}
|
||||
|
||||
volume_mounts {
|
||||
mount_path = "/app/data"
|
||||
volume_name = "app-data"
|
||||
is_read_only = false
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "containers" {
|
||||
for_each = var.mcp_container_image != "" ? [1] : []
|
||||
content {
|
||||
display_name = "mcp-sidecar"
|
||||
image_url = var.mcp_container_image
|
||||
|
||||
environment_variables = {
|
||||
NODE_ENV = "production"
|
||||
MCP_PORT = tostring(var.mcp_port)
|
||||
}
|
||||
|
||||
resource_config {
|
||||
vcpus_limit = 0.25
|
||||
memory_limit_in_gbs = 0.25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# NOTE: OCI Container Instances only support EMPTYDIR and CONFIGFILE volume
|
||||
# types. For persistent NFS (FSS) storage, mount via the container entrypoint
|
||||
# using the mount target IP from oci_file_storage_mount_target.main, or
|
||||
# migrate to OCI Kubernetes Engine (OKE) which supports NFS PersistentVolumes.
|
||||
volumes {
|
||||
name = "app-data"
|
||||
volume_type = "EMPTYDIR"
|
||||
backing_store = "EPHEMERAL_STORAGE"
|
||||
}
|
||||
|
||||
freeform_tags = merge(local.common_tags, {
|
||||
deployment_slot = "blue"
|
||||
})
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
freeform_tags["last_deployed"],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
resource "oci_container_instances_container_instance" "green" {
|
||||
count = var.active_deployment_slot == "green" || var.green_weight > 0 ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
availability_domain = local.ad_name
|
||||
display_name = "${local.name_prefix}-green"
|
||||
|
||||
shape = "CI.Standard.E4.Flex"
|
||||
shape_config {
|
||||
ocpus = var.cpu / 1000.0
|
||||
memory_in_gbs = var.memory / 1024.0
|
||||
}
|
||||
|
||||
vnics {
|
||||
subnet_id = oci_core_subnet.private.id
|
||||
is_public_ip_assigned = false
|
||||
}
|
||||
|
||||
containers {
|
||||
display_name = "app"
|
||||
image_url = var.app_container_image
|
||||
|
||||
environment_variables = var.environment_variables
|
||||
|
||||
health_checks {
|
||||
health_check_type = "HTTP"
|
||||
port = var.app_port
|
||||
path = var.health_check_path
|
||||
interval_in_seconds = 30
|
||||
timeout_in_seconds = 5
|
||||
}
|
||||
|
||||
resource_config {
|
||||
vcpus_limit = var.cpu / 1000.0
|
||||
memory_limit_in_gbs = var.memory / 1024.0
|
||||
}
|
||||
|
||||
volume_mounts {
|
||||
mount_path = "/app/data"
|
||||
volume_name = "app-data"
|
||||
is_read_only = false
|
||||
}
|
||||
}
|
||||
|
||||
# NOTE: OCI Container Instances only support EMPTYDIR and CONFIGFILE volume
|
||||
# types. See blue instance comment for FSS mounting guidance.
|
||||
volumes {
|
||||
name = "app-data"
|
||||
volume_type = "EMPTYDIR"
|
||||
backing_store = "EPHEMERAL_STORAGE"
|
||||
}
|
||||
|
||||
freeform_tags = merge(local.common_tags, {
|
||||
deployment_slot = "green"
|
||||
})
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Flexible Load Balancer
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_load_balancer_load_balancer" "main" {
|
||||
compartment_id = var.compartment_id
|
||||
display_name = "${local.name_prefix}-lb"
|
||||
shape = "flexible"
|
||||
|
||||
shape_details {
|
||||
minimum_bandwidth_in_mbps = var.environment == "production" ? 100 : 10
|
||||
maximum_bandwidth_in_mbps = var.environment == "production" ? 1000 : 100
|
||||
}
|
||||
|
||||
subnet_ids = [oci_core_subnet.public.id]
|
||||
|
||||
is_private = false
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
|
||||
lifecycle {
|
||||
prevent_destroy = false
|
||||
}
|
||||
}
|
||||
|
||||
# Backend set with health check
|
||||
resource "oci_load_balancer_backend_set" "app" {
|
||||
load_balancer_id = oci_load_balancer_load_balancer.main.id
|
||||
name = "${local.name_prefix}-app-bs"
|
||||
policy = "ROUND_ROBIN"
|
||||
|
||||
session_persistence_configuration {
|
||||
cookie_name = "CCAM_SESSION"
|
||||
is_secure = true
|
||||
}
|
||||
|
||||
health_checker {
|
||||
protocol = "HTTP"
|
||||
port = var.app_port
|
||||
url_path = var.health_check_path
|
||||
return_code = 200
|
||||
interval_ms = var.health_check_interval * 1000
|
||||
timeout_in_millis = var.health_check_timeout * 1000
|
||||
retries = var.health_check_unhealthy_threshold
|
||||
}
|
||||
}
|
||||
|
||||
# Blue backend
|
||||
resource "oci_load_balancer_backend" "blue" {
|
||||
load_balancer_id = oci_load_balancer_load_balancer.main.id
|
||||
backendset_name = oci_load_balancer_backend_set.app.name
|
||||
ip_address = oci_container_instances_container_instance.blue.vnics[0].private_ip
|
||||
port = var.app_port
|
||||
weight = var.blue_weight
|
||||
}
|
||||
|
||||
# Green backend
|
||||
resource "oci_load_balancer_backend" "green" {
|
||||
count = length(oci_container_instances_container_instance.green) > 0 ? 1 : 0
|
||||
|
||||
load_balancer_id = oci_load_balancer_load_balancer.main.id
|
||||
backendset_name = oci_load_balancer_backend_set.app.name
|
||||
ip_address = oci_container_instances_container_instance.green[0].vnics[0].private_ip
|
||||
port = var.app_port
|
||||
weight = var.green_weight
|
||||
}
|
||||
|
||||
# HTTP listener
|
||||
resource "oci_load_balancer_listener" "http" {
|
||||
load_balancer_id = oci_load_balancer_load_balancer.main.id
|
||||
name = "${local.name_prefix}-http"
|
||||
default_backend_set_name = oci_load_balancer_backend_set.app.name
|
||||
port = 80
|
||||
protocol = "HTTP"
|
||||
|
||||
connection_configuration {
|
||||
idle_timeout_in_seconds = 300 # WebSocket support
|
||||
}
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# OCI Monitoring – Alarms and Notifications
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
resource "oci_ons_notification_topic" "alerts" {
|
||||
count = var.enable_monitoring ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
name = "${local.name_prefix}-alerts"
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_ons_subscription" "email" {
|
||||
count = var.enable_monitoring && var.alert_email != "" ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
topic_id = oci_ons_notification_topic.alerts[0].id
|
||||
protocol = "EMAIL"
|
||||
endpoint = var.alert_email
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_monitoring_alarm" "lb_unhealthy" {
|
||||
count = var.enable_monitoring ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
display_name = "${local.name_prefix}-unhealthy-backends"
|
||||
namespace = "oci_lbaas"
|
||||
query = "UnHealthyBackendCount[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.max() > 0"
|
||||
severity = "CRITICAL"
|
||||
is_enabled = true
|
||||
pending_duration = "PT5M"
|
||||
|
||||
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
|
||||
|
||||
message_format = "ONS_OPTIMIZED"
|
||||
body = "Unhealthy backends detected for ${local.name_prefix} load balancer"
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_monitoring_alarm" "lb_5xx" {
|
||||
count = var.enable_monitoring ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
display_name = "${local.name_prefix}-high-5xx"
|
||||
namespace = "oci_lbaas"
|
||||
query = "HttpResponses5xx[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.sum() > 10"
|
||||
severity = "WARNING"
|
||||
is_enabled = true
|
||||
pending_duration = "PT5M"
|
||||
|
||||
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "oci_monitoring_alarm" "high_latency" {
|
||||
count = var.enable_monitoring ? 1 : 0
|
||||
|
||||
compartment_id = var.compartment_id
|
||||
display_name = "${local.name_prefix}-high-latency"
|
||||
namespace = "oci_lbaas"
|
||||
query = "BackendTimeFirstByte[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.percentile(0.99) > 2000"
|
||||
severity = "WARNING"
|
||||
is_enabled = true
|
||||
pending_duration = "PT5M"
|
||||
|
||||
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
|
||||
|
||||
freeform_tags = local.common_tags
|
||||
}
|
||||
Reference in New Issue
Block a user