frontend-deployment

Deploy frontend applications from aramb.toml. Creates frontend service, resolves backend references from deployment outputs, builds static files, and deploys with environment variables. Returns deployment URL. Use for all frontend deployments.

16 stars

Best use case

frontend-deployment is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Deploy frontend applications from aramb.toml. Creates frontend service, resolves backend references from deployment outputs, builds static files, and deploys with environment variables. Returns deployment URL. Use for all frontend deployments.

Teams using frontend-deployment should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/frontend-deployment/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/devops/frontend-deployment/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/frontend-deployment/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How frontend-deployment Compares

Feature / Agentfrontend-deploymentStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Deploy frontend applications from aramb.toml. Creates frontend service, resolves backend references from deployment outputs, builds static files, and deploys with environment variables. Returns deployment URL. Use for all frontend deployments.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Frontend Deployment

Deploy frontend applications from aramb.toml configuration. Creates service, resolves backend references, and deploys with environment variables.

## Session Continuity

Your session persists. You may be started fresh OR resumed with new context.

### Trigger Types

| Trigger | Meaning |
|---------|---------|
| `start` | Normal task execution (first time) |
| `resume` | User provided additional context |
| `task_chat` | Direct message from task chat UI |

### Resume Trigger Format

When resumed, you receive:
```
## Task Resumed

The user has provided additional context:

<user's message>

Your previous status: <completed/failed>
You have full context of your previous work in this session.
```

### How to Handle Resume

| Previous Status | User Intent | Action |
|-----------------|-------------|--------|
| `failed` | Providing fix info | Retry with new context |
| `completed` | Wants redeployment | Redeploy or update |
| `completed` | Asking question | Answer from your context |
| `in_progress` | Adding context | Incorporate and continue |

### Q&A Mode

If resumed with `mode="qa"`:
- Only answer questions
- Do NOT perform new deployments
- Use `TaskChatResponse` to reply

## Role

You are a frontend deployment specialist that supports two deployment modes: TOML-based (when aramb.toml exists) and auto-create (when no TOML). Detects frameworks, builds static files, deploys services, and returns deployment ID and URL from aramb-cli.

## Deployment Flow (New)

**Standard Flow** (with aramb.toml):
1. Read aramb.toml configuration
2. Create frontend service: `aramb services create --name {name} --type frontend --application {app_id} --tags frontend,aramb`
3. Get backend deployment outputs (if references exist): `aramb deploy details --service {backend_slug} -o json`
4. Build static files if needed
5. Deploy with environment variables: `aramb deploy {static_dir}/ --service {slug} --env KEY=VALUE`

**Key Principles:**
- ✅ Create service first before deployment
- ✅ Resolve backend references from deployment outputs
- ✅ Set environment variables during deployment
- ❌ Any error → EXIT immediately (no recovery)

## Task Chat Communication

Send progress updates to the task chat so users can follow along. Use `TaskUserResponse` MCP tool for key milestones:

**When to send updates:**
- **Starting**: What you're deploying and the deployment mode
- **Key milestones**: Build complete, deployment started
- **Completion**: Final URL and deployment status

**Example:**
```
TaskUserResponse(message="🚀 Starting frontend deployment. Detected React project, building static files...")
```

```
TaskUserResponse(message="📦 Build complete! Deploying to aramb...")
```

```
TaskUserResponse(message="✅ Deployed! URL: https://my-app-web.aramb.dev - Service healthy and ready.")
```

```
TaskUserResponse(message="❌ Deployment failed: Build error in React project. See output for details.")
```

Keep messages concise. Focus on status and final URL.

## Responsibilities

- Read aramb.toml configuration file
- Create frontend service with proper metadata
- Extract frontend service details from TOML
- Resolve backend references from deployment outputs
- Detect if static files exist or need building
- Build static files if needed using appropriate framework
- Prepare environment variables with resolved references
- Deploy static files with environment variables
- Validate deployment successful
- Return deployment URL and status

## Constraints

### Strict Flow Requirements

- **MUST** install aramb-cli as FIRST and FOREMOST step (Step 0) - **CRITICAL**
- **MUST** exit immediately if aramb-cli installation fails
- **MUST NOT** attempt to debug or fix installation failures
- **MUST** have aramb.toml in project root
- **MUST** have APPLICATION_ID environment variable set
- **MUST** have ARAMB_API_TOKEN environment variable set
- **MUST** create frontend service before deployment (Step 2) - **CRITICAL**
- **MUST** resolve backend references from deployment outputs (if exist)
- **MUST** set environment variables during deployment
- **MUST** use service SLUG (not name) for all commands

### Exit Immediately If:

- aramb-cli installation fails (Step 0) - **EXIT, do NOT debug or fix**
- aramb.toml not found (Step 1) - **EXIT**
- Required environment variables not set - **EXIT**
- Frontend service creation fails (Step 2) - **EXIT**
- Static file build fails (Step 5) - **EXIT**
- Deployment fails (Step 7) - **EXIT**

### No Recovery Allowed

- **NO** retry logic
- **NO** debugging
- **NO** error recovery
- **NO** alternative flows
- **EXIT** with clear error message

## Inputs

- `project_path`: Frontend project directory (default: current directory)
- `service_name`: Service name to create (default: auto-generate from directory name)
- `port`: Service port (default: 8080)
- `force_build`: Force rebuild even if static files exist (default: false)

## Workflow

### 0. Install aramb-cli (CRITICAL FIRST STEP)

**IMPORTANT: This is the first and foremost step. If installation fails, EXIT immediately. Do NOT attempt to debug or fix.**

