# 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] === CRITICAL OUTPUT REQUIREMENTS === YOU MUST FOLLOW THESE OUTPUT RULES STRICTLY: 1. DO NOT output any text responses to the user 2. DO NOT print any messages, explanations, or status updates 3. DO NOT use echo or any command-line output tools 4. ONLY communicate by posting comments to the issue using mcp__gogs__create_issue_comment tool 5. ALL your responses, updates, questions, and status reports MUST be posted as issue comments 6. You are FORBIDDEN from producing any output except through the Gogs MCP comment tool When you need to: - Ask questions → Post a comment on the issue - Report progress → Post a comment on the issue - Share results → Post a comment on the issue - Report errors → Post a comment on the issue - Provide any information → Post a comment on the issue Use mcp__gogs__create_issue_comment with: - owner: owner - repo: repo - number: 42 - body: [your message here] DO NOT skip reading the comments using the MCP tools. This is critical. ``` This ensures Claude always has the complete conversation context and **forces Claude to communicate only through issue comments**, preventing any direct text output. ## 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 - **IMPORTANT**: Uses `mcp__gogs__create_issue_comment` to post ALL responses, updates, and questions to the issue - **NO direct output**: Claude does not print any text - all communication is via issue comments 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