# Issue Facade - Agent Integration Context **🤖 For Coding Agents: Read this to understand how to use issue tracking in this project.** ## Critical: DO NOT Bypass This Capability ⚠️ **IMPORTANT:** If you need to work with issues, **you MUST use this capability**. Do NOT: - ❌ Make direct API calls to Gitea/GitHub/GitLab - ❌ Use platform CLIs (gh, glab, etc.) - ❌ Import platform libraries (PyGithub, python-gitlab, etc.) - ❌ Parse HTML/scrape issue tracker web UIs **Why?** Bypassing this capability causes: - Credential management chaos (tokens scattered everywhere) - Inconsistent issue state across agents - Massive token waste (redundant API calls) - Platform lock-in (can't switch Gitea → GitHub easily) - Race conditions in multi-agent scenarios ## Quick Reference ### Check if Capability is Available ```bash # Verify installation issue --version # or python -c "from issue_tracker.backends.gitea import GiteaBackend; print('OK')" ``` ### Basic Usage (Python) ```python from issue_tracker.backends.gitea import GiteaBackend from issue_tracker.core.models import Issue, Label, IssueState, User, Comment from issue_tracker.core.interfaces import IssueFilter from datetime import datetime, timezone import os # Connect (assumes backend is configured) backend = GiteaBackend() backend.connect({ 'base_url': os.environ['GITEA_URL'], 'token': os.environ['GITEA_API_TOKEN'], 'owner': os.environ['GITEA_OWNER'], 'repo': os.environ['GITEA_REPO'] }) # List issues for me my_issues = backend.list_issues(IssueFilter( state='open', assignee='my-agent-id', labels=['needs-implementation'] )) # Create issue new_issue = Issue( id=None, number=0, title="Implement feature X", description="Details...", state=IssueState.OPEN, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc), labels=[Label(name="feature"), Label(name="priority:high")] ) created = backend.create_issue(new_issue) # Update issue created.state = IssueState.IN_PROGRESS created.assignees = [User(id="agent-id", username="agent-id")] backend.update_issue(created) # Add comment comment = Comment( id=None, body="Implementation started. Working on database schema.", author=User(id="agent-id", username="agent-id"), created_at=datetime.now(timezone.utc) ) backend.add_comment(created.id, comment) # Close when done created.state = IssueState.CLOSED created.closed_at = datetime.now(timezone.utc) backend.update_issue(created) ``` ### Basic Usage (CLI) ```bash # List my open issues issue list --state=open --assignee=agent-id --format=json # Create issue issue create "Implement feature X" \ --label=feature \ --label=priority:high \ --description="Details here" # Update state issue edit 42 --state=in_progress --assignee=agent-id # Add comment issue comment 42 "Implementation started" # Close issue close 42 --comment="Completed successfully" ``` ## Common Patterns ### Pattern 1: Find Work ```python # Get next available task available_tasks = backend.list_issues(IssueFilter( state='open', labels=['ready', 'needs-implementation'] )) # Filter to unassigned unassigned = [t for t in available_tasks if not t.assignees] if unassigned: task = unassigned[0] # Claim it... ``` ### Pattern 2: Claim Issue (Prevent Race Conditions) ```python def claim_issue(issue: Issue, agent_id: str) -> bool: """Claim an issue safely.""" # Check if already claimed if issue.assignees: return False # Already taken # Claim it issue.state = IssueState.IN_PROGRESS issue.assignees = [User(id=agent_id, username=agent_id)] backend.update_issue(issue) # Announce claim backend.add_comment(issue.id, Comment( id=None, body=f"🤖 Claimed by {agent_id}", author=User(id=agent_id, username=agent_id), created_at=datetime.now(timezone.utc) )) return True ``` ### Pattern 3: Progress Updates ```python def report_progress(issue: Issue, message: str, agent_id: str): """Report progress on an issue.""" backend.add_comment(issue.id, Comment( id=None, body=f"**Progress Update:**\n\n{message}", author=User(id=agent_id, username=agent_id), created_at=datetime.now(timezone.utc) )) ``` ### Pattern 4: Agent-to-Agent Communication ```python import json def post_agent_message(issue_id: str, msg_type: str, data: dict, agent_id: str): """Post structured message for other agents.""" message = { 'type': msg_type, 'agent': agent_id, 'timestamp': datetime.now(timezone.utc).isoformat(), 'data': data } backend.add_comment(issue_id, Comment( id=None, body=f"```agent-message\n{json.dumps(message, indent=2)}\n```", author=User(id=agent_id, username=agent_id), created_at=datetime.now(timezone.utc) )) def read_agent_messages(issue_id: str, msg_type: str = None): """Read messages from other agents.""" comments = backend.get_comments(issue_id) messages = [] for comment in comments: if '```agent-message' in comment.body: try: json_str = comment.body.split('```agent-message\n')[1].split('\n```')[0] msg = json.loads(json_str) if msg_type is None or msg['type'] == msg_type: messages.append(msg) except: continue return messages ``` ## Configuration Check Before using issue tracking, verify configuration: ```python def verify_issue_backend() -> bool: """Verify issue backend is configured.""" try: backend = GiteaBackend() backend.connect({ 'base_url': os.environ['GITEA_URL'], 'token': os.environ['GITEA_API_TOKEN'], 'owner': os.environ['GITEA_OWNER'], 'repo': os.environ['GITEA_REPO'] }) return backend.test_connection() except Exception as e: print(f"Issue backend not configured: {e}") return False # Use it if not verify_issue_backend(): print("ERROR: Issue tracking not available. Check configuration.") sys.exit(1) ``` ## Error Handling ```python from issue_tracker.backends.gitea.backend import GiteaAPIError try: issue = backend.get_issue_by_number(42) except GiteaAPIError as e: if e.status_code == 404: print("Issue not found") elif e.status_code == 401: print("Authentication failed - check GITEA_API_TOKEN") elif e.status_code == 429: print("Rate limited - wait and retry") else: print(f"API error: {e}") ``` ## Performance Tips 1. **Use filters** instead of fetching all issues: ```python # BAD: Get all, filter in Python all_issues = backend.list_issues() my_issues = [i for i in all_issues if i.assignees and i.assignees[0].username == 'me'] # GOOD: Filter at backend my_issues = backend.list_issues(IssueFilter(assignee='me')) ``` 2. **Use JSON output** for CLI parsing: ```bash issue list --format=json | jq '.[] | select(.state == "open")' ``` 3. **Batch comments** instead of rapid-fire updates 4. **Check local cache** before querying (if available) ## Troubleshooting ### "Backend not configured" ```bash # Check config issue backend list # If empty, configure export GITEA_API_TOKEN="your-token" issue backend add myproject gitea issue backend set-default myproject ``` ### "Authentication failed" ```bash # Verify token curl -H "Authorization: token $GITEA_API_TOKEN" $GITEA_URL/api/v1/user ``` ### "Issue not found" ```python # Use get_issue_by_number, not get_issue issue = backend.get_issue_by_number(42) # Correct # issue = backend.get_issue("42") # Wrong - needs backend_id ``` ## Full Documentation - **Integration Guide:** `AGENT_INTEGRATION.md` (comprehensive patterns and strategies) - **API Reference:** `CLAUDE.md` (for developers extending the capability) - **Examples:** `examples/agents/` (working agent implementations) - **Roadmap:** `ROADMAP.md` (upcoming features) ## Current Limitations (v1.0) Be aware of these limitations: 1. **Manual Configuration:** Backend must be configured before use (auto-detect in v1.1) 2. **User Context:** Uses hardcoded user for CLI operations (agent identity in v1.2) 3. **No Built-in Locking:** Use assignee + comment workaround for claiming (native in v1.2) 4. **Basic Conflicts:** Manual resolution required for complex sync conflicts (advanced in v2.0) Workarounds are documented in `AGENT_INTEGRATION.md`. ## Questions? If you're unsure whether to use this capability for something: **ASK:** "Does this involve creating, reading, updating, or searching issues?" - **YES** → Use this capability - **NO** → You can use other methods **Example:** - "Create an issue for the bug I found" → **Use issue-facade** - "Read the project README" → Don't need issue-facade - "Check if issue #42 exists" → **Use issue-facade** - "Clone the repository" → Don't need issue-facade