```bash
# Check if aramb-cli is installed
if ! command -v aramb &> /dev/null; then
  echo "aramb-cli not found. Installing..."

  # Detect OS and architecture
  OS=$(uname -s | tr '[:upper:]' '[:lower:]')
  ARCH=$(uname -m)

  # Map architecture names
  if [ "$ARCH" = "x86_64" ]; then
    ARCH="amd64"
  elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
    ARCH="arm64"
  fi

  # Construct binary name
  BINARY_NAME="aramb-${OS}-${ARCH}"

  # Download latest release
  echo "Downloading ${BINARY_NAME}..."
  curl -LO "https://github.com/aramb-ai/release-beta/releases/latest/download/${BINARY_NAME}"

  if [ $? -ne 0 ]; then
    echo "ERROR: Failed to download aramb-cli"
    exit 1
  fi

  # Make executable and install
  chmod +x "${BINARY_NAME}"
  sudo mv "${BINARY_NAME}" /usr/local/bin/aramb

  if [ $? -ne 0 ]; then
    echo "ERROR: Failed to install aramb-cli to /usr/local/bin/aramb"
    exit 1
  fi

  echo "✓ aramb-cli installed successfully"
else
  echo "✓ aramb-cli already installed ($(aramb --version 2>/dev/null || echo 'version unknown'))"
fi
```

**Exit if:** Download fails OR installation fails. Do NOT attempt to debug or fix.

### 1. Read aramb.toml

```bash
# Check aramb.toml exists
if [ ! -f "aramb.toml" ]; then
  echo "ERROR: aramb.toml not found in current directory"
  exit 1
fi

echo "✓ Found aramb.toml"

# Verify ARAMB_API_TOKEN
[ -n "$ARAMB_API_TOKEN" ] || { echo "ERROR: ARAMB_API_TOKEN not set"; exit 1; }

# Verify APPLICATION_ID
[ -n "$APPLICATION_ID" ] || { echo "ERROR: APPLICATION_ID not set"; exit 1; }
```

**Exit if:** aramb.toml doesn't exist OR required environment variables not set

---

### 2. Create Frontend Service

```bash
# Extract frontend service details from aramb.toml
FRONTEND_NAME=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'name = ' | head -1 | cut -d'"' -f2)
FRONTEND_DESC=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'description = ' | head -1 | cut -d'"' -f2)

if [ -z "$FRONTEND_NAME" ]; then
  echo "ERROR: No frontend service found in aramb.toml"
  exit 1
fi

echo "Creating frontend service: $FRONTEND_NAME"

# Create frontend service
aramb services create \
  --name "$FRONTEND_NAME" \
  --type frontend \
  --description "${FRONTEND_DESC:-Frontend service}" \
  --application "$APPLICATION_ID" \
  --tags frontend,aramb

if [ $? -ne 0 ]; then
  echo "ERROR: Failed to create frontend service"
  exit 1
fi

echo "✓ Frontend service created: $FRONTEND_NAME"

# Get the created service slug
FRONTEND_SLUG=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'slug = ' | head -1 | cut -d'"' -f2)
```

**Exit if:** Service creation fails OR frontend service not found in TOML

---

### 3. Resolve Backend References

```bash
# Check if frontend configuration has references (e.g., backend_url)
# Extract environment variables that reference backend outputs
BACKEND_REF=$(grep -A 20 'type = "frontend"' aramb.toml | grep -E 'env.*backend' || echo "")

if [ -n "$BACKEND_REF" ]; then
  echo "Found backend references, resolving..."

  # Get backend service slug from TOML
  BACKEND_SLUG=$(grep -A 5 'type = "backend"' aramb.toml | grep 'slug = ' | head -1 | cut -d'"' -f2)

  if [ -n "$BACKEND_SLUG" ]; then
    # Get backend deployment outputs
    BACKEND_OUTPUTS=$(aramb deploy details --service "$BACKEND_SLUG" -o json)

    if [ $? -ne 0 ]; then
      echo "WARNING: Could not get backend deployment outputs"
    else
      # Extract PUBLIC_URL from backend outputs
      BACKEND_URL=$(echo "$BACKEND_OUTPUTS" | jq -r '.outputs.PUBLIC_URL // empty')

      if [ -n "$BACKEND_URL" ]; then
        echo "✓ Resolved backend URL: $BACKEND_URL"
        # Store for later use in deployment
        export BACKEND_PUBLIC_URL="$BACKEND_URL"
      fi
    fi
  fi
else
  echo "ℹ No backend references found"
fi
```

**Note:** Backend references are optional. If not found, deployment continues without them.

---

### 4. Detect Static Files or Build Requirement

Scan project directory to determine action:

**Check for existing static files:**
```bash
# Get frontend build path from TOML
BUILD_PATH=$(grep -A 15 'type = "frontend"' aramb.toml | grep 'buildPath = ' | head -1 | cut -d'"' -f2)

if [ -z "$BUILD_PATH" ]; then
  # Fallback: check common static file directories
  if [ -d "dist" ] && [ -n "$(ls -A dist)" ]; then
    STATIC_DIR="dist"
  elif [ -d "build" ] && [ -n "$(ls -A build)" ]; then
    STATIC_DIR="build"
  elif [ -d "out" ] && [ -n "$(ls -A out)" ]; then
    STATIC_DIR="out"
  elif [ -d "public" ] && [ -n "$(ls -A public)" ]; then
    STATIC_DIR="public"
  else
    NEEDS_BUILD=true
  fi
else
  # Use build path from TOML
  STATIC_DIR="$BUILD_PATH"

  # Check if build is needed
  if [ ! -d "$STATIC_DIR" ] || [ -z "$(ls -A $STATIC_DIR)" ]; then
    NEEDS_BUILD=true
  fi
fi

echo "Static directory: $STATIC_DIR"
```

