This document explains how Claude Code runs automatically in response to Gogs webhook events (issues and comments).
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
src/server.js)http://0.0.0.0:3000/webhooksrc/jobQueue.js)queue.jsonscripts/handle-issue.sh)claude user--print --dangerously-skip-permissions.env:
# Issues Event Configuration
WEBHOOK_ISSUES_ENABLED=true
# Issue Comment Event Configuration
WEBHOOK_ISSUE_COMMENT_ENABLED=true
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
}
]
}
}
By default, Claude Code runs in interactive mode and expects:
When run from a script, Claude would hang waiting for input.
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"
Multiple webhooks arrive quickly:
Queue processes sequentially:
New webhooks accepted during processing:
The system forces Claude to read all issue comments before starting work. This is achieved through:
Explicit Instructions in Prompt
Gogs MCP Tools Used
mcp__gogs__get_issue - Fetches complete issue detailsmcp__gogs__list_issue_comments - Fetches ALL comments chronologicallyWhy This Matters
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.
User creates issue in Gogs
claudeGogs sends webhook → POST /webhook
issuesopenedServer accepts webhook → Returns 200 OK (instant)
Job enqueued:
{
"id": 5,
"eventType": "issues",
"status": "pending",
"config": { "command": "handle-issue.sh", ... }
}
Queue starts processing:
handle-issue.shBuilds 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.
Claude Code runs:
claude --print --dangerously-skip-permissions "$PROMPT"
mcp__gogs__get_issue to fetch issue detailsmcp__gogs__list_issue_comments to fetch ALL commentsmcp__gogs__create_issue_comment to post ALL responses, updates, and questions to the issueJob completes → Next job starts (if any)
./scripts/test-claude-noninteractive.sh
Expected output:
✓ SUCCESS: Claude ran non-interactively
Send multiple webhooks rapidly:
./test-queue-blocking.sh
Monitor queue:
watch -n1 'cat queue.json | jq .queue'
You should see:
status: "running"status: "pending"cat queue.json | jq
watch -n1 'cat queue.json | jq .queue'
# If running with systemd
journalctl -u agent-manager -f -n100
# If running with npm run dev
# Check terminal where server is running
Problem: Claude is waiting for user input
Solution: Ensure you're using --print and --dangerously-skip-permissions flags
Problem: Jobs are being queued but not processing
Solution:
cat queue.json | jq '.queue[] | select(.status=="running")'Problem: Gogs webhook delivery fails with timeout
Solution: This shouldn't happen - webhooks return immediately. Check:
curl http://localhost:3000/healthProblem: Claude runs but doesn't commit anything
Solution:
claude user--dangerously-skip-permissions FlagThis flag bypasses all permission checks. It's safe in this context because:
claude userDo NOT use if:
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.
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"
Typical execution times:
Queue handles bursts: