issue-core/README.md
tegwick f88e9a28fe
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 1m22s
feat: implement ISSUE-WP-0005 connector mapping and scope alignment
Add MappingService (work_record_uuid ↔ external id), project/map CLI with
outward push-status, optional TaskSpec work_record fields, boundary-sync
policy, and packaging/capability framing cleanup. Mark WP-0005 finished.
2026-07-22 00:25:06 +02:00

15 KiB

Issue Core — External Tracker Connector

A backend-agnostic connector to third-party issue trackers (Gitea/Forgejo, GitHub, …), not the fleet's internal work-origin or coordination substrate.

Purpose

issue-core is a standardized abstraction layer for talking to external issue-tracking backends (Gitea, GitHub, GitLab, local SQLite cache). Instead of each agent or automation implementing platform-specific APIs, they use one consistent CLI and Python interface — and, going forward, a durable work-record UUID ↔ external issue id mapping when a tracker projection is switched on.

Fleet coordination vs external trackers

Internal fleet work is not originated here. Work records (workplans, tasks, intake, decisions, …) live as repo files (ADR-001) and are indexed by state-hub under the work-record types canon — see the-custodian/canon/standards/work-record-types_v0.1.md and the-custodian/research/WorkOrchestrationArchitectureDraft.md §4.2.

issue-core's role (founder-reviewed, 2026-07-20):

  • Connector to external issue-tracking systems when collaboration requires them
  • Mapping between internal work-record UUIDs and external issue ids (design: docs/uuid-external-id-mapping.md)
  • Two-way boundary sync when a third-party tracker is actually in use
  • Zero load on the internal loop until an external integration is switched on

External trackers remain useful for:

  • Human / open-source collaboration on GitHub, Forgejo, Jira, etc.
  • Communication via comments when the counterparty lives in that UI
  • Visibility for people who only watch the tracker, not the fleet hub
  • Optional projection of a work record outward (not birth of the work record)

For agent coordination inside the Coulomb fleet, use work records + state-hub, not Forgejo as the default task board. See INTENT.md and SCOPE.md.

Current Status

Production-ready core with manual setup (v1.0)

Fully Implemented:

  • Complete CRUD operations (issues, labels, users, milestones, comments)
  • Gitea backend (production-ready with full API integration)
  • Local SQLite backend (offline work with sync capability)
  • CLI with JSON output for machine parsing
  • Python API for programmatic access
  • Comprehensive filtering and search
  • Basic synchronization between backends

⚠️ Current Limitations:

  • Manual backend configuration required (one-time setup per project)
  • No auto-detection from git remotes (coming in v1.1)
  • Basic conflict resolution (manual intervention for complex cases)
  • Hardcoded user context (agents need external identity management)

Quick Start

Installation

cd capabilities/issue-core
pip install -e .                  # CLI only
pip install -e ".[api]"           # CLI + REST ingestion server

REST Server (intentional external issues)

issue-core exposes POST /issues/ for authenticated clients that deliberately create external tracker issues. This is not the primary fleet path for originating work (work records start as repo files). activity-core's IssueSink may call this only when an external issue is intentional policy — not as an always-on landing zone for internal findings.

export ISSUE_CORE_API_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
issue serve --host 0.0.0.0 --port 8765

Clients authenticate with Authorization: Bearer <key> or X-API-Key: <key>. See SCOPE.md "TaskSpec payload" for the request schema, or visit http://<host>:<port>/docs once the server is running for live OpenAPI docs.

Configuration (One-Time Setup)

For Gitea-backed projects:

# Set your Gitea token
export GITEA_API_TOKEN="your-token-here"

# Configure backend
issue backend add myproject gitea
# Prompts for: URL, owner, repo (reads token from environment)

# Set as default
issue backend set-default myproject

# Verify
issue backend test myproject

For local/offline work:

issue backend add local-work local
# Prompts for: database path (.issue-core/issues.db)

issue backend set-default local-work

Basic Usage

# List issues (JSON output for agents)
issue list --format=json

# Create issue
issue create "Implement user authentication" \
  --label=feature --label=priority:high