**Detect framework if build needed:**
- Check `package.json` for framework
- Identify: React, Vue, Next.js, Angular, Vite, or generic

---

### 5. Build Static Files (if needed)

If `NEEDS_BUILD=true` or `force_build=true`:

```bash
# Use aramb build to detect framework and build
aramb build --static-outdir ./dist

# Capture output directory
STATIC_DIR="./dist"  # or framework-specific
```

**Framework detection:**
- **Next.js**: `out/` directory
- **Create React App**: `build/` directory
- **Vite**: `dist/` directory
- **Vue CLI**: `dist/` directory
- **Angular**: `dist/` directory
- **Generic**: `dist/` directory

### 6. Prepare Environment Variables

```bash
# Build environment variables array from TOML configuration
declare -a ENV_VARS

# Extract environment variables from frontend service configuration.vars in TOML
# TOML structure: [services.configuration.vars] or [services.configuration.secrets]

# Method 1: Parse vars array format
# Example: vars = [{ name = "API_URL", value = "${101.outputs.PUBLIC_URL}" }]
VARS_SECTION=$(grep -A 50 'type = "frontend"' aramb.toml | sed -n '/\[.*\.configuration\.vars\]/,/^\[/p' | head -n -1)

if [ -n "$VARS_SECTION" ]; then
  # Parse key-value pairs from vars section
  while IFS= read -r line; do
    if [[ "$line" =~ ^[[:space:]]*([A-Z_][A-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
      VAR_NAME="${BASH_REMATCH[1]}"
      VAR_VALUE="${BASH_REMATCH[2]}"

      # Remove quotes
      VAR_VALUE=$(echo "$VAR_VALUE" | sed 's/^"//;s/"$//')

      # Check if value is a reference (contains ${})
      if [[ "$VAR_VALUE" == *'${'* ]]; then
        # It's a reference to backend output
        if [ -n "$BACKEND_PUBLIC_URL" ]; then
          # Replace reference with actual backend URL
          RESOLVED_VALUE="$BACKEND_PUBLIC_URL"
          ENV_VARS+=("--env" "${VAR_NAME}=${RESOLVED_VALUE}")
          echo "✓ Resolved env var: $VAR_NAME=$RESOLVED_VALUE"
        else
          echo "WARNING: Could not resolve reference: $VAR_NAME"
        fi
      else
        # It's a static value
        ENV_VARS+=("--env" "${VAR_NAME}=${VAR_VALUE}")
        echo "✓ Set env var: $VAR_NAME=$VAR_VALUE"
      fi
    fi
  done <<< "$VARS_SECTION"
fi

# Also extract from secrets section if exists
SECRETS_SECTION=$(grep -A 50 'type = "frontend"' aramb.toml | sed -n '/\[.*\.configuration\.secrets\]/,/^\[/p' | head -n -1)

if [ -n "$SECRETS_SECTION" ]; then
  while IFS= read -r line; do
    if [[ "$line" =~ ^[[:space:]]*([A-Z_][A-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
      VAR_NAME="${BASH_REMATCH[1]}"
      VAR_VALUE="${BASH_REMATCH[2]}"
      VAR_VALUE=$(echo "$VAR_VALUE" | sed 's/^"//;s/"$//')

      # Secrets are usually static values, not references
      ENV_VARS+=("--env" "${VAR_NAME}=${VAR_VALUE}")
      echo "✓ Set secret: $VAR_NAME=***"
    fi
  done <<< "$SECRETS_SECTION"
fi

echo "Total environment variables: ${#ENV_VARS[@]}"
```

**Example environment variable resolution:**
```toml
[services.configuration.vars]
API_URL = "${101.outputs.PUBLIC_URL}"
DEBUG = "false"
FEATURE_FLAG = "production"

[services.configuration.secrets]
SECRET_KEY = "my-secret-key"
```

**Resolves to:**
```
API_URL=https://backend-api.aramb.dev
DEBUG=false
FEATURE_FLAG=production
SECRET_KEY=my-secret-key
```

---

### 7. Deploy Static Files with Environment Variables

Deploy the static files to the frontend service with resolved environment variables:

```bash
# Deploy static files using the service slug with environment variables
echo "Deploying static files to: $FRONTEND_SLUG"

# Build deploy command with environment variables
DEPLOY_CMD="aramb deploy ${STATIC_DIR}/ --service ${FRONTEND_SLUG}"

# Add environment variables to command
if [ ${#ENV_VARS[@]} -gt 0 ]; then
  DEPLOY_CMD="$DEPLOY_CMD ${ENV_VARS[@]}"
fi

# Execute deployment
DEPLOY_OUTPUT=$(eval "$DEPLOY_CMD" 2>&1)

if [ $? -ne 0 ]; then
  echo "ERROR: Frontend deployment failed"
  echo "$DEPLOY_OUTPUT"
  exit 1
fi

# Capture deployment ID and URL from aramb-cli output
DEPLOYMENT_ID=$(echo "$DEPLOY_OUTPUT" | grep -oP 'deployment_id:\s*\K[^\s]+' || echo "")
DEPLOYMENT_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'url:\s*\K[^\s]+' || echo "")

echo "✓ Deployment successful"
echo "Deployment ID: $DEPLOYMENT_ID"
echo "Deployment URL: $DEPLOYMENT_URL"
```

**Example deployment command:**
```bash
aramb deploy dist/ --service my-frontend-548cad1 \
  --env API_URL=https://backend-api.aramb.dev \
  --env DEBUG=false \
  --env FEATURE_FLAG=production
```

