Files
issue-core/AGENT_INTEGRATION.md
tegwick 324453bd8d feat: transform to agent coordination platform with comprehensive documentation
Transform Issue Facade from a universal CLI tool into an agent coordination platform with comprehensive documentation and enhanced capabilities for autonomous coding agents.

Major Changes:
- Complete README rewrite focusing on agent-driven coordination
- New comprehensive documentation (AGENT_INTEGRATION.md, CLAUDE.md, ROADMAP.md)
- Capability integration setup with CAPABILITY.yaml and integration scripts
- Enhanced Makefile with local development targets for easier workflows

Bug Fixes:
- Fix schema initialization using executescript() for multi-line SQL support
- Disable FTS5 triggers due to compatibility issues (documented for future re-enablement)

Features:
- Enhanced CLI list command with full parameter passthrough
- New examples directory with agent integration patterns
- New comprehensive test suite (test_core_models.py, test_local_backend.py)

Code Quality:
- Remove @cached_property decorators for Label properties (simplification)
- Clean up test organization (removed old test_gitea_integration.py)

This milestone establishes Issue Facade as a production-ready coordination layer for multi-agent software development, with clear integration paths and comprehensive developer documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 19:32:37 +01:00

18 KiB

Agent Integration Guide

Issue Facade for Autonomous Coding Agent Coordination

Purpose

The Issue Facade 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

cd capabilities/issue-facade
pip install -e .

2. Backend Configuration (One-Time Setup)

For Gitea Projects:

# 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:

# Configure local SQLite backend
issue backend add local-work local
# Prompts for:
# - Database path: .issue-facade/issues.db

issue backend set-default local-work

3. Basic Agent Operations

# 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.

#!/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.

# 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.

# Agent creates implementation issues from requirements
from issue_tracker.backends.gitea import GiteaBackend
from issue_tracker.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

from issue_tracker.backends.gitea import GiteaBackend
from issue_tracker.core.models import Issue, Label, IssueState, User
from issue_tracker.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_tracker.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

# 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:

# 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
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:

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

# 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

# Check for conflicts before sync
from issue_tracker.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:

# 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:

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:

#!/bin/bash
# setup-issue-tracking.sh

cat > .issue-facade-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-facade-config
export GITEA_API_TOKEN=$(cat $GITEA_TOKEN_FILE)

issue backend add $(basename $(pwd)) gitea <<INPUT
$GITEA_URL
$GITEA_OWNER
$GITEA_REPO
INPUT

issue backend set-default $(basename $(pwd))

Performance Considerations

Efficient Querying

# BAD: Get all issues then filter in Python
all_issues = backend.list_issues()
my_issues = [i for i in all_issues if i.assignees and i.assignees[0].username == 'agent-coder']

# GOOD: Use backend filtering
my_issues = backend.list_issues(IssueFilter(
    assignee='agent-coder',
    state='open'
))

Batch Operations

# BAD: Update issues one by one
for issue_number in [1, 2, 3, 4, 5]:
    issue = backend.get_issue_by_number(issue_number)
    issue.labels.append(Label(name="batch-processed"))
    backend.update_issue(issue)

# GOOD: Use local backend for bulk operations
from issue_tracker.backends.local import LocalSQLiteBackend

local = LocalSQLiteBackend()
local.connect({'db_path': '/tmp/batch.db'})

# Pull from remote
for issue_number in [1, 2, 3, 4, 5]:
    issue = backend.get_issue_by_number(issue_number)
    local.create_issue(issue)

# Bulk update locally
issues = local.list_issues()
for issue in issues:
    issue.labels.append(Label(name="batch-processed"))
    local.update_issue(issue)

# Push back to remote
for issue in local.list_issues():
    backend.update_issue(issue)

Caching

# Cache issue list for short-lived operations
import functools
import time

@functools.lru_cache(maxsize=1)
def get_open_issues_cached():
    return backend.list_issues(IssueFilter(state='open'))

# Invalidate cache after 60 seconds
last_fetch = time.time()
if time.time() - last_fetch > 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-facade/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"

# List configured backends
issue backend list

# If empty, configure one
issue backend add myproject gitea

"Authentication failed"

# 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"

# 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"

# 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