chore(ci): expand claude.yml + add auto-issue-comment.yml

- claude.yml: add issues:[opened,labeled,assigned] + pull_request_review_comment triggers
- claude.yml: add issue-triage job (welcome comment on new issues)
- claude.yml: expand direct_prompt with PraisonAIUI-specific routing (STEP 0-6):
  - architecture routing (core / features / UI builders / frontend / tests / docs)
  - external-repo routing (PraisonAI / PraisonAI-Tools / PraisonAIDocs)
  - conceptual checks (no duplicate exports, no class-first Ask*Message, lazy
    optional deps, real DeprecationWarning on deprecations)
  - import-time < 200ms + no heavy-dep leak invariant
  - PR body template (Summary, Before/After, SHA-cited checklist, test evidence,
    import-time proof)
  - STEP 6 reviewer-loop instructions (respond to CodeRabbit/Copilot/human
    review comments, push to same branch)
- auto-issue-comment.yml: optional workflow to escalate an issue to Claude by
  adding the 'claude' label (workflow_dispatch-only; issues:opened trigger
  commented out by default)

CodeRabbit + Copilot: no workflow file needed — both are GitHub Apps that
react to PRs automatically. The chain (CodeRabbit → Copilot → Claude) is
already orchestrated by auto-pr-comment.yml.
This commit is contained in:
MervinPraison committed 2026-04-22 06:08:37 +01:00
1 parent f0431291da
commit e3e7731547
2 files changed
+311 -27

No files matched your search