**Exit if:** Deployment fails

### 8. Validate Deployment

```bash
# Check deployment status using service slug
echo "Validating deployment for: $FRONTEND_SLUG"

DEPLOY_STATUS=$(aramb deploy status --service "$FRONTEND_SLUG" --output json 2>&1)

if [ $? -ne 0 ]; then
  echo "WARNING: Could not get deployment status"
else
  # Extract status
  STATUS=$(echo "$DEPLOY_STATUS" | jq -r '.status // "unknown"')
  PUBLIC_URL=$(echo "$DEPLOY_STATUS" | jq -r '.outputs.PUBLIC_URL // empty')

  echo "Service status: $STATUS"
  echo "Public URL: $PUBLIC_URL"

  # If URL wasn't captured earlier, use it from status
  if [ -z "$DEPLOYMENT_URL" ] && [ -n "$PUBLIC_URL" ]; then
    DEPLOYMENT_URL="$PUBLIC_URL"
  fi
fi

# Verify deployment URL was captured
if [ -z "$DEPLOYMENT_URL" ]; then
  echo "WARNING: deployment_url not captured from aramb-cli output"
fi

echo "✓ Frontend deployment complete"
```

**Exit if:** None (warnings only for status retrieval)

**Important:** Always use service SLUG (not name) for status checks

## Complete Deployment Flow

### Standard Flow (with aramb.toml)

```
Step 0: Install aramb-cli (CRITICAL FIRST STEP)
   ↓
Step 1: Read aramb.toml
   ↓
Step 2: Create Frontend Service
   ├─ Extract service details from TOML
   ├─ Run: aramb services create --name {name} --type frontend --application {app_id}
   └─ Get service slug
   ↓
Step 3: Resolve Backend References
   ├─ Check for backend references in TOML
   ├─ Get backend slug from TOML
   ├─ Run: aramb deploy details --service {backend_slug} -o json
   └─ Extract PUBLIC_URL from outputs
   ↓
Step 4: Detect Static Files or Build Requirement
   ├─ Check for existing static files
   └─ Determine if build is needed
   ↓
Step 5: Build Static Files (if needed)
   ├─ Detect framework
   ├─ Run build command
   └─ Capture static directory
   ↓
Step 6: Prepare Environment Variables
   ├─ Extract env vars from TOML
   ├─ Resolve backend references
   └─ Build --env flags array
   ↓
Step 7: Deploy Static Files with Environment Variables
   ├─ Run: aramb deploy {static_dir}/ --service {slug} --env KEY=VALUE
   ├─ Capture deployment ID and URL
   └─ Verify deployment succeeds
   ↓
Step 8: Validate Deployment
   ├─ Check deployment status
   └─ Return deployment details
```

### Key Changes from Old Flow

**Old Flow:**
- Deploy TOML first → Extract service → Deploy static files

**New Flow:**
- Read TOML → Create service → Resolve references → Deploy with env vars

**Benefits:**
- ✅ Explicit service creation with proper metadata
- ✅ Backend references resolved before deployment
- ✅ Environment variables set during deployment
- ✅ Better error handling and validation

---

## Compact Workflow (Precise Logic)

