Files
issue-core/AGENT_INTEGRATION.md
tegwick b605d970e3 feat: rename to issue-core and add task ingestion endpoint
Renames the package, distribution, CLI alias, Makefile targets, and
working directory from issue-facade to issue-core, signalling its
role as the authoritative task lifecycle manager for the Coulomb org
(peer to activity-core, rules-core, project-core).

Adds POST /issues/ ingestion endpoint for activity-core's IssueSink,
under a new optional [api] extra. The endpoint is served by `issue
serve`, authenticates via the ISSUE_CORE_API_KEY env var (Bearer or
X-API-Key header), and routes the TaskSpec payload to the configured
default backend with full traceability metadata embedded in
sync_metadata.

- T01: Python package issue_tracker -> issue_core, dir rename
- T02: registered in state hub under custodian domain
- T03: INTENT.md (what it is, what it isn't, how it fits)
- T04: SCOPE.md (in/out-of-scope, integration boundaries)
- T05: POST /issues/ via FastAPI + Uvicorn, 9 unit tests
- T06: docs/nats-task-ingestion.md design stub

Closes ISSC-WP-0001.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 05:16:27 +02:00

676 lines
18 KiB
Markdown

# 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 <<INPUT
$GITEA_URL
$GITEA_OWNER
$GITEA_REPO
INPUT
issue backend set-default $(basename $(pwd))
```
## Performance Considerations
### Efficient Querying
```python
# 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
```python
# 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_core.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
```python
# 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-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