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:
2026-07-29 17:07:45 +07:00
commit 57dc91585d
783 changed files with 221743 additions and 0 deletions
@@ -0,0 +1,396 @@
# ─────────────────────────────────────────────────────────────────────────────
# Compute module Container orchestration with blue/green slot support
#
# Provisions an ECS Fargate service with:
# - Main application container (Express + React)
# - MCP sidecar container
# - EFS persistent volume for SQLite
# - Auto-scaling policies
# - Blue/green deployment slot via variable
# ─────────────────────────────────────────────────────────────────────────────
locals {
name_prefix = lower(replace("${var.project_name}-${var.environment}", "_", "-"))
slot_name = "${local.name_prefix}-${var.deployment_slot}"
common_tags = merge(
{
module = "compute"
deployment_slot = var.deployment_slot
},
var.tags,
)
}
# ─────────────────────────────────────────────────────────────────────────────
# ECS Cluster (shared across slots)
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_ecs_cluster" "main" {
name = "${local.name_prefix}-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
configuration {
execute_command_configuration {
logging = "DEFAULT"
}
}
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-cluster"
})
lifecycle {
prevent_destroy = false
}
}
resource "aws_ecs_cluster_capacity_providers" "main" {
cluster_name = aws_ecs_cluster.main.name
capacity_providers = ["FARGATE", "FARGATE_SPOT"]
default_capacity_provider_strategy {
base = 1
weight = 1
capacity_provider = "FARGATE"
}
}
# ─────────────────────────────────────────────────────────────────────────────
# IAM roles
# ─────────────────────────────────────────────────────────────────────────────
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
resource "aws_iam_role" "task_execution" {
name = "${local.slot_name}-task-exec"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}]
})
tags = local.common_tags
}
resource "aws_iam_role_policy_attachment" "task_execution" {
role = aws_iam_role.task_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_iam_role" "task" {
name = "${local.slot_name}-task"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}]
})
tags = local.common_tags
}
# EFS access policy for the task role
resource "aws_iam_role_policy" "task_efs" {
name = "${local.slot_name}-efs-access"
role = aws_iam_role.task.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"elasticfilesystem:ClientMount",
"elasticfilesystem:ClientWrite",
"elasticfilesystem:ClientRootAccess",
]
Resource = "arn:aws:elasticfilesystem:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:file-system/${var.storage_filesystem_id}"
}]
})
}
# ─────────────────────────────────────────────────────────────────────────────
# CloudWatch log group
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_cloudwatch_log_group" "app" {
name = "/ecs/${local.slot_name}"
retention_in_days = 30
tags = local.common_tags
}
# ─────────────────────────────────────────────────────────────────────────────
# Task definition
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_ecs_task_definition" "app" {
family = local.slot_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = tostring(var.cpu)
memory = tostring(var.memory)
execution_role_arn = aws_iam_role.task_execution.arn
task_role_arn = aws_iam_role.task.arn
container_definitions = jsonencode(concat(
[
{
name = "app"
image = var.container_image
essential = true
cpu = var.mcp_container_image != "" ? floor(var.cpu * 0.75) : var.cpu
memory = var.mcp_container_image != "" ? floor(var.memory * 0.75) : var.memory
portMappings = [
{
containerPort = var.app_port
protocol = "tcp"
}
]
environment = [
for k, v in var.environment_variables : {
name = k
value = v
}
]
mountPoints = [
{
sourceVolume = "app-data"
containerPath = "/app/data"
readOnly = false
}
]
healthCheck = {
command = ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:${var.app_port}${var.health_check_path} || exit 1"]
interval = 30
timeout = 5
retries = 3
startPeriod = 60
}
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.app.name
"awslogs-region" = data.aws_region.current.name
"awslogs-stream-prefix" = "app"
}
}
}
],
var.mcp_container_image != "" ? [
{
name = "mcp-sidecar"
image = var.mcp_container_image
essential = false
cpu = floor(var.cpu * 0.25)
memory = floor(var.memory * 0.25)
portMappings = [
{
containerPort = var.mcp_port
protocol = "tcp"
}
]
environment = [
{
name = "NODE_ENV"
value = "production"
},
{
name = "MCP_PORT"
value = tostring(var.mcp_port)
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.app.name
"awslogs-region" = data.aws_region.current.name
"awslogs-stream-prefix" = "mcp"
}
}
}
] : []
))
volume {
name = "app-data"
efs_volume_configuration {
file_system_id = var.storage_filesystem_id
root_directory = "/"
transit_encryption = "ENABLED"
authorization_config {
iam = "ENABLED"
}
}
}
tags = local.common_tags
lifecycle {
create_before_destroy = true
}
}
# ─────────────────────────────────────────────────────────────────────────────
# Target group (registered with LB by the loadbalancer module)
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_lb_target_group" "app" {
name_prefix = substr(var.deployment_slot, 0, 5)
port = var.app_port
protocol = "HTTP"
vpc_id = var.vpc_id
target_type = "ip"
health_check {
enabled = true
path = var.health_check_path
port = "traffic-port"
protocol = "HTTP"
healthy_threshold = 2
unhealthy_threshold = 3
timeout = 5
interval = 30
matcher = "200"
}
stickiness {
type = "lb_cookie"
cookie_duration = 86400
enabled = true
}
deregistration_delay = 60
tags = merge(local.common_tags, {
Name = "${local.slot_name}-tg"
})
lifecycle {
create_before_destroy = true
}
}
# ─────────────────────────────────────────────────────────────────────────────
# ECS Service
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_ecs_service" "app" {
name = local.slot_name
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = var.desired_count
launch_type = "FARGATE"
platform_version = "LATEST"
health_check_grace_period_seconds = 120
enable_execute_command = var.environment != "production"
network_configuration {
subnets = var.private_subnet_ids
security_groups = var.security_group_ids
assign_public_ip = false
}
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = "app"
container_port = var.app_port
}
deployment_configuration {
maximum_percent = 200
minimum_healthy_percent = 100
}
deployment_circuit_breaker {
enable = true
rollback = true
}
tags = local.common_tags
lifecycle {
ignore_changes = [desired_count]
}
}
# ─────────────────────────────────────────────────────────────────────────────
# Auto-scaling
# ─────────────────────────────────────────────────────────────────────────────
resource "aws_appautoscaling_target" "ecs" {
count = var.max_count > 0 ? 1 : 0
max_capacity = var.max_count
min_capacity = var.min_count
resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.app.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
tags = local.common_tags
}
resource "aws_appautoscaling_policy" "cpu" {
count = var.max_count > 0 ? 1 : 0
name = "${local.slot_name}-cpu-scaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs[0].resource_id
scalable_dimension = aws_appautoscaling_target.ecs[0].scalable_dimension
service_namespace = aws_appautoscaling_target.ecs[0].service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
target_value = var.autoscaling_cpu_target
scale_in_cooldown = 300
scale_out_cooldown = 60
}
}
resource "aws_appautoscaling_policy" "memory" {
count = var.max_count > 0 ? 1 : 0
name = "${local.slot_name}-memory-scaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs[0].resource_id
scalable_dimension = aws_appautoscaling_target.ecs[0].scalable_dimension
service_namespace = aws_appautoscaling_target.ecs[0].service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageMemoryUtilization"
}
target_value = var.autoscaling_memory_target
scale_in_cooldown = 300
scale_out_cooldown = 60
}
}