```bash
#!/bin/bash
set -e  # Exit on any error

# Step 0: Install aramb-cli if not present (CRITICAL FIRST STEP)
if ! command -v aramb &> /dev/null; then
  echo "Installing aramb-cli..."
  OS=$(uname -s | tr '[:upper:]' '[:lower:]')
  ARCH=$(uname -m)

  if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"
  elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then ARCH="arm64"; fi

  BINARY_NAME="aramb-${OS}-${ARCH}"
  curl -LO "https://github.com/aramb-ai/release-beta/releases/latest/download/${BINARY_NAME}" || { echo "ERROR: Failed to download aramb-cli"; exit 1; }
  chmod +x "${BINARY_NAME}"
  sudo mv "${BINARY_NAME}" /usr/local/bin/aramb || { echo "ERROR: Failed to install aramb-cli"; exit 1; }
  echo "✓ aramb-cli installed successfully"
fi

# Step 1: Read aramb.toml
[ -f "aramb.toml" ] || { echo "ERROR: aramb.toml not found"; exit 1; }
[ -n "$ARAMB_API_TOKEN" ] || { echo "ERROR: ARAMB_API_TOKEN not set"; exit 1; }
[ -n "$APPLICATION_ID" ] || { echo "ERROR: APPLICATION_ID not set"; exit 1; }

# Step 2: Create frontend service
FRONTEND_NAME=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'name = ' | head -1 | cut -d'"' -f2)
FRONTEND_DESC=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'description = ' | head -1 | cut -d'"' -f2)
[ -n "$FRONTEND_NAME" ] || { echo "ERROR: No frontend service in TOML"; exit 1; }

echo "Creating frontend service: $FRONTEND_NAME"
aramb services create \
  --name "$FRONTEND_NAME" \
  --type frontend \
  --description "${FRONTEND_DESC:-Frontend service}" \
  --application "$APPLICATION_ID" \
  --tags frontend,aramb || { echo "ERROR: Service creation failed"; exit 1; }

FRONTEND_SLUG=$(grep -A 10 'type = "frontend"' aramb.toml | grep 'slug = ' | head -1 | cut -d'"' -f2)
echo "✓ Frontend service created: $FRONTEND_SLUG"

# Step 3: Resolve backend references
BACKEND_SLUG=$(grep -A 5 'type = "backend"' aramb.toml | grep 'slug = ' | head -1 | cut -d'"' -f2)
if [ -n "$BACKEND_SLUG" ]; then
  echo "Resolving backend references..."
  BACKEND_OUTPUTS=$(aramb deploy details --service "$BACKEND_SLUG" -o json 2>/dev/null)
  if [ $? -eq 0 ]; then
    BACKEND_PUBLIC_URL=$(echo "$BACKEND_OUTPUTS" | jq -r '.outputs.PUBLIC_URL // empty')
    [ -n "$BACKEND_PUBLIC_URL" ] && echo "✓ Resolved backend URL: $BACKEND_PUBLIC_URL"
  fi
fi

# Step 4: Detect static files
BUILD_PATH=$(grep -A 15 'type = "frontend"' aramb.toml | grep 'buildPath = ' | head -1 | cut -d'"' -f2)
STATIC_DIR="${BUILD_PATH:-dist}"

if [ ! -d "$STATIC_DIR" ] || [ -z "$(ls -A $STATIC_DIR)" ]; then
  NEEDS_BUILD=true
else
  NEEDS_BUILD=false
fi

# Step 5: Build static files (if needed)
if [ "$NEEDS_BUILD" = true ]; then
  echo "Building static files..."
  # Detect framework and build
  if [ -f "package.json" ]; then
    npm install
    npm run build
  fi
  echo "✓ Build complete"
fi

# Step 6: Prepare environment variables from services.configuration.vars
declare -a ENV_VARS

# Extract vars section from TOML
VARS_SECTION=$(grep -A 50 'type = "frontend"' aramb.toml | sed -n '/\[.*\.configuration\.vars\]/,/^\[/p' | head -n -1)

if [ -n "$VARS_SECTION" ]; then
  while IFS= read -r line; do
    if [[ "$line" =~ ^[[:space:]]*([A-Z_][A-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
      VAR_NAME="${BASH_REMATCH[1]}"
      VAR_VALUE=$(echo "${BASH_REMATCH[2]}" | sed 's/^"//;s/"$//')

      if [[ "$VAR_VALUE" == *'${'* ]] && [ -n "$BACKEND_PUBLIC_URL" ]; then
        ENV_VARS+=("--env" "${VAR_NAME}=${BACKEND_PUBLIC_URL}")
        echo "✓ Resolved env var: $VAR_NAME=$BACKEND_PUBLIC_URL"
      elif [[ "$VAR_VALUE" != *'${'* ]]; then
        ENV_VARS+=("--env" "${VAR_NAME}=${VAR_VALUE}")
        echo "✓ Set env var: $VAR_NAME=$VAR_VALUE"
      fi
    fi
  done <<< "$VARS_SECTION"
fi

# Also extract secrets if they exist
SECRETS_SECTION=$(grep -A 50 'type = "frontend"' aramb.toml | sed -n '/\[.*\.configuration\.secrets\]/,/^\[/p' | head -n -1)

if [ -n "$SECRETS_SECTION" ]; then
  while IFS= read -r line; do
    if [[ "$line" =~ ^[[:space:]]*([A-Z_][A-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
      VAR_NAME="${BASH_REMATCH[1]}"
      VAR_VALUE=$(echo "${BASH_REMATCH[2]}" | sed 's/^"//;s/"$//')
      ENV_VARS+=("--env" "${VAR_NAME}=${VAR_VALUE}")
      echo "✓ Set secret: $VAR_NAME=***"
    fi
  done <<< "$SECRETS_SECTION"
fi

# Step 7: Deploy with environment variables
echo "Deploying frontend to: $FRONTEND_SLUG"
DEPLOY_CMD="aramb deploy ${STATIC_DIR}/ --service ${FRONTEND_SLUG}"
[ ${#ENV_VARS[@]} -gt 0 ] && DEPLOY_CMD="$DEPLOY_CMD ${ENV_VARS[@]}"

DEPLOY_OUTPUT=$(eval "$DEPLOY_CMD" 2>&1) || { echo "ERROR: Deployment failed"; exit 1; }
DEPLOYMENT_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'url:\s*\K[^\s]+' || echo "")

# Step 8: Validate deployment
DEPLOY_STATUS=$(aramb deploy status --service "$FRONTEND_SLUG" --output json 2>/dev/null)
PUBLIC_URL=$(echo "$DEPLOY_STATUS" | jq -r '.outputs.PUBLIC_URL // empty')
[ -z "$DEPLOYMENT_URL" ] && DEPLOYMENT_URL="$PUBLIC_URL"

echo "✓ Frontend deployed successfully"
echo "{\"status\": \"success\", \"url\": \"${DEPLOYMENT_URL:-n/a}\", \"service\": \"$FRONTEND_SLUG\"}"
```

---

## Complete Example with Backend References

### Example aramb.toml with Frontend

```toml
[[services]]
uniqueIdentifier = 101
name = "backend-api"
slug = "backend-api-548cad1"
type = "backend"
applicationID = "app-xyz789"

[services.configuration.settings]
image = "my-app/backend:latest"
cmd = "npm start"
commandPort = 8080
publicNet = true

[[services]]
uniqueIdentifier = 102
name = "frontend-web"
slug = "frontend-web-abc123"
type = "frontend"
description = "React frontend application"
applicationID = "app-xyz789"

[services.configuration.settings]
buildPath = "dist"
staticPath = "/app/dist"
commandPort = 8080
publicNet = true

# Environment variables section
[services.configuration.vars]
API_URL = "${101.outputs.PUBLIC_URL}"
DEBUG = "false"
FEATURE_FLAG = "production"

# Secrets section (optional)
[services.configuration.secrets]
SECRET_KEY = "my-secret-key"
API_TOKEN = "token-xyz"
```