# Update state
issue edit 42 --state=in_progress --assignee=agent-coder

# Add comment
issue comment 42 "Implementation complete, tests passing"

# Close issue
issue close 42 --comment="Ready for review"

Agent Integration

Prefer work records + state-hub for fleet task lifecycle. Use issue-core when an agent must operate on an external tracker (project a task, update a Forgejo/GitHub issue, sync comments at the boundary).

See AGENT_INTEGRATION.md for:

  • Programmatic Python API usage
  • Multi-agent patterns against tracker backends (not as the fleet board)
  • Label-based filters and state machine workflows on external issues
  • Comment-based communication when the counterparty is in the tracker UI
  • Workarounds for current limitations
  • Performance optimization tips

Quick example:

from issue_core.backends.gitea import GiteaBackend
from issue_core.core.interfaces import IssueFilter

# Initialize
backend = GiteaBackend()
backend.connect(config)

# Query issues for agent
issues = backend.list_issues(IssueFilter(
    state='open',
    labels=['bug', 'priority:critical'],
    assignee='agent-coder'
))

# Process each issue
for issue in issues:
    # Agent implements fix
    result = agent.fix_bug(issue)

    # Report back
    issue.state = IssueState.CLOSED
    backend.update_issue(issue)

Architecture

Facade Pattern with Plugin Backends

┌─────────────────────────────────────┐
│      CLI Layer (Click)              │
│   issue list | create | edit        │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│   Core Domain Models                │
│   (Issue, Label, User, etc.)        │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│   Backend Interface (ABC)           │
│   IssueBackend, SyncableBackend     │
└──────────────┬──────────────────────┘
               │
       ┌───────┴────────┐
       │                │
┌──────▼─────┐   ┌──────▼──────┐
│   Local    │   │   Gitea     │
│  (SQLite)  │   │  (REST API) │
└────────────┘   └─────────────┘

Key Design Principles:

  • Backend-agnostic core models
  • Plugin architecture for easy backend addition
  • Type-safe interfaces with comprehensive testing
  • Sync support for offline/online workflows

Supported Backends

Backend Status Features
Gitea Production Full API, rate limiting, state mapping
Local SQLite Production Offline work, fast queries, sync support
GitHub 🚧 Planned (v1.1) Full API integration
GitLab 🚧 Planned (v1.2) Full API integration

Use Cases

1. External tracker ops (when a backend is in use)

Agents or humans work issues that already live in Gitea/GitHub (e.g. OSS inbound, customer Jira, or an intentional projection):

# List open external issues for a label
issue list --label=needs-implementation --format=json

# Claim and update state on the tracker
issue edit 42 --assignee=agent-coder --state=in_progress
issue comment 42 "Implementation complete, tests passing"
issue close 42 --comment="Ready for review"

Fleet-internal task claim/execute should use workplan task status in the repo

  • state-hub, not Forgejo by default.

2. Human collaboration through a tracker UI

When the counterparty only uses GitHub/Gitea, project or update the external issue and keep comments there. Mapping design (UUID ↔ external id) will tie that projection back to the work record — see docs/uuid-external-id-mapping.md.

3. Offline development with sync

Work offline with local backend, sync when online:

# Setup local backup
issue backend add backup local
issue sync pull gitea-production backup

# Work offline
issue backend set-default backup
issue create "Offline tracker note" --label=offline

# Sync back
issue sync push backup gitea-production

CLI Commands Reference

Issue Operations

issue list [--state STATE] [--label LABEL] [--assignee USER] [--format FORMAT]
issue show ISSUE_NUMBER [--comments] [--format FORMAT]
issue create TITLE [--description DESC] [--label LABEL] [--assignee USER]
issue edit ISSUE_NUMBER [--title TITLE] [--state STATE] [--add-label LABEL]
issue close ISSUE_NUMBER [--comment COMMENT]
issue reopen ISSUE_NUMBER [--comment COMMENT]
issue comment ISSUE_NUMBER BODY

Backend Management

issue backend list
issue backend add NAME TYPE
issue backend remove NAME
issue backend test NAME
issue backend set-default NAME

