# 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 ```bash 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. ```bash 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 ` or `X-API-Key: `. See `SCOPE.md` "TaskSpec payload" for the request schema, or visit `http://:/docs` once the server is running for live OpenAPI docs. ### Configuration (One-Time Setup) **For Gitea-backed projects:** ```bash # 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:** ```bash issue backend add local-work local # Prompts for: database path (.issue-core/issues.db) issue backend set-default local-work ``` ### Basic Usage ```bash # 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](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: ```python 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): ```bash # 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: ```bash # 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 ```bash 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 ```bash issue backend list issue backend add NAME TYPE issue backend remove NAME issue backend test NAME issue backend set-default NAME ``` ### Synchronization ```bash issue sync status issue sync pull SOURCE TARGET [--dry-run] [--force] issue sync push SOURCE TARGET issue sync bidirectional BACKEND1 BACKEND2 ``` ## Development ### Testing ```bash # 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 ```bash # 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 - **[INTENT.md](INTENT.md)** — why issue-core exists (work-record-aligned connector) - **[SCOPE.md](SCOPE.md)** — shipped inventory and product boundary - **[docs/uuid-external-id-mapping.md](docs/uuid-external-id-mapping.md)** — mapping design - **[docs/boundary-sync-and-status-mapping.md](docs/boundary-sync-and-status-mapping.md)** — dual-lifecycle policy - **[AGENT_INTEGRATION.md](AGENT_INTEGRATION.md)** — programmatic API for tracker backends - **[ROADMAP.md](ROADMAP.md)** — feature trajectory (connector-aligned) - Work-record canon: `the-custodian/canon/standards/work-record-types_v0.1.md` - Architecture §4.2: `the-custodian/research/WorkOrchestrationArchitectureDraft.md` ### Work-record projection (mapping) ```bash # Project a work record to the default backend (idempotent) issue project --title "External title" --canonical-id ISSUE-WP-0005-T05 # Link an existing tracker issue issue map link 42 # Resolve / detach / outward status push issue map show --uuid issue map push-status --uuid --status progress issue map detach --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