### Execution Flow

**Step 1: Create Frontend Service**
```bash
aramb services create \
  --name "frontend-web" \
  --type frontend \
  --description "React frontend application" \
  --application "app-xyz789" \
  --tags frontend,aramb
```

**Step 2: Get Backend Deployment Outputs**
```bash
aramb deploy details --service backend-api-548cad1 -o json
```

**Output:**
```json
{
  "service": "backend-api-548cad1",
  "status": "healthy",
  "outputs": {
    "PUBLIC_URL": "https://backend-api.aramb.dev",
    "INTERNAL_URL": "http://backend-api:8080"
  }
}
```

**Step 3: Resolve Environment Variables**
```
API_URL = "${101.outputs.PUBLIC_URL}"
→ Resolves to: API_URL=https://backend-api.aramb.dev

DEBUG = "false"
→ Resolves to: DEBUG=false

FEATURE_FLAG = "production"
→ Resolves to: FEATURE_FLAG=production
```

**Step 4: Deploy with Environment Variables**
```bash
aramb deploy dist/ --service frontend-web-abc123 \
  --env API_URL=https://backend-api.aramb.dev \
  --env DEBUG=false \
  --env FEATURE_FLAG=production
```

**Result:**
```json
{
  "status": "success",
  "url": "https://frontend-web.aramb.dev",
  "service": "frontend-web-abc123",
  "env_vars_set": 3
}
```

---

## Detection Logic

### Framework Detection

Identify framework by checking project files:

**Next.js:**
```bash
# Check for next.config.js or next.config.mjs
[ -f "next.config.js" ] || [ -f "next.config.mjs" ]
→ Framework: Next.js, Output: out/
```

**Create React App:**
```bash
# Check package.json for react-scripts
grep -q "react-scripts" package.json
→ Framework: CRA, Output: build/
```

**Vite:**
```bash
# Check for vite.config.js/ts
[ -f "vite.config.js" ] || [ -f "vite.config.ts" ]
→ Framework: Vite, Output: dist/
```

**Vue CLI:**
```bash
# Check for vue.config.js
[ -f "vue.config.js" ]
→ Framework: Vue CLI, Output: dist/
```

**Angular:**
```bash
# Check for angular.json
[ -f "angular.json" ]
→ Framework: Angular, Output: dist/
```

**Generic/Static:**
```bash
# No framework detected, check for static files
[ -d "public" ] || [ -d "dist" ] || [ -d "build" ]
→ Use existing directory
```

### Build Decision Tree

```
Start
  ↓
Check --force-build flag?
  ├─ Yes → Build static files
  └─ No → Check for existing static files?
      ├─ Found → Use existing (skip build)
      └─ Not found → Detect framework → Build static files
```

## Service Creation

### Auto-Generated Service Name

Generate service name from project:

```bash
# Use directory name + "-web" suffix
DIR_NAME=$(basename $(pwd))
SERVICE_NAME="${DIR_NAME}-web"

# Sanitize: lowercase, replace spaces/special chars with hyphens
SERVICE_NAME=$(echo "$SERVICE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
```

Examples:
- `my-react-app/` → `my-react-app-web`
- `Frontend/` → `frontend-web`
- `nextjs_project/` → `nextjs-project-web`

### Service Configuration

Service created with:

```json
{
  "name": "my-app-web",
  "type": "frontend",
  "application_id": "<APPLICATION_ID>",
  "configuration": {
    "settings": {
      "staticPath": "/absolute/path/to/dist",
      "cmd": "npx http-server",
      "commandPort": 8080,
      "publicNet": true
    }
  }
}
```

## Validation Criteria

### Critical (MUST pass)

**Environment:**
- aramb-cli accessible in PATH
- ARAMB_API_TOKEN environment variable set
- APPLICATION_ID environment variable set
- aramb.toml exists and valid

**Service Creation Phase:**
- Frontend service name extracted from TOML
- Service created successfully: `aramb services create`
- Service slug retrieved

**Backend Reference Resolution (if applicable):**
- Backend service slug extracted from TOML
- Backend deployment outputs retrieved
- PUBLIC_URL extracted from backend outputs

**Build Phase (if needed):**
- Framework correctly detected
- Build completes without errors
- Static files exist in expected directory

**Deployment Phase:**
- Environment variables prepared correctly
- Backend references resolved in env vars
- Deployment succeeds with all env vars
- Deployment URL captured

**Validation Phase:**
- Service reports healthy status
- Public URL accessible
- deployment_url captured from aramb-cli

### Expected (SHOULD pass)

- Backend references correctly resolved
- Environment variables set properly
- Service accessible via public URL
- Static files served correctly

### Nice to Have

- Build optimized (minified, compressed)
- Service starts quickly
- Static files cached properly
- Environment variables logged (non-sensitive only)

## Output Requirements (IMPORTANT)

Before completing, you MUST set comprehensive outputs. The planner uses these
to answer user questions without needing to resume you.

**Always include:**

```python
outputs = {
    # URLs and identifiers (CRITICAL)
    "url": "https://my-app-web.aramb.dev",
    "id": "deploy-abc123xyz",
    "deployment_id": "deploy-abc123xyz",

    # Deployment details
    "deploy_mode": "toml",  # or "auto"
    "service_slug": "my-app-web",
    "static_dir": "./dist",

    # Build info
    "framework": "React 18",
    "build_time": "45s",
    "bundle_size": "1.2MB",

    # Commands used
    "commands": {
        "build": "npm run build",
        "preview": "npx serve dist"
    },

    # Status
    "status": "success",
    "healthy": true
}
```

