CLAUDE-AUTOMATION.md 11 KB

Claude Code Automation Guide

Overview

This document explains how Claude Code runs automatically in response to Gogs webhook events (issues and comments).

Architecture

How It Works

1. Gogs Webhook → HTTP Server (accepts immediately, returns 200)
                      ↓
2. Webhook Handler → Enqueues job (non-blocking)
                      ↓
3. Job Queue → Processes ONE job at a time (FIFO)
                      ↓
4. Command Executor → Runs handle-issue.sh (BLOCKS queue)
                      ↓
5. Claude Code → Runs non-interactively (completes task)
                      ↓
6. Job Complete → Next job starts

Key Components

1. Webhook Server (src/server.js)

  • Listens on http://0.0.0.0:3000/webhook
  • Accepts webhooks immediately (no blocking)
  • Returns HTTP 200 instantly

2. Job Queue (src/jobQueue.js)

  • FIFO Processing: Jobs execute in order received
  • Sequential Execution: Only ONE job runs at a time
  • Queue Blocks: Next job waits until current one finishes
  • Persistence: Queue state saved to queue.json
  • Crash Recovery: Pending jobs resume after restart

3. Issue Handler Script (scripts/handle-issue.sh)

  • Checks if issue is assigned to claude user
  • Clones/updates repository
  • Builds prompt instructing Claude to fetch all comments
  • Runs Claude Code non-interactively

4. Claude Code

  • Runs with --print --dangerously-skip-permissions
  • Uses Gogs MCP tools to fetch issue and all comments
  • Reads entire discussion history before starting work
  • No user interaction required
  • Completes task and exits

Configuration

Enable Issue & Comment Webhooks

.env:

# Issues Event Configuration
WEBHOOK_ISSUES_ENABLED=true

# Issue Comment Event Configuration
WEBHOOK_ISSUE_COMMENT_ENABLED=true

Command Configuration

commands.json:

{
  "commands": {
    "issues": [
      {
        "name": "claude-issue-handler",
        "description": "Automatically handle issues assigned to Claude",
        "type": "shell",
        "command": "/home/claude/agent-manager/scripts/handle-issue.sh",
        "args": [
          "{{repo_owner}}",
          "{{repo}}",
          "{{pusher}}",
          "{{issue_number}}",
          "{{issue_title}}",
          "{{issue_body}}",
          "{{issue_action}}",
          "",
          "{{issue_assignee}}"
        ],
        "cwd": null,
        "timeout": 600000,
        "filterBranch": null
      }
    ],
    "issue_comment": [
      {
        "name": "claude-comment-handler",
        "description": "Handle issue comments for Claude-assigned issues",
        "type": "shell",
        "command": "/home/claude/agent-manager/scripts/handle-issue.sh",
        "args": [
          "{{repo_owner}}",
          "{{repo}}",
          "{{pusher}}",
          "{{issue_number}}",
          "{{issue_title}}",
          "{{issue_body}}",
          "{{issue_action}}",
          "{{comment_body}}",
          "{{issue_assignee}}"
        ],
        "cwd": null,
        "timeout": 600000,
        "filterBranch": null
      }
    ]
  }
}

Critical Flags for Non-Interactive Claude

Problem

By default, Claude Code runs in interactive mode and expects:

  • Terminal (TTY) for UI
  • User to approve permissions
  • User to confirm actions

When run from a script, Claude would hang waiting for input.

Solution

Use these flags to run Claude non-interactively:

claude --print --dangerously-skip-permissions "$PROMPT"

Flags explained:

  • --print: Non-interactive mode - print output and exit
  • --dangerously-skip-permissions: Skip all permission dialogs (safe in controlled environment)

Alternative (safer in some contexts):

claude --print --permission-mode bypassPermissions "$PROMPT"

Behavior

✅ What Happens

  1. Multiple webhooks arrive quickly:

    • All are accepted immediately (HTTP 200)
    • All are queued
  2. Queue processes sequentially:

    • Job 1 starts → Claude runs → Claude finishes → Job 1 complete
    • Job 2 starts → Claude runs → Claude finishes → Job 2 complete
    • Job 3 starts → ...
  3. New webhooks accepted during processing:

    • Webhook arrives while Claude is running
    • Gets queued immediately
    • Webhook sender gets instant 200 response
    • Job will process when queue reaches it

✅ Benefits

  • No Lost Webhooks: Even if Claude takes 30 minutes, new webhooks are queued
  • No Concurrent Execution: Only one Claude runs at a time (prevents conflicts)
  • Crash Recovery: If server crashes, pending jobs resume on restart
  • No Timeouts: Webhook sender gets instant response, doesn't timeout

How Claude Reads All Comments

Critical Feature: Mandatory Comment Reading

The system forces Claude to read all issue comments before starting work. This is achieved through:

  1. Explicit Instructions in Prompt

    • Prompt contains step-by-step mandatory instructions
    • Claude MUST use MCP tools to fetch data
    • Clear order: fetch → read → understand → act
  2. Gogs MCP Tools Used

    • mcp__gogs__get_issue - Fetches complete issue details
    • mcp__gogs__list_issue_comments - Fetches ALL comments chronologically
  3. Why This Matters

    • Prevents Claude from missing context
    • Ensures Claude sees user clarifications
    • Avoids duplicate work or wrong assumptions
    • Claude understands full conversation history

Example Prompt Structure

