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>
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.jsonsupport issue config detectcommand
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 tasksmulti_agent_pipeline.py- Multiple agents in CI/CD-like workflowhuman_in_loop.py- Agents with human approval gatesmonitoring_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.mdfor development guide - Tests: Run
make testto verify installation - Issues: Report issues in the main markitect repository
License
MIT License - See LICENSE file