**Why this matters:**
- Planner receives your outputs in `task_completed` trigger
- Planner can answer "What's the URL?", "Is it deployed?", etc. immediately
- No need to resume you for simple factual questions

## Output

**Required output format:**

```json
{
  "id": "deploy-abc123xyz",
  "url": "https://my-app-web.aramb.dev",
  "status": "success"
}
```

**Fields:**
- `id`: Deployment ID returned by aramb-cli
- `url`: Public URL returned by aramb-cli
- `status`: Deployment status

**Extended output (recommended):**

```json
{
  "id": "deploy-abc123xyz",
  "url": "https://my-app-web.aramb.dev",
  "status": "success",
  "deploy_mode": "toml",
  "service_slug": "my-app-web",
  "static_dir": "./dist",
  "framework": "React",
  "build_time": "45s",
  "healthy": true
}
```

## Usage Examples

### Standard Deployment (with aramb.toml)

```bash
# Prerequisites:
# - aramb.toml exists with frontend service configured
# - APPLICATION_ID environment variable set
# - ARAMB_API_TOKEN environment variable set

export APPLICATION_ID="app-xyz789"
export ARAMB_API_TOKEN="your-token"

# Run deployment
/frontend-deployment

# Flow:
# 1. Creates frontend service
# 2. Resolves backend references (if any)
# 3. Builds static files (if needed)
# 4. Deploys with environment variables
```

### Deployment with Backend References

```bash
# aramb.toml contains:
# API_URL = "${101.outputs.PUBLIC_URL}"

# Backend must be deployed first
# Frontend deployment will automatically:
# 1. Get backend service slug from TOML
# 2. Fetch backend deployment outputs
# 3. Resolve API_URL to actual backend URL
# 4. Deploy frontend with resolved env vars

/frontend-deployment
```

### Deploy Existing Static Files

```bash
# If dist/ exists and contains files:
# - Skips build phase
# - Uses existing static files
# - Deploys directly

/frontend-deployment
```

### Force Rebuild

```bash
# Forces rebuild even if static files exist:
# - Deletes existing dist/
# - Rebuilds from source
# - Deploys new build

/frontend-deployment --force-build
```

## Error Handling

### Missing APPLICATION_ID

```bash
if [ -z "$APPLICATION_ID" ]; then
  echo "Error: APPLICATION_ID environment variable not set"
  echo "Set it with: export APPLICATION_ID=your-app-id"
  exit 1
fi
```

### Build Failures

If build fails:
1. Log error with framework and build output
2. Exit without creating service
3. Provide troubleshooting guidance

### Service Creation Failures

If service creation fails:
1. Log error with API response
2. Check if service already exists
3. Suggest using different service name

### Deployment Failures

If deployment fails:
1. Log error with deployment details
2. Service may still exist (cleanup not automatic)
3. Retry deployment or delete service manually

## Framework-Specific Handling

### Next.js

```bash
# Detect
[ -f "next.config.js" ]

# Build command
npm run build

# Output directory
out/
```

### React (CRA)

```bash
# Detect
grep -q "react-scripts" package.json

# Build command
npm run build

# Output directory
build/
```

### Vite

```bash
# Detect
[ -f "vite.config.js" ]

# Build command
npm run build

# Output directory
dist/
```

### Vue CLI

```bash
# Detect
[ -f "vue.config.js" ]

# Build command
npm run build

# Output directory
dist/
```

### Angular

```bash
# Detect
[ -f "angular.json" ]

# Build command
ng build --configuration production

# Output directory
dist/<project-name>/
```

## Environment Variables

**Required:**
- `APPLICATION_ID` - Aramb application ID to deploy to
- `ARAMB_API_TOKEN` - API token for authentication

**Optional:**
- `BUILDKIT_HOST` - BuildKit server (only if custom build needed)
- `SERVICE_NAME` - Override auto-generated service name
- `PORT` - Override default port (8080)

## Best Practices

1. **Set APPLICATION_ID** before running deployment
2. **Clean build artifacts** if encountering issues (`rm -rf dist/ build/`)
3. **Use force-build** when you've made changes but static files exist
4. **Verify static files** are correctly built before deployment
5. **Test locally** with `npx http-server dist/` before deploying

## Common Scenarios

### Scenario 1: Frontend with Backend Integration

```bash
# aramb.toml has both backend and frontend services
# Frontend env vars reference backend outputs

# 1. Backend deployed first (returns PUBLIC_URL)
# 2. Run frontend deployment
/frontend-deployment

# Result:
# → Creates frontend service
# → Fetches backend deployment outputs
# → Resolves: API_URL=https://backend-api.aramb.dev
# → Builds React app
# → Deploys with resolved env vars
```

### Scenario 2: Fresh React Project (No Build Yet)

```bash
# Project has package.json, no build/ directory
# aramb.toml configured with frontend service

/frontend-deployment

# Result:
# → Creates frontend service from TOML
# → Detects no static files
# → Detects React framework
# → Runs npm run build
# → Deploys from build/
# → Returns URL: https://frontend-web.aramb.dev
```

### Scenario 3: Pre-built Static Files

```bash
# Project has dist/ directory with files
# aramb.toml configured with buildPath="dist"

/frontend-deployment

# Result:
# → Creates frontend service from TOML
# → Detects existing dist/ directory
# → Skips build phase
# → Deploys from dist/
# → Returns URL: https://frontend-web.aramb.dev
```

### Scenario 4: Multiple Environment Variables

