# Agent Integration Guide **Issue Core for Autonomous Coding Agent Coordination** ## Purpose The **Issue Core** capability provides a standardized interface for autonomous coding agents to coordinate project implementation through issue tracking. Instead of agents directly interfacing with platform-specific APIs (GitHub, GitLab, Gitea), they use a unified abstraction that works consistently across backends. ### Why Issue Tracking for Agent Coordination? Issue tracking provides a natural coordination mechanism for multi-agent software development: - **Task Distribution**: Issues represent discrete units of work that agents can claim and execute - **State Management**: Issue states (open, in_progress, closed) track progress across the team - **Communication Channel**: Comments enable inter-agent communication and human oversight - **Progress Visibility**: Labels, assignees, and milestones provide real-time project status - **Audit Trail**: Complete history of who did what and when - **Human Integration**: Human developers can seamlessly participate in agent-driven projects ## Current Status: Production-Ready with Manual Setup ### What Works Now (v1.0) ✅ **Complete CRUD Operations** - Create, read, update, delete issues - Full label management - User and assignee handling - Milestone operations - Comment threads ✅ **Gitea Backend** (Production-Ready) - Complete API integration - Rate limiting and error handling - State mapping (open/in_progress/blocked → open/closed) - Sync support with local backup ✅ **Local SQLite Backend** (Fully Functional) - Offline operation - Complete data model - Sync with remote backends - Fast queries and filtering ✅ **Agent-Friendly Features** - JSON output mode for machine parsing - Programmatic Python API - Comprehensive filtering - Batch operations - Type-safe models ### Current Limitations ⚠️ **Manual Configuration Required** - No auto-detection from git remotes (yet) - Backend configuration is manual one-time setup - No environment-variable-only mode (yet) ⚠️ **Hardcoded User Context** - CLI operations use "cli-user" placeholder - Agent identity needs to be managed externally ⚠️ **Basic Conflict Resolution** - Sync detects conflicts but doesn't auto-resolve - Manual intervention required for complex merges ## Quick Start for Agents ### 1. Installation ```bash cd capabilities/issue-core pip install -e . ``` ### 2. Backend Configuration (One-Time Setup) **For Gitea Projects:** ```bash # Configure Gitea backend export GITEA_API_TOKEN="your-token-here" issue backend add my-project gitea # Prompts for: # - Gitea URL: https://gitea.example.com # - Owner: your-org # - Repo: your-project # - Token: (reads from GITEA_API_TOKEN) # Verify connection issue backend test my-project # Set as default issue backend set-default my-project ``` **For Local/Offline Work:** ```bash # Configure local SQLite backend issue backend add local-work local # Prompts for: # - Database path: .issue-core/issues.db issue backend set-default local-work ``` ### 3. Basic Agent Operations ```bash # List open issues assigned to an agent issue list --state=open --assignee=agent-coder --format=json # Create a new issue issue create "Implement user authentication" \ --label=feature --label=priority:high \ --assignee=agent-coder # Update issue state issue edit 42 --state=in_progress # Add progress comment issue comment 42 "Completed database schema migration" # Close when done issue close 42 --comment="Implementation complete, tests passing" ``` ## Agent Workflow Patterns ### Pattern 1: Single Agent, Task Execution **Scenario**: One agent implements features from an issue backlog. ```bash #!/bin/bash # Agent workflow script # 1. Get next available task ISSUE=$(issue list --state=open --label=ready \ --format=json --limit=1 | jq -r '.[0].number') # 2. Claim the issue issue edit $ISSUE --assignee=agent-coder --state=in_progress issue comment $ISSUE "Starting implementation" # 3. Execute work # ... agent implements the feature ... # 4. Report completion issue comment $ISSUE "Implementation complete. Files changed: src/auth.py, tests/test_auth.py" issue close $ISSUE --comment="Ready for review" ``` ### Pattern 2: Multi-Agent Coordination **Scenario**: Multiple specialized agents work on different aspects. ```bash # Agent 1 (Coder) - Claims and implements issue list --label=needs-implementation --state=open --format=json | \ jq -r '.[0].number' | \ xargs -I {} issue edit {} --assignee=agent-coder --state=in_progress # Agent 2 (Reviewer) - Reviews completed work issue list --label=needs-review --state=closed --format=json | \ jq -r '.[0].number' | \ xargs -I {} sh -c 'issue comment {} "Code review complete. Approved."' # Agent 3 (Tester) - Runs tests on reviewed code issue list --label=reviewed --state=closed --format=json | \ jq -r '.[0].number' | \ xargs -I {} sh -c 'issue comment {} "All tests passing. Deploying to staging."' ``` ### Pattern 3: Agent-Human Collaboration **Scenario**: Agents implement, humans review and approve. ```python # Agent creates implementation issues from requirements from issue_core.backends.gitea import GiteaBackend from issue_core.core.models import Issue, Label, IssueState from datetime import datetime, timezone backend = GiteaBackend() backend.connect({ 'base_url': 'https://gitea.example.com', 'token': os.environ['GITEA_API_TOKEN'], 'owner': 'myorg', 'repo': 'myproject' }) # Agent breaks down feature into tasks feature_issue = backend.get_issue_by_number(100) subtasks = [ "Implement database schema", "Create API endpoints", "Add frontend components", "Write integration tests" ] for task in subtasks: issue = Issue( id=None, number=0, title=f"{feature_issue.title}: {task}", description=f"Subtask of #{feature_issue.number}\n\n{task}", state=IssueState.OPEN, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc), labels=[ Label(name="agent-generated"), Label(name="needs-implementation"), Label(name="parent:100") ] ) backend.create_issue(issue) # Human reviews and approves/rejects via comments # Agent monitors for approval comments and proceeds ``` ## Programmatic API for Agents ### Python Integration ```python from issue_core.backends.gitea import GiteaBackend from issue_core.core.models import Issue, Label, IssueState, User from issue_core.core.interfaces import IssueFilter from datetime import datetime, timezone import os # Initialize backend 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'] }) # Query issues filter_criteria = IssueFilter( state='open', labels=['bug', 'priority:high'], assignee='agent-coder', limit=10 ) issues = backend.list_issues(filter_criteria) # Create issue new_issue = Issue( id=None, number=0, title="Fix memory leak in parser", description="Detected memory leak in parse_document() function", state=IssueState.OPEN, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc), labels=[ Label(name="bug"), Label(name="priority:critical"), Label(name="agent-detected") ], assignees=[User(id="agent-coder", username="agent-coder")] ) created = backend.create_issue(new_issue) # Update issue created.state = IssueState.IN_PROGRESS backend.update_issue(created) # Add comment from issue_core.core.models import Comment comment = Comment( id=None, body="Analysis complete. Root cause: unclosed file handles in line 234", author=User(id="agent-coder", username="agent-coder"), created_at=datetime.now(timezone.utc) ) backend.add_comment(created.id, comment) # Close issue created.state = IssueState.CLOSED created.closed_at = datetime.now(timezone.utc) backend.update_issue(created) ``` ### Advanced Filtering ```python # Get all high-priority bugs not assigned critical_bugs = backend.list_issues(IssueFilter( state='open', labels=['bug', 'priority:critical'] )) unassigned = [i for i in critical_bugs if not i.assignees] # Get stale issues (not updated in 7 days) from datetime import timedelta stale_threshold = datetime.now(timezone.utc) - timedelta(days=7) stale_issues = backend.list_issues(IssueFilter( state='open', updated_before=stale_threshold )) # Search by text search_results = backend.search_issues("authentication", limit=20) ``` ## Agent Coordination Strategies ### Strategy 1: Label-Based Role Assignment Use labels to indicate agent specialization: ```python # Agent types AGENT_ROLES = { 'agent:coder': ['feature', 'bug', 'refactor'], 'agent:tester': ['needs-testing', 'test-failure'], 'agent:reviewer': ['needs-review', 'code-quality'], 'agent:documenter': ['documentation', 'api-docs'] } # Each agent filters by their role def get_agent_tasks(agent_type): role_labels = AGENT_ROLES[agent_type] all_tasks = [] for label in role_labels: tasks = backend.list_issues(IssueFilter( state='open', labels=[label, agent_type] )) all_tasks.extend(tasks) return all_tasks ``` ### Strategy 2: State Machine Workflow Use issue states to track progress through pipeline: ``` open → in_progress → needs_review → closed ↓ ↓ ↓ blocked blocked blocked ``` ```python def advance_issue_state(issue_number): issue = backend.get_issue_by_number(issue_number) state_transitions = { IssueState.OPEN: IssueState.IN_PROGRESS, IssueState.IN_PROGRESS: IssueState.CLOSED # or needs_review } if issue.state in state_transitions: issue.state = state_transitions[issue.state] backend.update_issue(issue) return True return False ``` ### Strategy 3: Comment-Based Communication Use structured comments for agent-to-agent messages: ```python import json def post_agent_message(issue_id, message_type, data): """Post structured message for other agents""" message = { 'type': message_type, 'agent': 'agent-coder', 'timestamp': datetime.now(timezone.utc).isoformat(), 'data': data } comment = Comment( id=None, body=f"```agent-message\n{json.dumps(message, indent=2)}\n```", author=User(id="agent-coder", username="agent-coder"), created_at=datetime.now(timezone.utc) ) backend.add_comment(issue_id, comment) def read_agent_messages(issue_id, message_type=None): """Read structured 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 message_type is None or msg['type'] == message_type: messages.append(msg) except (IndexError, json.JSONDecodeError): continue return messages # Usage: post_agent_message(42, 'implementation_complete', { 'files_changed': ['src/auth.py', 'tests/test_auth.py'], 'tests_passing': True, 'coverage': 95.2 }) # Later, reviewer agent reads: results = read_agent_messages(42, 'implementation_complete') ``` ## Synchronization and Backup ### Sync Local and Remote ```bash # Pull all issues to local backup issue backend add backup local issue sync pull gitea-remote backup # Work offline with local backend issue backend set-default backup issue create "Offline work item" --label=offline # Sync back when online issue sync push backup gitea-remote ``` ### Conflict Handling ```python # Check for conflicts before sync from issue_core.cli.sync_commands import sync_pull try: sync_pull(source='remote', target='local', dry_run=True) except ConflictError as e: # Conflicts detected for conflict in e.conflicts: print(f"Conflict on issue {conflict['issue_number']}") print(f" Local updated: {conflict['local_updated']}") print(f" Remote updated: {conflict['remote_updated']}") # Resolve by choosing newer timestamp sync_pull(source='remote', target='local', force=True) ``` ## Current Workarounds for Limitations ### Workaround 1: Agent Identity Since "cli-user" is hardcoded, use labels or comments to indicate agent: ```python # Add agent identifier to all operations agent_id = "agent-coder-v1" # In issue creation labels.append(Label(name=f"created-by:{agent_id}")) # In comments comment.body = f"[{agent_id}] {actual_message}" ``` ### Workaround 2: Issue Claiming No built-in locking, so use assignee + comment: ```python def claim_issue(issue_number, agent_id, timeout_minutes=30): issue = backend.get_issue_by_number(issue_number) # Check if already claimed if issue.assignees: # Check claim age from comments comments = backend.get_comments(issue.id) claim_comments = [c for c in comments if 'CLAIMED' in c.body] if claim_comments: last_claim = claim_comments[-1].created_at age = datetime.now(timezone.utc) - last_claim if age.total_seconds() < timeout_minutes * 60: return False # Still claimed # Claim it issue.assignees = [User(id=agent_id, username=agent_id)] issue.state = IssueState.IN_PROGRESS backend.update_issue(issue) backend.add_comment(issue.id, Comment( id=None, body=f"CLAIMED by {agent_id} at {datetime.now(timezone.utc).isoformat()}", author=User(id=agent_id, username=agent_id), created_at=datetime.now(timezone.utc) )) return True ``` ### Workaround 3: Manual Repository Configuration Create a setup script for each project: ```bash #!/bin/bash # setup-issue-tracking.sh cat > .issue-core-config << EOF GITEA_URL=https://gitea.example.com GITEA_OWNER=myorg GITEA_REPO=myproject GITEA_TOKEN_FILE=~/.secrets/gitea-token EOF # Load config and configure backend source .issue-core-config export GITEA_API_TOKEN=$(cat $GITEA_TOKEN_FILE) issue backend add $(basename $(pwd)) gitea < 60: get_open_issues_cached.cache_clear() last_fetch = time.time() ``` ## Roadmap: Future Enhancements ### Phase 1: Auto-Configuration (v1.1) - Automatic git remote detection - Environment-variable-only setup - Per-repository `.issue-core/config.json` support - `issue config detect` command ### Phase 2: Agent Features (v1.2) - Agent identity management - Issue claiming/locking API - Structured metadata fields for agent state - Webhook support for reactive agents ### Phase 3: Advanced Coordination (v2.0) - Issue dependency tracking - Query DSL: `is:open assignee:me label:bug,critical` - Activity streams and event logs - Multi-agent conflict resolution strategies - Distributed locking for concurrent operations ## Examples Repository See `examples/agents/` for complete working examples: - `simple_task_executor.py` - Single agent claiming and executing tasks - `multi_agent_pipeline.py` - Multiple agents in CI/CD-like workflow - `human_in_loop.py` - Agents with human approval gates - `monitoring_agent.py` - Agent that monitors issue health and sends alerts ## Troubleshooting ### "Backend not configured" ```bash # List configured backends issue backend list # If empty, configure one issue backend add myproject gitea ``` ### "Authentication failed" ```bash # Check token is valid issue backend test myproject # Reconfigure with correct token export GITEA_API_TOKEN="new-token" issue backend remove myproject issue backend add myproject gitea ``` ### "Issue not found" ```python # Gitea uses backend_id, not number issue = backend.get_issue_by_number(42) # Correct # issue = backend.get_issue("42") # Wrong - needs backend_id ``` ### "Sync conflicts" ```bash # Force sync (overwrites target) issue sync pull source target --force # Or manually resolve issue list --backend=source --format=json > source.json issue list --backend=target --format=json > target.json # Compare and decide which to keep ``` ## Support - **Documentation**: See `CLAUDE.md` for development guide - **Tests**: Run `make test` to verify installation - **Issues**: Report issues in the main markitect repository ## License MIT License - See LICENSE file