Synchronization

issue sync status
issue sync pull SOURCE TARGET [--dry-run] [--force]
issue sync push SOURCE TARGET
issue sync bidirectional BACKEND1 BACKEND2

Development

Testing

# Install with dev dependencies
make install-dev

# Run all tests (109 tests, 61% coverage)
make test

# Run with coverage report
make test-cov

# Run only unit tests
make test-unit

Code Quality

# Run linter
make issue-core-lint

# Format code
black issue_core/ tests/

# Type check
mypy issue_core/

Project Structure

issue-core/
├── issue_core/
│   ├── core/              # Domain models and interfaces
│   │   ├── models.py      # Issue, Label, User, etc.
│   │   └── interfaces.py  # IssueBackend, SyncableBackend
│   ├── backends/
│   │   ├── gitea/         # Gitea backend implementation
│   │   └── local/         # SQLite backend implementation
│   └── cli/               # Click-based CLI
│       ├── commands.py    # Issue operations
│       ├── backend_commands.py
│       └── sync_commands.py
├── tests/                 # 109 tests, comprehensive coverage
├── examples/              # Agent integration examples
├── AGENT_INTEGRATION.md   # Agent coordination guide
├── CLAUDE.md             # Development guide for Claude Code
└── ROADMAP.md            # Future enhancements

Documentation

Work-record projection (mapping)

# Project a work record to the default backend (idempotent)
issue project <work-record-uuid> --title "External title" --canonical-id ISSUE-WP-0005-T05

# Link an existing tracker issue
issue map link <work-record-uuid> 42

# Resolve / detach / outward status push
issue map show --uuid <work-record-uuid>
issue map push-status --uuid <work-record-uuid> --status progress
issue map detach --uuid <work-record-uuid>

Mappings live in ~/.config/issue-tracker/mappings.db (bookkeeping), independent of whether CRUD targets Gitea or local SQLite.

Roadmap (summary)

Connector alignment (docs — ISSUE-WP-0004)

  • INTENT / SCOPE / README framing as external connector
  • UUID ↔ external-id mapping design

v1.1 - Auto-Configuration

  • Automatic git remote detection
  • Environment-variable-only setup
  • Per-repository configuration files
  • issue config detect command

Mapping + boundary sync (stage-3 work-record architecture)

  • Persist work-record UUID ↔ backend issue id
  • Optional two-way sync when a tracker is switched on
  • No load when integrations are off

Further backends / agent helpers

  • GitHub, GitLab, Jira backends
  • Claiming helpers for external issues
  • Webhooks for tracker-side events

Comparison with Platform CLIs

Feature Issue Core gh (GitHub) glab (GitLab)
Multi-backend support Yes GitHub only GitLab only
Offline capability Local SQLite No No
Agent-friendly API Python + JSON ⚠️ CLI only ⚠️ CLI only
Consistent interface Same across all Platform-specific Platform-specific
Backend sync Yes No No
Auto-configuration 🚧 Coming v1.1 Yes Yes

Contributing

The Issue Core is designed to be extensible:

To add a new backend:

  1. Implement the IssueBackend interface (see core/interfaces.py)
  2. Handle platform-specific API details in your backend
  3. Map platform models to/from core domain models
  4. Add comprehensive tests
  5. Register in BackendFactory

Backend implementation checklist:

  • All CRUD operations (issues, labels, users, milestones, comments)
  • State mapping to/from platform-specific states
  • Error handling and rate limiting
  • Sync support (if applicable)
  • Integration tests with mock API
  • Documentation

See existing backends (Gitea, Local) as reference implementations.

Why "Facade" / connector?

The Facade Pattern still describes the implementation style:

"Provide a unified interface to a set of interfaces in a subsystem." — Gang of Four, Design Patterns

Instead of agents learning different APIs for GitHub (gh), GitLab (glab), Gitea, JIRA, etc., they use one consistent interface. The facade does not replace issue trackers — and it does not replace work records as the origin of fleet work. It connects the fleet to trackers at the boundary.

License

MIT License - See LICENSE file