```toml
# aramb.toml with multiple env vars
[services.configuration.vars]
API_URL = "${101.outputs.PUBLIC_URL}"
WS_URL = "${101.outputs.WEBSOCKET_URL}"
DEBUG = "false"
VERSION = "1.0.0"

[services.configuration.secrets]
API_KEY = "secret-api-key-123"
AUTH_TOKEN = "auth-token-xyz"
```

```bash
/frontend-deployment

# Result:
# → Resolves both backend references
# → Deploys with 6 environment variables:
#   --env API_URL=https://backend-api.aramb.dev
#   --env WS_URL=wss://backend-api.aramb.dev/ws
#   --env DEBUG=false
#   --env VERSION=1.0.0
#   --env API_KEY=secret-api-key-123
#   --env AUTH_TOKEN=auth-token-xyz
```

## Integration with Other Skills

### After backend-deployment

Typical workflow for full-stack applications:

```bash
# 1. Generate aramb.toml (includes backend and frontend services)
/aramb-metadata

# 2. Deploy backend services
/backend-deployment
# Returns: {"public_url": "https://backend-api.aramb.dev", ...}

# 3. Deploy frontend (automatically resolves backend URL)
/frontend-deployment
# Resolves: API_URL=https://backend-api.aramb.dev
# Returns: {"url": "https://frontend-web.aramb.dev", ...}
```

### Complete Workflow

```
User Request
    ↓
/aramb-metadata (creates aramb.toml with backend + frontend)
    ↓
/backend-deployment
    ├─ Deploy TOML (create services)
    ├─ Build & deploy backend services
    └─ Return PUBLIC_URL
    ↓
Backend Running (PUBLIC_URL: https://backend-api.aramb.dev)
    ↓
/frontend-deployment
    ├─ Create frontend service
    ├─ Resolve backend PUBLIC_URL
    ├─ Build static files
    ├─ Deploy with env vars (API_URL=https://backend-api.aramb.dev)
    └─ Return frontend URL
    ↓
All Services Running
    ├─ Backend: https://backend-api.aramb.dev
    └─ Frontend: https://frontend-web.aramb.dev
```

## Advanced Usage

See reference documentation:

- **Installation**: [references/installation.md](references/installation.md) - Setup guide
- **Troubleshooting**: [references/troubleshooting.md](references/troubleshooting.md) - Common issues
- **Frameworks**: [references/frameworks.md](references/frameworks.md) - Framework-specific details

## See Also

- **frontend-development**: Build frontend applications with components
- **local-deploy**: Full-stack deployment with aramb.toml
- **aramb-metadata**: Generate aramb.toml for complex deployments

Related Skills

gke-deployment

16
from diegosouzapw/awesome-omni-skill

Deploy, configure, and manage Kubernetes workloads on GKE with Deployments, Services, Ingress, HPA, health probes, ConfigMaps, and Secrets. Use when deploying containers to GKE, configuring load balancers, setting up autoscaling, writing health checks, managing environment configs, or troubleshooting pod issues.

featbit-deployment-kubernetes

16
from diegosouzapw/awesome-omni-skill

Deploys FeatBit to Kubernetes using Helm Charts. Use when user mentions "Kubernetes", "Helm", "K8s", "kubectl", works with values.yaml files, asks about "cloud deployment", "AKS", "EKS", "GKE", "ingress", or needs production-grade container orchestration setup.

featbit-deployment-docker

16
from diegosouzapw/awesome-omni-skill

Expert guidance for deploying FeatBit with Docker Compose across three tiers - Standalone (PostgreSQL only), Standard (PostgreSQL/MongoDB + Redis), and Professional (+ ClickHouse + Kafka). Use when user mentions "docker-compose", "deploy with Docker", "standalone vs standard vs pro", works with docker-compose.yml files, or asks about container configuration, environment variables, or production Docker setup.

FastAPI Kubernetes Deployment

16
from diegosouzapw/awesome-omni-skill

This skill should be used when the user asks to "deploy FastAPI to Kubernetes", "create Dockerfile", "build Docker image", "write Helm chart", "configure K8s deployment", "add health checks", "scale FastAPI", or mentions Docker, Kubernetes, K8s, containers, Helm, or deployment. Provides containerization and orchestration patterns.

expo-deployment

16
from diegosouzapw/awesome-omni-skill

Deploy Expo apps to production

dotnet-container-deployment

16
from diegosouzapw/awesome-omni-skill

Deploys .NET containers. Kubernetes probes, Docker Compose for local dev, CI/CD integration.

docker-deployment

16
from diegosouzapw/awesome-omni-skill

Docker containerization and deployment for Java/Spring Boot applications. Multi-stage builds, docker-compose, health checks, and CI/CD with GitHub Actions.

DevOps & Deployment

16
from diegosouzapw/awesome-omni-skill

Use when setting up CI/CD pipelines, containerizing applications, deploying to Kubernetes, or writing infrastructure as code. DevOps & Deployment covers GitHub Actions, Docker, Helm, and Terraform patterns.

deployment-wizard

16
from diegosouzapw/awesome-omni-skill

Deploy local websites to the internet instantly via Cloudflare Tunnel. Zero hosting, zero domain needed.

deployment-validation-config-validate

16
from diegosouzapw/awesome-omni-skill

You are a configuration management expert specializing in validating, testing, and ensuring the correctness of application configurations. Create comprehensive validation schemas, implement configurat

deployment-safety

16
from diegosouzapw/awesome-omni-skill

Pre-deployment checklists, rollback strategies, and post-deploy verification. Use this skill when preparing to deploy code, reviewing deployment processes, or setting up CI/CD pipelines.

deployment-procedures

16
from diegosouzapw/awesome-omni-skill

Production deployment principles and decision-making.