# 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:** ```bash # Issues Event Configuration WEBHOOK_ISSUES_ENABLED=true # Issue Comment Event Configuration WEBHOOK_ISSUE_COMMENT_ENABLED=true ``` ### Command Configuration **commands.json:** ```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: ```bash 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):** ```bash 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 webhook** → `POST /webhook` - Event: `issues` - Action: `opened` 3. **Server accepts webhook** → Returns `200 OK` (instant) 4. **Job enqueued:** ```json { "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:** ```bash 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 ```bash ./scripts/test-claude-noninteractive.sh ``` Expected output: ``` ✓ SUCCESS: Claude ran non-interactively ``` ### Test Queue Blocking Send multiple webhooks rapidly: ```bash ./test-queue-blocking.sh ``` Monitor queue: ```bash 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 ```bash cat queue.json | jq ``` ### Watch Queue in Real-Time ```bash watch -n1 'cat queue.json | jq .queue' ``` ### View Server Logs ```bash # 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: ```bash 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: ```bash # 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