When an issue or comment is received, Claude gets this prompt:

IMPORTANT: Issue #42 was opened in repository owner/repo.

=== MANDATORY FIRST STEPS - READ ALL MESSAGES ===

Before you start any work on this issue, you MUST complete these steps IN ORDER:

1. Use the mcp__gogs__get_issue tool to fetch the complete issue details:
   - owner: owner
   - repo: repo
   - number: 42

2. Use the mcp__gogs__list_issue_comments tool to fetch ALL comments:
   - owner: owner
   - repo: repo
   - number: 42

3. Read and understand:
   - The complete issue description
   - ALL comments in the discussion thread
   - The full context

4. ONLY AFTER reading everything above, proceed with your work

=== ISSUE CONTEXT ===
[Issue details here]

=== YOUR TASK ===
[Instructions here]

DO NOT skip reading the comments using the MCP tools. This is critical.

This ensures Claude always has the complete conversation context.

Workflow Example

Scenario: User creates issue assigned to Claude

  1. User creates issue in Gogs

    • Title: "Add dark mode to settings"
    • Assignee: claude
  2. Gogs sends webhookPOST /webhook

    • Event: issues
    • Action: opened
  3. Server accepts webhook → Returns 200 OK (instant)

  4. Job enqueued:

    {
     "id": 5,
     "eventType": "issues",
     "status": "pending",
     "config": { "command": "handle-issue.sh", ... }
    }
    
  5. Queue starts processing:

    • Runs handle-issue.sh
    • Script clones/updates repo
    • Builds prompt:

      Issue #5 was opened in owner/repo by user.
      
      Issue Title: Add dark mode to settings
      
      Issue Description: [description here]
      
      This issue is assigned to you. Please review and handle it accordingly.
      
  6. Claude Code runs:

    claude --print --dangerously-skip-permissions "$PROMPT"
    
    • First: Uses mcp__gogs__get_issue to fetch issue details
    • Second: Uses mcp__gogs__list_issue_comments to fetch ALL comments
    • Third: Reads and understands the complete discussion thread
    • Then: Analyzes the requirements from full context
    • Reads codebase
    • Implements feature
    • Commits changes
    • Uses mcp__gogs__create_issue_comment to comment on issue
  7. Job completes → Next job starts (if any)

Testing

Test Non-Interactive Mode

./scripts/test-claude-noninteractive.sh

Expected output:

✓ SUCCESS: Claude ran non-interactively

Test Queue Blocking

Send multiple webhooks rapidly:

./test-queue-blocking.sh

Monitor queue:

watch -n1 'cat queue.json | jq .queue'

You should see:

  • All jobs queued immediately
  • Only one job with status: "running"
  • Others with status: "pending"
  • Jobs complete one by one

Monitoring

Check Queue Status

cat queue.json | jq

Watch Queue in Real-Time

watch -n1 'cat queue.json | jq .queue'

View Server Logs

# If running with systemd
journalctl -u agent-manager -f -n100

# If running with npm run dev
# Check terminal where server is running

Troubleshooting

Claude hangs/does nothing

Problem: Claude is waiting for user input

Solution: Ensure you're using --print and --dangerously-skip-permissions flags

Jobs pile up in queue

Problem: Jobs are being queued but not processing

Solution:

  1. Check if a job is stuck running: cat queue.json | jq '.queue[] | select(.status=="running")'
  2. Check server logs for errors
  3. Restart server to reset stuck jobs to pending

Webhooks timing out

Problem: Gogs webhook delivery fails with timeout

Solution: This shouldn't happen - webhooks return immediately. Check:

  1. Is server running? curl http://localhost:3000/health
  2. Check firewall/network
  3. Verify webhook URL in Gogs settings

Claude makes no changes

Problem: Claude runs but doesn't commit anything

Solution:

  1. Check if issue is assigned to claude user
  2. Verify repository exists and Claude has access
  3. Check the prompt being sent to Claude
  4. Review Claude's output in logs

Security Considerations

--dangerously-skip-permissions Flag

This flag bypasses all permission checks. It's safe in this context because:

  • ✅ Claude only runs on issues assigned to claude user
  • ✅ Runs in isolated environment
  • ✅ Repository is controlled/trusted
  • ✅ No external network access to malicious sites

Do NOT use if:

  • ❌ Untrusted users can trigger Claude
  • ❌ Claude has access to production systems
  • ❌ Running on sensitive data

Alternative Safer Approach

If you need more control, use permission modes:

claude --print --permission-mode acceptEdits "$PROMPT"

This auto-accepts edits but may still prompt for other actions.

Advanced: Adding Logging

To track Claude's output, modify the script:

# Create logs directory
mkdir -p "$HOME/agent-manager/logs"

# Log file with timestamp
LOG_FILE="$HOME/agent-manager/logs/issue${ISSUE_NUMBER}_$(date +%Y%m%d_%H%M%S).log"

# Run Claude with logging
claude --print --dangerously-skip-permissions "$PROMPT" 2>&1 | tee "$LOG_FILE"

Performance

Typical execution times:

  • Webhook acceptance: < 100ms
  • Simple issue (read/comment): 10-30 seconds
  • Complex issue (code changes): 2-5 minutes
  • Very complex (multiple files): 5-15 minutes

Queue handles bursts:

  • 10 webhooks → queued in ~1 second
  • Processing time: 10 × average job time
  • No webhook delivery failures