+86
View File
@@ -0,0 +1,86 @@
name: Auto Issue Comment
# Optional: automatically escalate every new issue to Claude for a full
# investigation + draft fix. Disabled by default (only workflow_dispatch).
# To enable auto-triage on every new issue, uncomment the `issues:` trigger.
#
# Note: `@claude` mentions only trigger claude.yml when the commenter is a
# HUMAN user (or github-actions[bot] via PAT). This workflow posts the
# comment as github-actions[bot], so claude.yml must allow that bot.
on:
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to triage with Claude"
required: true
type: number
# issues:
# types: [opened]
jobs:
# Escalate an issue to full Claude implementation by adding the `claude`
# label. claude.yml listens on `issues:labeled` + label=='claude' and
# triggers Job 2 (claude-response) which does the actual work.
trigger-claude:
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issues' && !contains(toJSON(github.event.issue.labels), 'claude'))
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Resolve issue number
id: resolve
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "number=${{ inputs.issue_number }}" >> "$GITHUB_OUTPUT"
else
echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
fi
- name: Add claude label + post instructions
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const issueNumber = Number('${{ steps.resolve.outputs.number }}');
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const labels = (issue.labels || []).map(l => typeof l === 'string' ? l : l.name);
if (labels.includes('claude')) {
console.log(`Issue #${issueNumber} already has 'claude' label — skipping.`);
return;
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: ['claude'],
});
const body = [
'🤖 Auto-triaging with Claude.',
'',
'Claude will:',
'',
'1. Read this issue and all comments.',
'2. Classify and route to the right area (`src/praisonaiui/`, `src/frontend/`, `docs/`, or external repo).',
'3. Implement a minimal fix per `AGENTS.md`.',
'4. Run `pytest` + the import-time invariant locally.',
'5. Open a draft PR linked to this issue.',
'',
'Follow-ups in this thread with `@claude` will re-trigger the loop.'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body,
});
+225 -27
View File
@@ -1,8 +1,26 @@
name: Claude Assistant
# Triggers:
# - issues:opened → lightweight triage (welcome comment + label)
# - issues:labeled → full implementation when `claude` label applied
# - issues:assigned → full implementation when issue assigned to Claude
# - issue_comment → full implementation when @claude mentioned (issues + PRs)
# - pull_request_review → full implementation when @claude mentioned in review
# - pull_request_review_comment → full implementation when @claude mentioned inline
#
# Focus: CLAUDE only. Copilot and CodeRabbit are GitHub Apps that react to PRs
# automatically — no workflow file needed. auto-pr-comment.yml orchestrates the
# CodeRabbit → Copilot → Claude review chain for PRs.
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, labeled, assigned]
pull_request_review:
types: [submitted]
permissions:
contents: write
@@ -12,15 +30,74 @@ permissions:
id-token: write
jobs:
# ================================================================
# Job 1 — Issue triage (runs on ANY new issue, including from external users)
# Posts a welcome comment. Does NOT execute Claude Code.
# To escalate to full implementation, a maintainer adds the `claude` label
# or mentions @claude in a comment — which triggers Job 2.
# ================================================================
issue-triage:
if: |
github.event_name == 'issues' &&
github.event.action == 'opened' &&
!contains(toJSON(github.event.issue.labels), 'claude')
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- name: Post welcome comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const body = [
'👋 Thanks for opening an issue in **PraisonAIUI**.',
'',
'A maintainer will triage this shortly. If you would like Claude to investigate and draft a fix, a maintainer can:',
'',
'- Apply the `claude` label to this issue, **or**',
'- Mention `@claude` in a comment with any additional instructions.',
'',
'Please make sure your issue includes:',
'',
'1. A clear description of the behaviour you expect vs what you see.',
'2. Minimal reproduction steps (code snippet or `aiui.template.yaml`).',
'3. Version: `python -c "import praisonaiui; print(praisonaiui.__version__)"`.',
'4. Any relevant log output.',
'',
'See [AGENTS.md](https://github.com/MervinPraison/PraisonAIUI/blob/main/AGENTS.md) for project conventions.'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
# ================================================================
# Job 2 — Full Claude Code implementation
# Runs when:
# - A comment containing `@claude` is posted on an issue or PR
# - The `claude` label is added to an issue
# - The issue is assigned to a Claude bot
# - A PR review or review-comment contains `@claude`
# ================================================================
claude-response:
env:
ISSUE_NUMBER_RESOLVED: ${{ github.event.issue.number }}
ISSUE_NUMBER_RESOLVED: ${{ github.event.issue.number || github.event.pull_request.number }}
if: |
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
github.actor != 'dependabot[bot]' &&
github.actor != 'cursor[bot]' &&
github.actor != 'renovate[bot]'
github.actor != 'renovate[bot]' &&
(
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && github.event.action == 'labeled' && contains(toJSON(github.event.label), 'claude')) ||
(github.event_name == 'issues' && github.event.action == 'assigned')
)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@@ -42,46 +119,167 @@ jobs:
allowed_bots: "praisonai-triage-agent[bot]"
timeout_minutes: "30"
direct_prompt: |
You are implementing changes in MervinPraison/PraisonAIUI (Server-Driven UI). Follow AGENTS.md in this repository.
You are implementing changes in **MervinPraison/PraisonAIUI** (YAML-driven server-driven UI with agentic chat).
Follow `AGENTS.md` at the repository root. If a conflict arises between this prompt and `AGENTS.md`, `AGENTS.md` wins.
Primary scope: src/praisonaiui/, tests/, docs/. If the fix belongs in praisonaiagents, praisonai, or PraisonAI-Tools, route there and explain — do not implement SDK/tool code inside this repo unless it is AIUI integration only.
STEP 0 — GIT & GITHUB CLI:
═══════════════════════════════════════════════════════════════
STEP 0 — GIT & GITHUB CLI
═══════════════════════════════════════════════════════════════
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
gh auth setup-git
STEP 1 — ISSUE:
Read the issue and all comments. Implement what the issue describes with minimal, focused changes.
═══════════════════════════════════════════════════════════════
STEP 1 — READ GUIDELINES
═══════════════════════════════════════════════════════════════
Read `AGENTS.md` and any `docs/principles.md`. Key invariants:
• Cold import of `praisonaiui` must stay under 200 ms; module count must not grow.
• Heavy / optional deps (`mcp`, `langchain`, `llama_index`, `semantic_kernel`,
`slack_sdk`, `discord.py`, `botbuilder.core`, `openai`, `anthropic`, `mistralai`,
`google.generativeai`) must be **lazy-imported** — never eager.
• Public API is verb-first. New classes in `src/praisonaiui/message.py` ending
in `Message` with a verb prefix (Ask*, Do*, Request*, …) are forbidden —
use a module-level `async def` verb helper instead (see `prompt`, `error`).
• Deprecations must emit a runtime `warnings.warn(..., DeprecationWarning, stacklevel=2)`
on first access, not only in the docstring.
• Deterministic serialisation in anything reaching the wire (sorted keys, stable field
order). See existing `to_dict` patterns.
• Multi-agent + async safe: no global mutable state without a lock.
STEP 2 — BRANCH (single name; reuse in STEP 4):
BRANCH="claude/issue-${{ env.ISSUE_NUMBER_RESOLVED }}-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
═══════════════════════════════════════════════════════════════
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before any code)
═══════════════════════════════════════════════════════════════
Answer these questions inline in your response, then proceed only if you pass:
STEP 3 — TEST / VERIFY:
Run targeted pytest or smoke checks relevant to your edits (e.g. pytest tests/unit -q).
ROUTING:
1. **Core aiui** (`src/praisonaiui/`) — protocols, message types, server, features.
2. **Features** (`src/praisonaiui/features/`) — opt-in capabilities (MCP, platforms, lifecycle, audio, auth, sharing, etc.).
3. **UI builders** (`src/praisonaiui/ui.py`) — declarative component helpers.
4. **Frontend** (`src/frontend/`) — React components / stores / SSE handlers.
5. **Tests** (`tests/unit/`, `tests/integration/`) — new features require both smoke and real-agentic tests.
6. **Docs** (`docs/`) — canonical name per feature, migration table for renames.
STEP 4 — COMMIT, PUSH, OPEN PR (mandatory if you produced commits):
git add -A
git commit -m "feat: <short summary> (fixes #${{ env.ISSUE_NUMBER_RESOLVED }})"
git push -u origin "$BRANCH"
REPO="${{ github.repository }}"
COUNT=$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')
if [ "$COUNT" -gt 0 ]; then
gh pr list --repo "$REPO" --head "$BRANCH" --json url --jq '.[0].url'
else
gh pr create --repo "$REPO" --base main --head "$BRANCH" --title "feat: <short title>" --body "Fixes #${{ env.ISSUE_NUMBER_RESOLVED }}"
fi
CRITICAL: Do not stop after `git push`. You MUST complete `gh pr create` (or print the existing PR URL from the step above) and post that URL on the issue. Never ask a human to open the PR manually.
EXTERNAL REPOS (do NOT edit from within this repo — route the work to the right place and stop):
• Core SDK: `MervinPraison/PraisonAI` (`praisonaiagents`, `praisonai`) — agent runtime.
• Tools: `MervinPraison/PraisonAI-Tools` — tool implementations.
• Docs site: `MervinPraison/PraisonAIDocs` — product docs.
If the requested change belongs in an external repo, comment on the issue explaining
where it should live and DO NOT open a PR in this repo.
CONCEPTUAL CHECKS (if ANY fails — add a comment, do NOT open a PR):
• Does it duplicate an existing public symbol in `src/praisonaiui/__init__.py`?
• Does it add new class-first message types (`class Ask*Message`, `class *Message`
with a verb in the name)? → Use a verb-first helper instead.
• Does it add a new hard dependency to `pyproject.toml` `[project] dependencies`?
→ Move to `[project.optional-dependencies]` and wrap imports lazily.
• Does it break backward compat (rename, signature change, removal)? → Add
a deprecation alias that emits `DeprecationWarning`; never hard-remove before the
documented removal version (e.g. `0.5.0`).
═══════════════════════════════════════════════════════════════
STEP 3 — IMPLEMENT
═══════════════════════════════════════════════════════════════
Single branch for the whole flow (reuse the same name in STEP 5):
BRANCH="claude/issue-${{ env.ISSUE_NUMBER_RESOLVED }}-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
Make minimal, focused changes:
• Stay within the files listed in the issue's "Scope" / "Files to change" section.
• Prefer extending existing modules over adding new ones.
• No emojis, no comments, no markdown except where the user asked for it.
• Python ≥ 3.10 style (`list[...]` not `List[...]`, `X | None` not `Optional[X]`).
═══════════════════════════════════════════════════════════════
STEP 4 — TEST / VERIFY
═══════════════════════════════════════════════════════════════
Run these targeted checks (NOT the full suite):
# 1. Lint on only the files you changed:
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\.py$' | tr '\n' ' ')
[ -n "$CHANGED" ] && ruff check $CHANGED
# 2. Unit tests for the module(s) you touched:
pytest tests/unit/<your_new_test_file>.py -v --tb=short
# 3. Import-time invariant (MUST stay under 200 ms cold):
python -c "import time, sys; t=time.time(); import praisonaiui; dt=(time.time()-t)*1000; heavy=[m for m in sys.modules if any(h in m for h in ['langchain','llama_index','mcp','slack','discord','botbuilder','openai.','anthropic.','mistralai','google.generativeai'])]; print(f'{dt:.1f}ms modules={len(sys.modules)} leaked={heavy}'); assert heavy == [], f'Heavy deps leaked: {heavy}'"
# 4. Real agentic end-to-end test (write this into tests/integration/
# if your feature changes the agent-facing API):
# from praisonaiagents import Agent
# import praisonaiui as aiui
# agent = Agent(name="demo", instructions="You are a helpful assistant")
# result = agent.start("Say hello in one sentence")
# print(result)
If anything fails, fix the root cause (never skip, xfail, or delete the test).
═══════════════════════════════════════════════════════════════
STEP 5 — COMMIT, PUSH, OPEN PR (MANDATORY if you produced commits)
═══════════════════════════════════════════════════════════════
git add -A
git commit -m "feat: <short summary> (fixes #${{ env.ISSUE_NUMBER_RESOLVED }})"
git push -u origin "$BRANCH"
REPO="${{ github.repository }}"
COUNT=$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')
if [ "$COUNT" -gt 0 ]; then
gh pr list --repo "$REPO" --head "$BRANCH" --json url --jq '.[0].url'
else
gh pr create --repo "$REPO" --base main --head "$BRANCH" \
--title "feat: <short title>" \
--body "Fixes #${{ env.ISSUE_NUMBER_RESOLVED }}
## Summary
<what changed in one paragraph>
## Before / After
<copy-pasteable snippet per public API change>
## Acceptance criteria
<copy from the issue; tick boxes only with commit SHA + file path evidence>
## Test evidence
\`\`\`
<paste pytest output>
\`\`\`
## Import-time proof
\`\`\`
<paste the python -c import-time output>
\`\`\`
"
fi
CRITICAL: Do NOT stop after `git push`. You MUST complete `gh pr create` (or print the
existing PR URL from the step above) and post that URL on the issue. Never ask a
human to open the PR manually.
═══════════════════════════════════════════════════════════════
STEP 6 — RESPOND TO REVIEW FEEDBACK (if this run was triggered by a review comment)
═══════════════════════════════════════════════════════════════
If you were invoked by a PR review comment, you are the Lead Engineer for this PR:
• Read ALL reviewer comments in chronological order (CodeRabbit → Copilot → human).
• Fix every VALID issue by pushing commits to THIS branch (do NOT open a new PR).
• Reply with a summary of which comments you addressed, which you disagreed with (and why).
• Never ship a fix that removes/weakens a test.
allowed_tools: |
Bash(git:*)
Bash(python:*)
Bash(pip:*)
Bash(pytest:*)
Bash(ruff:*)
Bash(gh:*)
Bash(npm:*)
Bash(npx:*)
Bash(python -m pytest:*)
Bash(python -m pip:*)
Bash(python -m ruff:*)
View
GlobTool
GrepTool