diff --git a/.claude/rules/repo-identity.md b/.claude/rules/repo-identity.md
index f2c71e2..fec783c 100644
--- a/.claude/rules/repo-identity.md
+++ b/.claude/rules/repo-identity.md
@@ -1,4 +1,4 @@
-**Purpose:** Authoritative task lifecycle manager for the Coulomb org. Backend-agnostic CLI + REST ingestion endpoint for tasks from activity-core's IssueSink. Pluggable backends (Gitea, SQLite, GitHub). Renamed from issue-facade on 2026-05-17.
+**Purpose:** Authoritative task lifecycle manager for the Coulomb org. Backend-agnostic CLI + REST ingestion endpoint for tasks from activity-core's IssueSink. Pluggable backends (Forgejo, SQLite, GitHub). Renamed from issue-facade on 2026-05-17.
**Domain:** infotech
**Repo slug:** issue-core
diff --git a/AGENTS.md b/AGENTS.md
index 6b1ef81..038ec25 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,7 +2,7 @@
## Repo Identity
-**Purpose:** Authoritative task lifecycle manager for the Coulomb org. Backend-agnostic CLI + REST ingestion endpoint for tasks from activity-core's IssueSink. Pluggable backends (Gitea, SQLite, GitHub). Renamed from issue-facade on 2026-05-17.
+**Purpose:** Authoritative task lifecycle manager for the Coulomb org. Backend-agnostic CLI + REST ingestion endpoint for tasks from activity-core's IssueSink. Pluggable backends (Forgejo, SQLite, GitHub). Renamed from issue-facade on 2026-05-17.
**Domain:** infotech
**Repo slug:** issue-core
diff --git a/AGENT_INTEGRATION.md b/AGENT_INTEGRATION.md
index 297ca95..6a0daeb 100644
--- a/AGENT_INTEGRATION.md
+++ b/AGENT_INTEGRATION.md
@@ -1,24 +1,55 @@
# Agent Integration Guide
-**Issue Core for Autonomous Coding Agent Coordination**
+**Issue Core for external tracker projection** — not the fleet ops queue.
## Purpose
-The **Issue Core** capability provides a standardized interface for autonomous coding agents to operate on **external issue trackers** (GitHub, GitLab, Gitea/Forgejo). Instead of agents learning platform-specific APIs, they use a unified abstraction.
+The **Issue Core** capability provides a standardized interface for autonomous
+coding agents to operate on **external issue trackers** (Forgejo, GitHub,
+GitLab, Jira). Instead of agents learning platform-specific APIs, they use a
+unified abstraction. The self-hosted forge is **Forgejo** only; the HTTP API
+is Gitea-compatible (`issue_core.backends.gitea`, backend type `gitea`).
-**Fleet note (2026-07-20):** Internal work originates as repo work records (ADR-001 / work-record canon), not as issue-core issues. Use this guide when an agent must project to or work inside a third-party tracker. See `INTENT.md` and `docs/uuid-external-id-mapping.md`.
+**Fleet note (2026-07-20 / ISSUE-WP-0006):** Internal work originates as repo
+work records (ADR-001 / work-record canon), not as issue-core issues. Use this
+guide when an agent must project to or work inside a third-party tracker. See
+`INTENT.md` and `docs/uuid-external-id-mapping.md`.
+
+### Happy path (projection, not automation loop)
+
+```
+ 1. Author work record in repo (ADR-001)
+ │
+ │ fix-consistency
+ v
+ state-hub index (UUIDv7 write-back)
+ │
+ │ optional project / link
+ v
+ 2. issue-core ──► Forgejo (or GitHub / Jira later)
+ 3. mapping: work-record UUID ↔ (backend=forgejo, external_id)
+ stored backend type string is currently `gitea`
+ (Forgejo Gitea-compatible API)
+```
+
+Internal scheduled automation (FI/Binky, mail, …) does **not** follow
+`activity-core → issue-core → harness`. That path is **legacy / external
+tickets only**. Claim/execute for fleet ops is activity-core **`ops_run`**
+(ACT-ADR-005). See rein-aharness `docs/task-intake.md` and ISSUE-WP-0006.
### When to use a tracker (and when not to)
-**Fleet claim/execute** runs on work records (repo files + state-hub), not on
-Forgejo by default. Use issue-core when:
+**Fleet claim/execute** runs on work records (repo files + state-hub) or on
+`ops_run` for scheduled automation — not on Forgejo by default. Use
+issue-core when:
-- A counterparty or OSS workflow lives in Gitea/GitHub/Jira
+- A counterparty or OSS workflow lives in Forgejo/GitHub/Jira
- You need to **project or link** a work record (`issue project` / `issue map`)
- You must update or comment on an **external** issue already in a tracker
-Do **not** treat issue-core as the org task board or as origin of intake/tasks.
-Findings → `kind: intake` + promotion; optional later projection.
+Do **not** treat issue-core as the org task board, the ops claim queue, or
+the origin of intake/tasks. Findings → `kind: intake` + promotion; optional
+later projection.
## Current Status: Production-Ready with Manual Setup
@@ -31,7 +62,7 @@ Findings → `kind: intake` + promotion; optional later projection.
- Milestone operations
- Comment threads
-✅ **Gitea Backend** (Production-Ready)
+✅ **Forgejo Backend** (Production-Ready; Gitea-compatible API)
- Complete API integration
- Rate limiting and error handling
- State mapping (open/in_progress/blocked → open/closed)
@@ -76,18 +107,19 @@ pip install -e .
### 2. Backend Configuration (One-Time Setup)
-**For Gitea Projects:**
+**For Forgejo Projects:**
```bash
-# Configure Gitea backend
-export GITEA_API_TOKEN="your-token-here"
+# Configure Forgejo backend (type string `gitea` = Gitea-compatible API)
+export FORGEJO_TOKEN="your-token-here"
+# Deprecated aliases: FORGEJO_API_TOKEN, GITEA_API_TOKEN, GITEA_TOKEN
issue backend add my-project gitea
# Prompts for:
-# - Gitea URL: https://gitea.example.com
+# - Forgejo URL: https://forgejo.example.com
# - Owner: your-org
# - Repo: your-project
-# - Token: (reads from GITEA_API_TOKEN)
+# - Token: (reads FORGEJO_TOKEN, then deprecated GITEA_* aliases)
# Verify connection
issue backend test my-project
@@ -187,8 +219,8 @@ from datetime import datetime, timezone
backend = GiteaBackend()
backend.connect({
- 'base_url': 'https://gitea.example.com',
- 'token': os.environ['GITEA_API_TOKEN'],
+ 'base_url': os.environ.get('FORGEJO_URL', 'https://forgejo.example.com'),
+ 'token': os.environ.get('FORGEJO_TOKEN') or os.environ['GITEA_API_TOKEN'],
'owner': 'myorg',
'repo': 'myproject'
})
@@ -236,10 +268,10 @@ 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']
+ 'base_url': os.environ.get('FORGEJO_URL') or os.environ['GITEA_URL'],
+ 'token': os.environ.get('FORGEJO_TOKEN') or os.environ.get('FORGEJO_API_TOKEN') or os.environ['GITEA_API_TOKEN'],
+ 'owner': os.environ.get('FORGEJO_OWNER') or os.environ['GITEA_OWNER'],
+ 'repo': os.environ.get('FORGEJO_REPO') or os.environ['GITEA_REPO']
})
# Query issues
@@ -421,14 +453,14 @@ results = read_agent_messages(42, 'implementation_complete')
```bash
# Pull all issues to local backup
issue backend add backup local
-issue sync pull gitea-remote backup
+issue sync pull forgejo-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
+issue sync push backup forgejo-remote
```
### Conflict Handling
@@ -509,20 +541,20 @@ Create a setup script for each project:
# 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
+FORGEJO_URL=https://forgejo.example.com
+FORGEJO_OWNER=myorg
+FORGEJO_REPO=myproject
+FORGEJO_TOKEN_FILE=~/.secrets/forgejo-token
EOF
# Load config and configure backend
source .issue-core-config
-export GITEA_API_TOKEN=$(cat $GITEA_TOKEN_FILE)
+export FORGEJO_TOKEN=$(cat $FORGEJO_TOKEN_FILE)
issue backend add $(basename $(pwd)) gitea <
- Backend-agnostic connector to external issue trackers (Gitea/Forgejo, SQLite).
+ Backend-agnostic connector to external issue trackers (Forgejo, SQLite).
Maps work-record UUIDs to external issue ids. Not the origin of fleet work records.
# What problems this capability solves
purpose:
primary: External tracker projection and ops (work-record-aware connector)
problems_solved:
- - Direct API calls to Gitea/GitHub/GitLab (credential sprawl)
+ - Direct API calls to Forgejo/GitHub/GitLab (credential sprawl)
- No durable link from work-record UUID to tracker issue
- Platform-specific agent code for tracker CRUD
- Offline SQLite cache / backend sync for tracker data
@@ -21,7 +21,7 @@ purpose:
# When agents should use this capability
usage_rules:
MUST_USE_INSTEAD_OF:
- - "Direct Gitea API calls (requests.post to /api/v1/repos/...)"
+ - "Direct Forgejo API calls (requests.post to /api/v1/repos/...)"
- "GitHub CLI (gh issue create/list/...)"
- "GitLab CLI (glab issue create/list/...)"
- "Python libraries (PyGithub, python-gitlab) for routine tracker ops"
@@ -67,7 +67,7 @@ integration:
required: true
method: manual # v1.0 - auto in v1.1
steps:
- - "Export GITEA_API_TOKEN environment variable"
+ - "Export FORGEJO_TOKEN environment variable (GITEA_API_TOKEN is a deprecated alias)"
- "Run: issue backend add myproject gitea"
- "Provide: URL, owner, repo when prompted"
- "Run: issue backend set-default myproject"
@@ -115,8 +115,9 @@ efficiency:
credentials:
method: environment_variables
variables:
- - GITEA_API_TOKEN
- - GITEA_URL (optional with config)
+ - FORGEJO_TOKEN (preferred; FORGEJO_API_TOKEN also accepted)
+ - GITEA_API_TOKEN / GITEA_TOKEN (deprecated aliases)
+ - FORGEJO_URL (optional with config; GITEA_URL deprecated alias)
security:
- "Tokens never in code or logs"
@@ -259,7 +260,7 @@ support:
solution: "Run: issue backend add "
- problem: "Authentication failed"
- solution: "Check GITEA_API_TOKEN is set and valid"
+ solution: "Check FORGEJO_TOKEN is set and valid (legacy GITEA_API_TOKEN still accepted)"
- problem: "Command not found: issue"
solution: "Run: pip install -e capabilities/issue-core/"
diff --git a/INTENT.md b/INTENT.md
index 14bc3eb..89229b3 100644
--- a/INTENT.md
+++ b/INTENT.md
@@ -9,11 +9,12 @@ state-hub, under a closed kind registry (`workplan`, `task`, `intake`,
`the-custodian/canon/standards/work-record-types_v0.1.md` and the founder-
reviewed architecture draft (`WorkOrchestrationArchitectureDraft.md` v0.2).
-External issue trackers (Forgejo / Gitea, GitHub, Jira, …) remain necessary
+External issue trackers (Forgejo, GitHub, Jira, …) remain necessary
when a human counterparty, open-source workflow, or third-party process lives
there. They are **not** the fleet coordination substrate and are **not** a
work-record kind. Canon is explicit: *issue-core issues become external
-projections only.*
+projections only.* The self-hosted forge product is **Forgejo** only
+(ACT-ADR-005); Gitea is not a supported second product or migration target.
issue-core exists so that, **when an external tracker is actually in use**,
the fleet has one backend-agnostic surface to project, query, and update
@@ -32,9 +33,11 @@ calls with no stable back-reference to the work record.
issue-core was originally built and documented as a **task landing zone**: a
single place where humans, activity-core, and agents filed work via CLI /
-REST, with Gitea as the default store. That framing contradicted file-first
-work records and produced a live incident (`daily-todo-md-stale-review` →
-IssueSink → Forgejo issues that were never fleet work).
+REST, with the self-hosted forge as the default store (product language then
+said Gitea; the fleet forge is **Forgejo**). That framing contradicted
+file-first work records and produced a live incident
+(`daily-todo-md-stale-review` → IssueSink → Forgejo issues that were never
+fleet work).
Architecture draft §4.2 and the work-record types standard (CUST-WP-0060)
retargeted purpose: **connector, not origin**. Capability (CRUD, backends,
@@ -51,13 +54,16 @@ execution loop.
- **Tracker CRUD** on configured backends: create, read, update, close /
reopen, comment (and related label / assignee / milestone operations).
-- **Backends:** local SQLite (offline store / cache), Gitea (Forgejo-
- compatible in deployment). Further backends (GitHub, GitLab, Jira) are
- product growth, not yet implemented.
+- **Backends:** local SQLite (offline store / cache), **Forgejo** (Gitea-
+ compatible API; Python module `issue_core.backends.gitea`, backend type
+ string `gitea`). Further backends (GitHub, GitLab, Jira) are product
+ growth, not yet implemented. Gitea is not a second supported product.
- **CLI** (`issue` / `issue-core`) and **Python library** for direct backend use.
-- **REST** (`issue serve`, optional `[api]` extra): intentional create
- (`POST /issues/`), list/get/claim (`GET`/`PATCH /issues/`).
-- **Backend↔backend sync** via CLI (e.g. Gitea ↔ SQLite) — *not* the same as
+- **REST** (`issue serve`, optional `[api]` extra): intentional **external
+ tracker** create (`POST /issues/`), list/get (`GET`/`PATCH /issues/`).
+ REST claim/list is for tracker issues already on a backend — **not** the
+ fleet ops claim queue (see below).
+- **Backend↔backend sync** via CLI (e.g. Forgejo ↔ SQLite) — *not* the same as
work-record boundary sync below.
- **Optional intentional ingestion** of TaskSpec payloads for clients that
deliberately create tracker issues (not the fleet path for internal findings).
@@ -104,10 +110,23 @@ connector must add **no coordination load** to the internal loop.
Emitter policy: activity-core **ACTIVITY-WP-0022** (from ISSUE-WP-0004-T05 /
CUST-WP-0060).
+- **Not the fleet ops claim queue.** Internal scheduled automation
+ (FI daily brief, Binky rhythm, mail intake, …) **claim and execute** via
+ activity-core **`ops_run`** ([ACT-ADR-005](../activity-core/docs/adr/adr-005-ops-runs-vs-dev-work-records.md)).
+ issue-core does **not** provide that queue. `POST /issues/` creates or
+ links an **external tracker** issue only. The default activity-core sink
+ remains state-hub progress + `ops_run` — **not** REST to issue-core for
+ Binky/FI. Do not poll issue-core as the primary automation loop.
+
+ ACT-ADR-005: *issue-core’s correct role is a connector facade over
+ external trackers (Forgejo, GitHub, Jira, …). It is not the origin of
+ work records and not the default internal ops queue. Gitea is out of
+ scope for this fleet; the self-hosted forge is Forgejo.*
+
- **Not a second autonomy or budget model.** `lane`, `tags`, and budgets live
on the work record. Projections carry only what external collab needs
(title, body, agreed labels); they must not invent parallel lane/budget
- semantics on Gitea labels without explicit rules.
+ semantics on Forgejo labels without explicit rules.
- **Not a project manager, spawn audit trail, event bus, notification
system, or workflow engine.** Plans and dependencies are workplan tooling;
@@ -151,8 +170,8 @@ cancel`) and tracker **`IssueState`** (`open` / `in_progress` / `blocked` /
+---+------+------+--+
| | |
v v v
- Gitea/ SQLite GitHub
- Forgejo cache (planned)
+ Forgejo SQLite GitHub
+ cache (planned)
```
**Primary fleet path (coordination):**
@@ -205,3 +224,7 @@ cancel`) and tracker **`IssueState`** (`open` / `in_progress` / `blocked` /
connector decision.
- `the-custodian/canon/architecture/adr-001-workplans-as-repo-artefacts.md`.
- activity-core **ACTIVITY-WP-0022** — IssueSink default policy (emitter side).
+- activity-core **ACT-ADR-005** — ops runs vs work records; issue-core is not
+ the ops claim queue.
+- `workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md` — Forgejo-only
+ product language and projection boundary.
diff --git a/Makefile b/Makefile
index 8e9120b..91389f9 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ help: ## Show issue core capability help
@echo " issue-backend-list List configured backends"
@echo " issue-backend-detect Auto-detect backend from repository"
@echo " issue-backend-set-local Configure local SQLite backend"
- @echo " issue-backend-set-gitea Configure Gitea backend"
+ @echo " issue-backend-set-gitea Configure Forgejo backend (Gitea-compatible API)"
@echo ""
@echo "Synchronization:"
@echo " issue-sync Sync with remote backend"
diff --git a/README.md b/README.md
index 823c92e..67d39ed 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# 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.**
+**A backend-agnostic connector to third-party issue trackers (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.
+**issue-core** is a standardized abstraction layer for talking to external issue-tracking backends (Forgejo, 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. The self-hosted forge is **Forgejo** only (ACT-ADR-005); the HTTP API is Gitea-compatible.
### Fleet coordination vs external trackers
@@ -32,7 +32,7 @@ For agent coordination *inside* the Coulomb fleet, use work records + state-hub,
✅ **Fully Implemented:**
- Complete CRUD operations (issues, labels, users, milestones, comments)
-- Gitea backend (production-ready with full API integration)
+- Forgejo backend (Gitea-compatible API; production-ready)
- Local SQLite backend (offline work with sync capability)
- CLI with JSON output for machine parsing
- Python API for programmatic access
@@ -72,15 +72,20 @@ 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.
+Internal scheduled automation (FI/Binky, mail, …) does **not** poll this
+server. Claim/execute is activity-core **`ops_run`** (ACT-ADR-005).
+`POST /issues/` is external tracker create/link only.
+
### Configuration (One-Time Setup)
-**For Gitea-backed projects:**
+**For Forgejo-backed projects:**
```bash
-# Set your Gitea token
-export GITEA_API_TOKEN="your-token-here"
+# Preferred token name (CLI also accepts FORGEJO_API_TOKEN)
+export FORGEJO_TOKEN="your-token-here"
+# Deprecated aliases still work: GITEA_API_TOKEN, GITEA_TOKEN
-# Configure backend
+# Configure backend (type string `gitea` = Forgejo Gitea-compatible API)
issue backend add myproject gitea
# Prompts for: URL, owner, repo (reads token from environment)
@@ -185,7 +190,7 @@ for issue in issues:
┌───────┴────────┐
│ │
┌──────▼─────┐ ┌──────▼──────┐
-│ Local │ │ Gitea │
+│ Local │ │ Forgejo │
│ (SQLite) │ │ (REST API) │
└────────────┘ └─────────────┘
```
@@ -200,7 +205,7 @@ for issue in issues:
| Backend | Status | Features |
|---------|--------|----------|
-| **Gitea** | ✅ Production | Full API, rate limiting, state mapping |
+| **Forgejo** (Gitea-compatible API) | ✅ 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 |
@@ -209,7 +214,7 @@ for issue in issues:
### 1. External tracker ops (when a backend is in use)
-Agents or humans work issues that already live in Gitea/GitHub (e.g. OSS
+Agents or humans work issues that already live in Forgejo/GitHub (e.g. OSS
inbound, customer Jira, or an intentional projection):
```bash
@@ -227,7 +232,7 @@ Fleet-internal task claim/execute should use workplan task status in the repo
### 2. Human collaboration through a tracker UI
-When the counterparty only uses GitHub/Gitea, project or update the external
+When the counterparty only uses GitHub/Forgejo, 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`.
@@ -238,14 +243,14 @@ Work offline with local backend, sync when online:
```bash
# Setup local backup
issue backend add backup local
-issue sync pull gitea-production backup
+issue sync pull forgejo-production backup
# Work offline
issue backend set-default backup
issue create "Offline tracker note" --label=offline
# Sync back
-issue sync push backup gitea-production
+issue sync push backup forgejo-production
```
## CLI Commands Reference
@@ -318,7 +323,7 @@ issue-core/
│ │ ├── models.py # Issue, Label, User, etc.
│ │ └── interfaces.py # IssueBackend, SyncableBackend
│ ├── backends/
-│ │ ├── gitea/ # Gitea backend implementation
+│ │ ├── gitea/ # Forgejo backend (Gitea-compatible API)
│ │ └── local/ # SQLite backend implementation
│ └── cli/ # Click-based CLI
│ ├── commands.py # Issue operations
@@ -358,7 +363,7 @@ issue map detach --uuid
```
Mappings live in `~/.config/issue-tracker/mappings.db` (bookkeeping), independent
-of whether CRUD targets Gitea or local SQLite.
+of whether CRUD targets Forgejo or local SQLite.
## Roadmap (summary)
@@ -412,7 +417,7 @@ The Issue Core is designed to be extensible:
- [ ] Integration tests with mock API
- [ ] Documentation
-See existing backends (Gitea, Local) as reference implementations.
+See existing backends (Forgejo / `gitea` module, Local) as reference implementations.
## Why "Facade" / connector?
@@ -421,7 +426,7 @@ 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.
+Instead of agents learning different APIs for GitHub (`gh`), GitLab (`glab`), Forgejo, 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
diff --git a/ROADMAP.md b/ROADMAP.md
index 23635b6..f9935bc 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -28,7 +28,7 @@ replacing workplans/tasks.
✅ **Complete:**
- Core CRUD operations (100%)
-- Gitea backend (production-ready)
+- Forgejo backend (Gitea-compatible API; production-ready)
- Local SQLite backend (fully functional)
- CLI with JSON output
- Python programmatic API
@@ -80,8 +80,8 @@ def detect_git_remote() -> Optional[Dict[str, str]]:
Returns:
{
- 'platform': 'gitea' | 'github' | 'gitlab',
- 'base_url': 'https://gitea.example.com',
+ 'platform': 'forgejo' | 'github' | 'gitlab',
+ 'base_url': 'https://forgejo.example.com',
'owner': 'myorg',
'repo': 'myproject'
}
@@ -90,15 +90,15 @@ def detect_git_remote() -> Optional[Dict[str, str]]:
def parse_remote_url(url: str) -> Optional[Dict[str, str]]:
"""
Parse various git remote URL formats:
- - https://gitea.example.com/owner/repo.git
- - git@gitea.example.com:owner/repo.git
+ - https://forgejo.example.com/owner/repo.git
+ - git@forgejo.example.com:owner/repo.git
- https://github.com/owner/repo
"""
```
**Tests:** `tests/test_detection.py`
- Test various URL formats (HTTPS, SSH, with/without .git)
-- Test platform detection (Gitea, GitHub, GitLab)
+- Test platform detection (Forgejo, GitHub, GitLab)
- Test edge cases (subgroups, custom domains)
**Effort:** 2-3 days
@@ -112,7 +112,8 @@ def parse_remote_url(url: str) -> Optional[Dict[str, str]]:
def load_backend_from_env() -> Optional[Dict[str, Any]]:
"""
Load backend config from environment variables:
- - GITEA_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO
+ - FORGEJO_URL, FORGEJO_TOKEN, FORGEJO_OWNER, FORGEJO_REPO
+ (deprecated aliases: GITEA_URL, GITEA_TOKEN / GITEA_API_TOKEN, …)
- GITHUB_TOKEN (with auto-detection)
- GITLAB_URL, GITLAB_TOKEN
"""
@@ -149,10 +150,10 @@ issue config auto
{
"backend": {
"type": "gitea",
- "url": "https://gitea.example.com",
+ "url": "https://forgejo.example.com",
"owner": "myorg",
"repo": "myproject",
- "token_source": "env:GITEA_TOKEN" // or "file:/path/to/token"
+ "token_source": "env:FORGEJO_TOKEN" // or "file:/path/to/token"; GITEA_* deprecated
},
"sync": {
"enabled": true,
@@ -247,7 +248,7 @@ if issue backend show "$backend_name" &>/dev/null; then
fi
# Offer existing values as defaults
- read -p "Gitea URL [$CURRENT_URL]: " url
+ read -p "Forgejo URL [$CURRENT_URL]: " url
url="${url:-$CURRENT_URL}"
read -p "Repository owner [$CURRENT_OWNER]: " owner
@@ -403,7 +404,7 @@ class LockManager:
**Storage:** Store claims in issue metadata or separate tracking table.
-**For Gitea backend:**
+**For Forgejo backend:**
```json
// In issue.sync_metadata
{
@@ -788,7 +789,7 @@ def sync_with_strategy(
### Phase 1 Success
- [ ] Agent can attach to any repo's tracker with zero manual config
-- [ ] Environment-only setup works: `GITEA_TOKEN=xxx issue list`
+- [ ] Environment-only setup works: `FORGEJO_TOKEN=xxx issue list`
- [ ] Auto-detection accuracy: >95% for common platforms
### Phase 1.5 Success (mapping)
diff --git a/ReusableCapabilitiesArchitecture.md b/ReusableCapabilitiesArchitecture.md
index 3b1d2d2..413e463 100644
--- a/ReusableCapabilitiesArchitecture.md
+++ b/ReusableCapabilitiesArchitecture.md
@@ -55,7 +55,7 @@ A **Capability Implementation** is a concrete realization of a Capability Family
**Characteristics:**
- Provides **concrete functionality** (code, CLI, API)
-- May implement **multiple backend variants** (Gitea, GitHub, local)
+- May implement **multiple backend variants** (Forgejo, GitHub, local)
- Has **maturity levels** (experimental, beta, production)
- Can be **composed with other capabilities**
@@ -255,7 +255,7 @@ metadata:
implementation: issue-core
version: 1.0.0
description: >
- Unified interface for issue tracking across Gitea, GitHub, GitLab.
+ Unified interface for issue tracking across Forgejo, GitHub, GitLab.
Enables agent coordination via standardized issue operations.
purpose:
@@ -315,7 +315,7 @@ purpose:
- "Unified issue management for polyglot platform environments"
problems_solved:
- - "Direct API calls to GitHub/GitLab/Gitea (avoids credential sprawl)"
+ - "Direct API calls to GitHub/GitLab/Forgejo (avoids credential sprawl)"
- "Inconsistent issue tracking access patterns"
- "Platform-specific code in agents"
- "Offline/online workflow synchronization"
@@ -323,7 +323,7 @@ purpose:
# When to use this capability
usage_rules:
MUST_USE_INSTEAD_OF:
- - "Direct Gitea/GitHub/GitLab API calls"
+ - "Direct Forgejo/GitHub/GitLab API calls"
- "Platform-specific CLIs (gh, glab)"
- "Python libraries (PyGithub, python-gitlab)"
@@ -361,7 +361,7 @@ integration:
required: true
method: manual # auto-detection planned for v1.1
steps:
- - "Export GITEA_API_TOKEN environment variable"
+ - "Export FORGEJO_TOKEN environment variable (GITEA_API_TOKEN is a deprecated alias)"
- "Run: issue backend add myproject gitea"
- "Provide: URL, owner, repo when prompted"
- "Run: issue backend set-default myproject"
@@ -416,8 +416,8 @@ efficiency:
credentials:
method: environment_variables
variables:
- - GITEA_API_TOKEN
- - GITEA_URL # optional with config
+ - FORGEJO_TOKEN # preferred; GITEA_API_TOKEN is a deprecated alias
+ - FORGEJO_URL # optional with config; GITEA_URL deprecated alias
security:
- "Tokens never in code or logs"
@@ -736,7 +736,7 @@ metadata:
```
Project A needs GitHub issues
Project B needs GitLab issues
-Project C needs Gitea issues
+Project C needs Forgejo issues
→ Pattern: "We need issue tracking"
→ Family: "issue-tracking"
diff --git a/SCOPE.md b/SCOPE.md
index d718a3e..8b891f1 100644
--- a/SCOPE.md
+++ b/SCOPE.md
@@ -25,7 +25,7 @@ aspirational lists when deciding “does issue-core already do X?”
| Concept | Notes |
| --- | --- |
| `Issue` | id, number, title, description, state, timestamps, labels, assignees, milestone, comments, backend_id/type, `sync_metadata` |
-| `IssueState` | `open`, `closed`, `in_progress`, `blocked` (Gitea maps non-closed → open on the wire) |
+| `IssueState` | `open`, `closed`, `in_progress`, `blocked` (Forgejo Gitea-compatible API maps non-closed → open on the wire) |
| `Label` / priority / type | Priority and type are primarily **label conventions** (`priority:high`, `bug`, …), not separate backend columns everywhere |
| `User`, `Milestone`, `Comment` | First-class models on the backend interface |
| `Priority`, `IssueType` enums | Helpers for label-derived classification |
@@ -46,7 +46,7 @@ aspirational lists when deciding “does issue-core already do X?”
| Backend | Module | Role |
| --- | --- | --- |
| **Local SQLite** | `issue_core.backends.local` | Offline store; hard delete supported; bulk ops; sync-capable |
-| **Gitea** | `issue_core.backends.gitea` | Remote REST; **Forgejo-compatible** in railiance01 deploy; no true delete (close-as-delete); rate-limit aware; sync-capable |
+| **Forgejo** | `issue_core.backends.gitea` | Remote REST via **Forgejo (Gitea-compatible API)**; backend type string remains `gitea`. Gitea is not a second product. No true delete (close-as-delete); rate-limit aware; sync-capable |
**Not implemented as code:** GitHub, GitLab, Jira backends (optional deps may be
declared in `pyproject.toml`; no backend package under `issue_core/backends/`).
@@ -64,7 +64,9 @@ declared in `pyproject.toml`; no backend package under `issue_core/backends/`).
- JSON-friendly output for agents (`--format=json` on list/show paths).
- Backend configs: `~/.config/issue-tracker/` (default backend + named configs).
- Mapping store: `~/.config/issue-tracker/mappings.db` (independent of CRUD backend).
-- Gitea token typically from env (`GITEA_API_TOKEN` / config); never commit secrets.
+- Forgejo token from env: **`FORGEJO_TOKEN`** (preferred) or `FORGEJO_API_TOKEN`;
+ legacy **`GITEA_API_TOKEN` / `GITEA_TOKEN`** are deprecated aliases the CLI
+ still accepts. Never commit secrets.
### 1.4b Work-record mapping (shipped v0.2.x)
@@ -103,7 +105,7 @@ also `sync_metadata.mapping` and a row in `mappings.db`.
### 1.6 Synchronization (CLI)
-- Bidirectional pull/push between configured backends (e.g. Gitea ↔ local).
+- Bidirectional pull/push between configured backends (e.g. Forgejo ↔ local).
- Uses `get_issues_modified_since` / conflict hooks where backends implement them.
- Conflict handling is basic (operator / force flags) — not a full merge engine.
@@ -111,7 +113,7 @@ also `sync_metadata.mapping` and a row in `mappings.db`.
| Artifact | Provides |
| --- | --- |
-| PyPI package | Built wheel/sdist; Makefile targets publish to Coulomb Gitea/Forgejo registry |
+| PyPI package | Built wheel/sdist; Makefile targets publish to Coulomb Forgejo registry |
| Docker image | Built and published by this app repo; production consumes an immutable digest |
| `rapp-issue-core` | Authoritative railiance01 runtime package: manifests, private Service, ExternalSecret references, NetworkPolicy, rollout, rollback, and live evidence |
| `docs/package-release.md` | Release notes for packaging |
@@ -148,7 +150,7 @@ Things this repo **owns** and may grow, consistent with the connector role.
backends when tracker use is intentional.
- List and filter (state, labels, assignee, milestone, text search as backends allow).
- Label, assignee, and milestone management through the backend interface.
-- Delete where the backend allows (SQLite hard delete; Gitea effectively close).
+- Delete where the backend allows (SQLite hard delete; Forgejo effectively close).
### 2.2 Connector / mapping (owned direction)
@@ -164,7 +166,9 @@ Things this repo **owns** and may grow, consistent with the connector role.
### 2.3 Surfaces
- CLI for humans and agents on a shell.
-- REST for intentional automation and worker claim/list/close.
+- REST for intentional **external tracker** create/link and worker
+ list/update/close of tracker issues. This is **not** the fleet ops claim
+ queue (ACT-ADR-005 / activity-core `ops_run`).
- Python library for embedding.
- Optional future NATS consumer **only** for intentional external projection
(never silent fleet work origin).
@@ -204,6 +208,24 @@ activity-core (and peers) must not treat `POST /issues/` as the always-on
default for every matched rule. Emitters own that policy; issue-core keeps
accepting authenticated POSTs without advertising itself as a landing zone.
Follow-up: `activity-core` **ACTIVITY-WP-0022** (from ISSUE-WP-0004-T05).
+Default activity-core sink remains **state-hub progress + `ops_run`**, not
+REST to issue-core for Binky/FI.
+
+### 3.3b Ops claim queue (ACT-ADR-005) — not this repo
+
+Internal scheduled automation **claim/execute** belongs to activity-core
+**`ops_run`** ([ACT-ADR-005](../activity-core/docs/adr/adr-005-ops-runs-vs-dev-work-records.md)).
+issue-core does **not** provide the fleet ops claim queue. Do not poll
+`GET /issues/` as “the automation queue.”
+
+ACT-ADR-005: *issue-core’s correct role is a connector facade over
+external trackers (Forgejo, GitHub, Jira, …). It is not the origin of
+work records and not the default internal ops queue. Gitea is out of
+scope for this fleet; the self-hosted forge is Forgejo.*
+
+`POST /issues/` = external tracker create/link only. rein-aharness
+`poll --source=issue-core` is **legacy / external ticket** path only
+(see ISSUE-WP-0006, REINAH-WP-0005-T06).
### 3.4 Project management
@@ -246,8 +268,8 @@ Emitters record who/what spawned an external issue (e.g. activity-core
| --- | --- | --- |
| Human / agent shell | CLI | Tracker admin; `project` / `map` for work-record links |
| Library consumers | Python API + `MappingService` | Same backends + mapping store without shell |
-| Workers (e.g. harness) | REST GET/PATCH | List / claim / close external issues when in the loop |
-| activity-core IssueSink | REST POST | **Optional, intentional** external issues only — not default for internal findings; may pass `work_record_uuid` |
+| Workers (e.g. harness) | REST GET/PATCH | List / update / close **external tracker** issues when that tracker is in use — **not** the fleet ops claim queue |
+| activity-core IssueSink | REST POST | **Optional, intentional** external issues only — not default for internal findings or Binky/FI; may pass `work_record_uuid`. Default sink is state-hub progress + `ops_run` (ACT-ADR-005) |
| Mapping-aware emitters | CLI or POST `/issues/` with UUID | Project/link work-record UUID ↔ external id |
### 4.3 TaskSpec contract (`POST /issues/`)
@@ -287,14 +309,16 @@ Retained for intentional emits and backward compatibility:
```
`issue_id` is the **backend** issue identity for the emitter’s log; not a
-work-record UUID. (`github` appears in the response enum for forward
-compatibility; no GitHub backend is shipped yet.)
+work-record UUID. The wire value `gitea` is the Forgejo (Gitea-compatible
+API) backend type string — not a second Gitea product. (`github` appears in
+the response enum for forward compatibility; no GitHub backend is shipped
+yet.)
### 4.4 Credential routing (operators / agents)
| Need | Owner |
| --- | --- |
-| Gitea/Forgejo API token for backend | OpenBao / operator path (`warden route`) |
+| Forgejo API token for backend (`FORGEJO_TOKEN`; legacy `GITEA_*` alias) | OpenBao / operator path (`warden route`) |
| `ISSUE_CORE_API_KEY` for REST | Shared secret via deploy secrets (e.g. ExternalSecret) |
| SSH certs | ops-warden only |
@@ -309,7 +333,7 @@ issue_core/
core/ # models, IssueBackend ABC, factory, MappingService
backends/
local/ # SQLite issue store
- gitea/ # Gitea/Forgejo REST
+ gitea/ # Forgejo REST (Gitea-compatible API)
cli/ # Click: issue, project, map, backend, sync, serve
api/ # FastAPI: ingest + query (+ auth, schemas)
tests/
@@ -326,7 +350,7 @@ tests, image construction, and Forgejo image publication.
| Language | Python 3.8+ |
| CLI | Click |
| HTTP | FastAPI + Pydantic v2 + uvicorn (`[api]` extra) |
-| HTTP client (Gitea) | requests |
+| HTTP client (Forgejo) | requests |
| Issue store (local) | SQLite (`issues.db`) |
| Mapping store | SQLite (`mappings.db`, separate file) |
| Tests | pytest |
@@ -350,3 +374,5 @@ tests, image construction, and Forgejo image publication.
(issue-core issues = external projections only)
- `the-custodian/research/WorkOrchestrationArchitectureDraft.md` §4.2
- activity-core IssueSink / **ACTIVITY-WP-0022** — emitter-side default policy
+- activity-core **ACT-ADR-005** — `ops_run` is the fleet ops claim queue; not issue-core
+- `workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md` — Forgejo-only + projection boundary
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index e89a947..56c7eb7 100644
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -2,9 +2,10 @@
# Render issue-core backends.json from environment, then start the API.
#
# The backend structure (host/owner/repo/default) is non-secret and supplied
-# via the BACKENDS_TEMPLATE env (a ConfigMap), with the Gitea token injected
-# from GITEA_BACKEND_TOKEN (an ExternalSecret-materialized Secret). The token
-# is never baked into the image or committed to Git.
+# via the BACKENDS_TEMPLATE env (a ConfigMap), with the Forgejo token injected
+# from FORGEJO_BACKEND_TOKEN (preferred) or GITEA_BACKEND_TOKEN (deprecated
+# alias; ExternalSecret-materialized Secret). The token is never baked into
+# the image or committed to Git.
set -eu
CONFIG_DIR="${HOME}/.config/issue-tracker"
@@ -14,12 +15,13 @@ mkdir -p "${CONFIG_DIR}"
# Substitute the token placeholder using python (always present in the image)
# to avoid shell-escaping issues with the secret value.
+FORGEJO_BACKEND_TOKEN="${FORGEJO_BACKEND_TOKEN:-}" \
GITEA_BACKEND_TOKEN="${GITEA_BACKEND_TOKEN:-}" \
BACKENDS_TEMPLATE="${BACKENDS_TEMPLATE}" \
python - "${CONFIG_DIR}/backends.json" <<'PY'
import json, os, sys
tmpl = json.loads(os.environ["BACKENDS_TEMPLATE"])
-token = os.environ.get("GITEA_BACKEND_TOKEN", "")
+token = os.environ.get("FORGEJO_BACKEND_TOKEN") or os.environ.get("GITEA_BACKEND_TOKEN", "")
for cfg in tmpl.values():
if isinstance(cfg, dict) and cfg.get("token") == "__FROM_ENV__":
cfg["token"] = token
diff --git a/docs/boundary-sync-and-status-mapping.md b/docs/boundary-sync-and-status-mapping.md
index 1bd9e64..b9f3659 100644
--- a/docs/boundary-sync-and-status-mapping.md
+++ b/docs/boundary-sync-and-status-mapping.md
@@ -21,7 +21,7 @@
| Side | Key |
| --- | --- |
| Work record | **UUIDv7** (bookkeeping); canonical id optional denorm for UX |
-| External | `(backend, external_id)` where backend is `sqlite` \| `gitea` \| … |
+| External | `(backend, external_id)` where backend is `sqlite` \| `gitea` (Forgejo) \| … |
## Outward status table (task kind + pass-through)
diff --git a/docs/intent-work-record-alignment-review.md b/docs/intent-work-record-alignment-review.md
index e073b92..c1f463c 100644
--- a/docs/intent-work-record-alignment-review.md
+++ b/docs/intent-work-record-alignment-review.md
@@ -87,7 +87,7 @@ without naming UUIDv7 or the human-facing id.
**Why it matters:** Mapping implementation and CLI (`issue project
ISSUE-WP-…`) will almost always start from the **canonical name**; storage
key should be UUID. INTENT’s UUID-only phrasing can steer readers to hide
-canonical ids or treat Gitea numbers as peer identity to human task names.
+canonical ids or treat Forgejo numbers as peer identity to human task names.
**Recommendation:** In INTENT “Why / Mapping”, say:
@@ -215,7 +215,7 @@ Framework makes `lane` mandatory on every work record; tags and budgets are
normative.
INTENT is silent — **acceptable** if projections never invent parallel
-lane/budget models on issues. Soft risk if Gitea labels start carrying a
+lane/budget models on issues. Soft risk if Forgejo labels start carrying a
second autonomy model (`lane:green` as issue labels without mapping rules).
**Recommendation:** Mapping/projection: lane, tags, budget stay on the work
@@ -231,7 +231,7 @@ INTENT’s “What it is” lists responsibilities that mix **shipped** and
| Responsibility in INTENT | Shipped? |
| --- | --- |
-| Projection / CRUD on backends | **Yes** (SQLite, Gitea) |
+| Projection / CRUD on backends | **Yes** (SQLite, Forgejo) |
| Mapping UUID ↔ external id | **No** — design only |
| Two-way boundary sync | **No** — CLI backend sync ≠ work-record boundary sync |
| CLI + REST | **Yes** |
@@ -295,7 +295,7 @@ defaults, rewriting AGENT_INTEGRATION examples — those are separate work.
| Connector role | Yes | Yes | Yes |
| Not work origin | Yes | §3.1 | Yes |
| Mapping | Target | Design + not shipped | Yes if INTENT softens “What it is” |
-| Backends | SQLite + Gitea (+ planned) | Same | Yes |
+| Backends | SQLite + Forgejo (+ planned) | Same | Yes |
| REST TaskSpec | Optional intentional | Full contract | Yes |
| State-hub runtime events from package | Downstream mention | Explicitly not shipped | Mild aspirational gap in older SCOPE; current SCOPE honest |
diff --git a/docs/package-release.md b/docs/package-release.md
index 52cee67..ca35904 100644
--- a/docs/package-release.md
+++ b/docs/package-release.md
@@ -15,7 +15,7 @@ make package-check
Publish to the Coulomb organization registry:
```bash
-TWINE_USERNAME= \
+TWINE_USERNAME= \
TWINE_PASSWORD= \
make publish-forgejo
```
diff --git a/docs/uuid-external-id-mapping.md b/docs/uuid-external-id-mapping.md
index 8bc525d..b9de6e2 100644
--- a/docs/uuid-external-id-mapping.md
+++ b/docs/uuid-external-id-mapping.md
@@ -11,13 +11,13 @@ kinds in `the-custodian/canon/standards/work-record-types_v0.1.md`
## Problem
-When collaboration requires a third-party tracker (Forgejo/Gitea, GitHub,
+When collaboration requires a third-party tracker (Forgejo, GitHub,
Jira, …), the fleet still needs a stable link between:
| Side | Identity today | Owner |
| --- | --- | --- |
| Internal work record | UUIDv7 written back as `state_hub_*_id` (workplan/task/intake/…) | repo file + state-hub |
-| External issue | Backend issue id / number (+ URL) | Gitea, GitHub, … via issue-core |
+| External issue | Backend issue id / number (+ URL) | Forgejo, GitHub, … via issue-core |
Without an explicit mapping:
@@ -95,7 +95,7 @@ mapping:
work_record_uuid: # primary internal key
work_record_id: "ISSUE-WP-0004-T01" # canonical name, optional denorm
work_record_kind: task # task | intake | workplan | …
- backend: gitea # gitea | github | gitlab | jira | sqlite
+ backend: gitea # forgejo product; type string `gitea` | github | gitlab | jira | sqlite
external_id: "176" # backend-native issue id/number
external_url: "https://…/issues/176"
target_repo: "coulomb/example" # optional routing hint
@@ -123,7 +123,7 @@ issue-core only:
```yaml
# on a task / intake YAML block (illustrative — exact key names TBD with canon)
external_tracker:
- backend: gitea
+ backend: forgejo # product; stored type may be `gitea`
issue_id: "176"
issue_url: "https://…"
mapped_by: issue-core
@@ -132,7 +132,7 @@ external_tracker:
Alternatively a single string field if canon prefers flat keys:
```text
-issue_core_external_ref: "gitea:coulomb/example#176"
+issue_core_external_ref: "forgejo:coulomb/example#176"
```
Canon PR owns the field name; issue-core owns the mapping authority.
@@ -142,7 +142,7 @@ Canon PR owns the field name; issue-core owns the mapping authority.
Recommended v1:
1. **Local SQLite** table `work_record_issue_map` (even when primary CRUD
- backend is Gitea) — mapping is fleet bookkeeping, not a Gitea concept.
+ backend is Forgejo) — mapping is fleet bookkeeping, not a Forgejo concept.
2. **Issue.sync_metadata.mapping** (or top-level) echo for convenience when
the issue is loaded:
```json
@@ -154,7 +154,7 @@ Recommended v1:
}
}
```
-3. Optional Gitea label / body footer for human visibility in the tracker UI
+3. Optional Forgejo label / body footer for human visibility in the tracker UI
(non-authoritative).
### API / CLI (sketch only)
@@ -255,7 +255,7 @@ increment. Until enabled, connector load is zero beyond idle process cost.
documenting multi-tracker projection is future work.
- **SQLite-only offline:** mapping table lives with local DB; sync of
issues and mappings to remote is coordinated (mapping rows are not
- pushed as Gitea native objects).
+ pushed as Forgejo native objects).
## Implementation sketch (later workplan)
diff --git a/examples/agents/README.md b/examples/agents/README.md
index 6798ade..576267a 100644
--- a/examples/agents/README.md
+++ b/examples/agents/README.md
@@ -12,7 +12,8 @@ This directory contains working examples of autonomous agents using the Issue Co
2. **Configure backend** (one-time setup):
```bash
- export GITEA_API_TOKEN="your-token"
+ export FORGEJO_TOKEN="your-token"
+ # Deprecated alias: GITEA_API_TOKEN
issue backend add myproject gitea
# Enter: URL, owner, repo when prompted
issue backend set-default myproject
@@ -20,10 +21,11 @@ This directory contains working examples of autonomous agents using the Issue Co
3. **Set environment variables** for scripts:
```bash
- export GITEA_URL=https://gitea.example.com
- export GITEA_TOKEN=your-token
- export GITEA_OWNER=your-org
- export GITEA_REPO=your-repo
+ export FORGEJO_URL=https://forgejo.example.com
+ export FORGEJO_TOKEN=your-token
+ export FORGEJO_OWNER=your-org
+ export FORGEJO_REPO=your-repo
+ # Deprecated aliases: GITEA_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO
```
## Examples
@@ -212,7 +214,7 @@ issue backend add myproject gitea
### "Authentication failed"
```bash
# Check token is valid
-curl -H "Authorization: token $GITEA_TOKEN" $GITEA_URL/api/v1/user
+curl -H "Authorization: token $FORGEJO_TOKEN" $FORGEJO_URL/api/v1/user
```
### "No issues found"
diff --git a/examples/agents/human_in_loop.py b/examples/agents/human_in_loop.py
index dddd0de..f4b4236 100755
--- a/examples/agents/human_in_loop.py
+++ b/examples/agents/human_in_loop.py
@@ -9,10 +9,10 @@ This agent demonstrates agent-human collaboration:
4. Agent can ask questions and wait for answers
Usage:
- export GITEA_URL=https://gitea.example.com
- export GITEA_TOKEN=your-token
- export GITEA_OWNER=your-org
- export GITEA_REPO=your-repo
+ export FORGEJO_URL=https://forgejo.example.com
+ export FORGEJO_TOKEN=your-token
+ export FORGEJO_OWNER=your-org
+ export FORGEJO_REPO=your-repo
python human_in_loop.py
"""
@@ -40,11 +40,11 @@ class HumanInLoopAgent:
self.backend = None
def connect(self):
- """Connect to backend."""
- base_url = os.environ['GITEA_URL']
- token = os.environ['GITEA_TOKEN']
- owner = os.environ['GITEA_OWNER']
- repo = os.environ['GITEA_REPO']
+ """Connect to Forgejo backend."""
+ base_url = os.environ.get('FORGEJO_URL') or os.environ['GITEA_URL']
+ token = os.environ.get('FORGEJO_TOKEN') or os.environ.get('FORGEJO_API_TOKEN') or os.environ['GITEA_TOKEN']
+ owner = os.environ.get('FORGEJO_OWNER') or os.environ['GITEA_OWNER']
+ repo = os.environ.get('FORGEJO_REPO') or os.environ['GITEA_REPO']
self.backend = GiteaBackend()
self.backend.connect({
diff --git a/examples/agents/monitoring_agent.py b/examples/agents/monitoring_agent.py
index 719f6ea..62525e4 100755
--- a/examples/agents/monitoring_agent.py
+++ b/examples/agents/monitoring_agent.py
@@ -9,10 +9,10 @@ This agent monitors issue health and sends alerts:
- Reports on project velocity and bottlenecks
Usage:
- export GITEA_URL=https://gitea.example.com
- export GITEA_TOKEN=your-token
- export GITEA_OWNER=your-org
- export GITEA_REPO=your-repo
+ export FORGEJO_URL=https://forgejo.example.com
+ export FORGEJO_TOKEN=your-token
+ export FORGEJO_OWNER=your-org
+ export FORGEJO_REPO=your-repo
python monitoring_agent.py [--stale-days=7] [--check-interval=3600]
"""
@@ -42,11 +42,11 @@ class MonitoringAgent:
self.backend = None
def connect(self):
- """Connect to backend."""
- base_url = os.environ['GITEA_URL']
- token = os.environ['GITEA_TOKEN']
- owner = os.environ['GITEA_OWNER']
- repo = os.environ['GITEA_REPO']
+ """Connect to Forgejo backend."""
+ base_url = os.environ.get('FORGEJO_URL') or os.environ['GITEA_URL']
+ token = os.environ.get('FORGEJO_TOKEN') or os.environ.get('FORGEJO_API_TOKEN') or os.environ['GITEA_TOKEN']
+ owner = os.environ.get('FORGEJO_OWNER') or os.environ['GITEA_OWNER']
+ repo = os.environ.get('FORGEJO_REPO') or os.environ['GITEA_REPO']
self.backend = GiteaBackend()
self.backend.connect({
diff --git a/examples/agents/multi_agent_pipeline.py b/examples/agents/multi_agent_pipeline.py
index ecdebda..7753d04 100755
--- a/examples/agents/multi_agent_pipeline.py
+++ b/examples/agents/multi_agent_pipeline.py
@@ -11,10 +11,10 @@ Demonstrates a CI/CD-like pipeline with multiple specialized agents:
Each agent monitors for issues in their stage and advances them through the pipeline.
Usage:
- export GITEA_URL=https://gitea.example.com
- export GITEA_TOKEN=your-token
- export GITEA_OWNER=your-org
- export GITEA_REPO=your-repo
+ export FORGEJO_URL=https://forgejo.example.com
+ export FORGEJO_TOKEN=your-token
+ export FORGEJO_OWNER=your-org
+ export FORGEJO_REPO=your-repo
# Run all agents in parallel (in separate terminals)
python multi_agent_pipeline.py --agent=coder
@@ -50,11 +50,11 @@ class BaseAgent:
self.backend = None
def connect(self):
- """Connect to backend from environment."""
- base_url = os.environ['GITEA_URL']
- token = os.environ['GITEA_TOKEN']
- owner = os.environ['GITEA_OWNER']
- repo = os.environ['GITEA_REPO']
+ """Connect to Forgejo backend from environment."""
+ base_url = os.environ.get('FORGEJO_URL') or os.environ['GITEA_URL']
+ token = os.environ.get('FORGEJO_TOKEN') or os.environ.get('FORGEJO_API_TOKEN') or os.environ['GITEA_TOKEN']
+ owner = os.environ.get('FORGEJO_OWNER') or os.environ['GITEA_OWNER']
+ repo = os.environ.get('FORGEJO_REPO') or os.environ['GITEA_REPO']
self.backend = GiteaBackend()
self.backend.connect({
diff --git a/examples/agents/simple_task_executor.py b/examples/agents/simple_task_executor.py
index 121db62..fdd9815 100755
--- a/examples/agents/simple_task_executor.py
+++ b/examples/agents/simple_task_executor.py
@@ -9,10 +9,10 @@ This agent demonstrates a basic workflow:
4. Report completion and close the issue
Usage:
- export GITEA_URL=https://gitea.example.com
- export GITEA_TOKEN=your-token
- export GITEA_OWNER=your-org
- export GITEA_REPO=your-repo
+ export FORGEJO_URL=https://forgejo.example.com
+ export FORGEJO_TOKEN=your-token
+ export FORGEJO_OWNER=your-org
+ export FORGEJO_REPO=your-repo
python simple_task_executor.py
"""
@@ -39,16 +39,22 @@ class SimpleTaskExecutor:
self.backend = None
def connect(self):
- """Connect to Gitea backend from environment variables."""
- base_url = os.environ.get('GITEA_URL')
- token = os.environ.get('GITEA_TOKEN')
- owner = os.environ.get('GITEA_OWNER')
- repo = os.environ.get('GITEA_REPO')
+ """Connect to Forgejo backend from environment variables."""
+ base_url = os.environ.get('FORGEJO_URL') or os.environ.get('GITEA_URL')
+ token = (
+ os.environ.get('FORGEJO_TOKEN')
+ or os.environ.get('FORGEJO_API_TOKEN')
+ or os.environ.get('GITEA_TOKEN')
+ or os.environ.get('GITEA_API_TOKEN')
+ )
+ owner = os.environ.get('FORGEJO_OWNER') or os.environ.get('GITEA_OWNER')
+ repo = os.environ.get('FORGEJO_REPO') or os.environ.get('GITEA_REPO')
if not all([base_url, token, owner, repo]):
raise ValueError(
"Missing required environment variables: "
- "GITEA_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO"
+ "FORGEJO_URL, FORGEJO_TOKEN, FORGEJO_OWNER, FORGEJO_REPO "
+ "(deprecated aliases: GITEA_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO)"
)
self.backend = GiteaBackend()
diff --git a/integration/gitea-backend.integration.yaml b/integration/gitea-backend.integration.yaml
index 991795c..75ed002 100644
--- a/integration/gitea-backend.integration.yaml
+++ b/integration/gitea-backend.integration.yaml
@@ -1,9 +1,10 @@
schema_version: open-reuse.integration.v0.1
id: issue-core-gitea
-name: issue-core Gitea Backend
+name: issue-core Forgejo Backend
description: >
Pluggable remote backend that maps the issue-core unified issue model onto the
- Gitea issues API for external-tracker projection and synchronization.
+ Forgejo issues API (Gitea-compatible) for external-tracker projection and
+ synchronization. Gitea is not a second supported product.
status: registered
owner: issue-core
@@ -13,9 +14,9 @@ local:
system: issue-core
upstream:
- name: Gitea
- project_url: https://github.com/go-gitea/gitea
- homepage: https://about.gitea.com/
+ name: Forgejo (Gitea-compatible API)
+ project_url: https://codeberg.org/forgejo/forgejo
+ homepage: https://forgejo.org/
version_policy: gitea-api-v1
monitor:
releases: true
@@ -29,14 +30,14 @@ reuse:
- plugin
risk_level: medium
rationale: >
- Gitea REST API is wrapped behind the RemoteBackend interface; local task
- lifecycle semantics remain stable across backend swaps.
+ Forgejo (Gitea-compatible) REST API is wrapped behind the RemoteBackend
+ interface; local task lifecycle semantics remain stable across backend swaps.
boundary:
type: adapter
local_adapter: issue_core.backends.gitea.backend.GiteaBackend
local_interface: issue_core.core.interfaces.RemoteBackend
- reused_surface: Gitea /api/v1 issues, labels, milestones, comments
+ reused_surface: Forgejo (Gitea-compatible) /api/v1 issues, labels, milestones, comments
contracts:
- issue-core.backend.v1
fragility_points:
diff --git a/issue_core/__init__.py b/issue_core/__init__.py
index 911fd17..f80d45e 100644
--- a/issue_core/__init__.py
+++ b/issue_core/__init__.py
@@ -2,12 +2,12 @@
issue-core — external issue-tracker connector
Backend-agnostic CLI, library, and optional REST surface for operating on
-third-party issue trackers (Gitea/Forgejo, local SQLite). Not the origin of
-fleet work records (see INTENT.md / SCOPE.md).
+third-party issue trackers (Forgejo via Gitea-compatible API, local SQLite).
+Not the origin of fleet work records (see INTENT.md / SCOPE.md).
Shipped:
- Unified issue model and IssueBackend plugin architecture
-- Local SQLite + Gitea backends; bidirectional sync CLI
+- Local SQLite + Forgejo backends; bidirectional sync CLI
- CLI (`issue` / `issue-core`) and optional FastAPI REST (`issue serve`)
"""
diff --git a/issue_core/backends/__init__.py b/issue_core/backends/__init__.py
index 429769c..d9da69e 100644
--- a/issue_core/backends/__init__.py
+++ b/issue_core/backends/__init__.py
@@ -7,5 +7,5 @@ API regardless of the underlying issue tracking system.
Available Backends:
- local: SQLite-based local backend for offline use
-- gitea: Gitea API backend for GitHub-compatible systems
+- gitea: Forgejo backend (Gitea-compatible API)
"""
\ No newline at end of file
diff --git a/issue_core/backends/gitea/__init__.py b/issue_core/backends/gitea/__init__.py
index c02af71..b00ae63 100644
--- a/issue_core/backends/gitea/__init__.py
+++ b/issue_core/backends/gitea/__init__.py
@@ -1,12 +1,11 @@
"""
-Gitea Backend
+Forgejo backend (Gitea-compatible API).
-A backend implementation for Gitea issue tracking systems.
-This backend provides integration with Gitea API for remote issue management.
+Talks to the self-hosted Forgejo HTTP API. Gitea is not a second supported
+product. The backend type string remains `gitea`.
Features:
-- Full Gitea API integration
-- GitHub-compatible operations
+- Full Forgejo / Gitea-compatible API integration
- Remote synchronization
- Authentication support
- Rate limiting compliance
diff --git a/issue_core/backends/gitea/backend.py b/issue_core/backends/gitea/backend.py
index 4ed4b15..3aa73d9 100644
--- a/issue_core/backends/gitea/backend.py
+++ b/issue_core/backends/gitea/backend.py
@@ -1,8 +1,9 @@
"""
-Gitea Backend Implementation
+Forgejo backend (Gitea-compatible API).
-Provides integration with Gitea API for remote issue tracking.
-This backend adapts the Gitea API to our unified issue model.
+Talks to the self-hosted Forgejo HTTP API, which is Gitea-compatible.
+Gitea is not a second supported product. The backend type string remains
+`gitea` for compatibility.
"""
import requests
@@ -16,7 +17,7 @@ from ...core.models import Issue, Label, User, Milestone, Comment, IssueState, P
class GiteaAPIError(Exception):
- """Gitea API specific errors."""
+ """Forgejo (Gitea-compatible API) errors."""
pass
@@ -26,7 +27,7 @@ class GiteaRateLimitError(GiteaAPIError):
class GiteaBackend(RemoteBackend, SyncableBackend):
- """Gitea API backend for remote issue tracking."""
+ """Forgejo backend using the Gitea-compatible HTTP API."""
def __init__(self):
self.base_url: Optional[str] = None
@@ -44,7 +45,7 @@ class GiteaBackend(RemoteBackend, SyncableBackend):
supports_webhooks=True,
supports_real_time=False,
max_labels_per_issue=None,
- max_assignees_per_issue=10 # Gitea typical limit
+ max_assignees_per_issue=10 # Forgejo / Gitea-compatible typical limit
)
@property
@@ -56,7 +57,7 @@ class GiteaBackend(RemoteBackend, SyncableBackend):
return self._capabilities
def connect(self, config: Dict[str, Any]) -> None:
- """Connect to Gitea API."""
+ """Connect to Forgejo (Gitea-compatible API)."""
self.base_url = config['base_url'].rstrip('/')
self.token = config['token']
self.owner = config['owner']
@@ -71,10 +72,10 @@ class GiteaBackend(RemoteBackend, SyncableBackend):
# Test connection
if not self.test_connection():
- raise GiteaAPIError("Failed to connect to Gitea API")
+ raise GiteaAPIError("Failed to connect to Forgejo (Gitea-compatible API)")
def disconnect(self) -> None:
- """Disconnect from Gitea API."""
+ """Disconnect from Forgejo."""
self.session.close()
self.base_url = None
self.token = None
@@ -195,20 +196,20 @@ class GiteaBackend(RemoteBackend, SyncableBackend):
if issue.milestone:
data['milestone'] = int(issue.milestone.backend_id) if issue.milestone.backend_id else None
- # Gitea expects numeric label IDs on issue create/update. Name-only
- # labels are preserved in issue-core metadata but omitted from the API
- # payload until a label-resolution step exists.
- label_ids = []
- for label in issue.labels:
- if not label.backend_id:
- continue
- try:
- label_ids.append(int(label.backend_id))
- except (TypeError, ValueError):
- continue
- if label_ids:
- data['labels'] = label_ids
-
+ # Gitea expects numeric label IDs on issue create/update. Name-only
+ # labels are preserved in issue-core metadata but omitted from the API
+ # payload until a label-resolution step exists.
+ label_ids = []
+ for label in issue.labels:
+ if not label.backend_id:
+ continue
+ try:
+ label_ids.append(int(label.backend_id))
+ except (TypeError, ValueError):
+ continue
+ if label_ids:
+ data['labels'] = label_ids
+
return data
# Issue CRUD Operations
diff --git a/issue_core/cli/backend_commands.py b/issue_core/cli/backend_commands.py
index 1adaf80..6c41da1 100644
--- a/issue_core/cli/backend_commands.py
+++ b/issue_core/cli/backend_commands.py
@@ -12,6 +12,23 @@ from .utils import (
echo_error, echo_warning, echo_info, confirm_action
)
+# Preferred FORGEJO_*; GITEA_* remain deprecated aliases (ISSUE-WP-0006).
+_FORGE_TOKEN_ENV_NAMES = (
+ 'FORGEJO_TOKEN',
+ 'FORGEJO_API_TOKEN',
+ 'GITEA_API_TOKEN',
+ 'GITEA_TOKEN',
+)
+
+
+def _forge_token_from_env():
+ """Return (env_name, token) for the first set Forgejo/legacy token var."""
+ for name in _FORGE_TOKEN_ENV_NAMES:
+ value = os.getenv(name)
+ if value:
+ return name, value
+ return None, None
+
@click.group()
def backend_group():
@@ -46,14 +63,19 @@ def add_backend(ctx, name, backend_type):
'db_path': str(db_path)
}
elif backend_type == 'gitea':
- base_url = click.prompt('Gitea base URL (e.g., https://git.example.com)')
+ base_url = click.prompt('Forgejo base URL (Gitea-compatible API)')
owner = click.prompt('Repository owner/organization')
repo = click.prompt('Repository name')
- # Check for API token in environment variable first
- env_token = os.getenv('GITEA_API_TOKEN')
+ env_name, env_token = _forge_token_from_env()
if env_token:
- click.echo(f"Using API token from GITEA_API_TOKEN environment variable")
+ if env_name in ('GITEA_API_TOKEN', 'GITEA_TOKEN'):
+ click.echo(
+ f"Using API token from {env_name} "
+ "(deprecated alias; prefer FORGEJO_TOKEN)"
+ )
+ else:
+ click.echo(f"Using API token from {env_name} environment variable")
token = env_token
else:
token = click.prompt('Access token', hide_input=True)
diff --git a/pyproject.toml b/pyproject.toml
index 28222d1..7da4946 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "issue-core"
-description = "External issue-tracker connector (Gitea/Forgejo, SQLite) with work-record UUID mapping — not the fleet work origin"
+description = "External issue-tracker connector (Forgejo, SQLite) with work-record UUID mapping — not the fleet work origin"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
diff --git a/registry/capabilities/capability.infotech.issue-tracking.md b/registry/capabilities/capability.infotech.issue-tracking.md
index 67ebd67..bc2ccb3 100644
--- a/registry/capabilities/capability.infotech.issue-tracking.md
+++ b/registry/capabilities/capability.infotech.issue-tracking.md
@@ -1,7 +1,7 @@
---
id: capability.infotech.issue-tracking
name: External Issue Tracker Connector
-summary: Backend-agnostic CLI/Python connector to Gitea/Forgejo (and SQLite cache)
+summary: Backend-agnostic CLI/Python connector to Forgejo (and SQLite cache)
with work-record UUID ↔ external issue mapping. Not the fleet work origin.
owner: issue-core
status: draft
@@ -29,10 +29,10 @@ external_evidence:
confidence: medium
basis: scope_vs_intent_and_consumer_expectations
satisfied_expectations:
- - Gitea + local SQLite backends
+ - Forgejo + local SQLite backends
- CLI with JSON output; project/map commands
- work_record_uuid optional on TaskSpec
- - credential handling via env vars (GITEA_API_TOKEN, ISSUE_CORE_API_KEY)
+ - credential handling via env vars (FORGEJO_TOKEN preferred; GITEA_API_TOKEN deprecated alias; ISSUE_CORE_API_KEY)
broken_expectations: []
out_of_scope_expectations:
- Fleet task origin / intake promotion (work-record canon)
diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml
index f2d9de6..7be3fce 100644
--- a/registry/indexes/capabilities.yaml
+++ b/registry/indexes/capabilities.yaml
@@ -4,7 +4,7 @@ domain: helix_forge
capabilities:
- id: capability.infotech.issue-tracking
name: Universal Issue Tracking Coordination
- summary: Unified Python/CLI interface for issue tracking across Gitea, GitHub, and GitLab, preventing
+ summary: Unified Python/CLI interface for issue tracking across Forgejo, GitHub, and GitLab, preventing
direct platform API usage and credential sprawl for coordinating agents.
vector: D4 / A2 / C2 / R1
domain: infotech
diff --git a/tests/test_cli_commands.py b/tests/test_cli_commands.py
index a7e57d3..38bd2b4 100644
--- a/tests/test_cli_commands.py
+++ b/tests/test_cli_commands.py
@@ -53,7 +53,7 @@ class TestCLICommands:
], input='https://git.example.com\ntestorg\ntestrepo\n')
assert result.exit_code == 0
- assert 'Using API token from GITEA_API_TOKEN environment variable' in result.output
+ assert 'Using API token from FORGEJO_TOKEN environment variable' in result.output
assert 'Backend \'test-gitea\' added successfully' in result.output
# Verify save_backend_configs was called with correct data
@@ -205,8 +205,13 @@ class TestEnvironmentTokenDetection:
@patch('os.getenv')
def test_gitea_token_detection(self, mock_getenv):
- """Test GITEA_API_TOKEN environment variable detection."""
- mock_getenv.return_value = 'test-env-token'
+ """Deprecated GITEA_API_TOKEN alias is still accepted."""
+ def _getenv(name, default=None):
+ if name == 'GITEA_API_TOKEN':
+ return 'test-env-token'
+ return default
+
+ mock_getenv.side_effect = _getenv
from issue_core.cli.backend_commands import add_backend
@@ -220,4 +225,5 @@ class TestEnvironmentTokenDetection:
], input='https://git.example.com\ntestorg\ntestrepo\n')
assert result.exit_code == 0
- assert 'Using API token from GITEA_API_TOKEN environment variable' in result.output
\ No newline at end of file
+ assert 'Using API token from GITEA_API_TOKEN' in result.output
+ assert 'deprecated alias; prefer FORGEJO_TOKEN' in result.output
\ No newline at end of file
diff --git a/tests/test_gitea_backend.py b/tests/test_gitea_backend.py
index e3107c8..fd67a34 100644
--- a/tests/test_gitea_backend.py
+++ b/tests/test_gitea_backend.py
@@ -77,7 +77,7 @@ class TestGiteaBackend:
backend = GiteaBackend()
backend.session = mock_session
- with pytest.raises(GiteaAPIError, match="Failed to connect to Gitea API"):
+ with pytest.raises(GiteaAPIError, match="Failed to connect to Forgejo"):
backend.connect(self.test_config)
def test_url_construction_fix(self):
@@ -98,29 +98,29 @@ class TestGiteaBackend:
called_url = mock_request.call_args[1]['url'] if 'url' in mock_request.call_args[1] else mock_request.call_args[0][1]
assert called_url == 'https://git.example.com/api/v1/repos/owner/repo'
- def test_gitea_payload_omits_name_only_labels(self):
- """Gitea issue payloads only include numeric label IDs."""
- now = datetime.now(timezone.utc)
- issue = Issue(
- id="",
- number=0,
- title="Test issue",
- description="Test description",
- state=IssueState.OPEN,
- created_at=now,
- updated_at=now,
- labels=[
- Label(name="priority:low"),
- Label(name="source:rule", backend_id="not-a-number"),
- Label(name="existing", backend_id="42"),
- ],
- )
-
- payload = self.backend._unified_issue_to_gitea(issue)
-
- assert payload["labels"] == [42]
- assert payload["title"] == "Test issue"
-
+ def test_gitea_payload_omits_name_only_labels(self):
+ """Gitea issue payloads only include numeric label IDs."""
+ now = datetime.now(timezone.utc)
+ issue = Issue(
+ id="",
+ number=0,
+ title="Test issue",
+ description="Test description",
+ state=IssueState.OPEN,
+ created_at=now,
+ updated_at=now,
+ labels=[
+ Label(name="priority:low"),
+ Label(name="source:rule", backend_id="not-a-number"),
+ Label(name="existing", backend_id="42"),
+ ],
+ )
+
+ payload = self.backend._unified_issue_to_gitea(issue)
+
+ assert payload["labels"] == [42]
+ assert payload["title"] == "Test issue"
+
@patch('issue_core.backends.gitea.backend.requests.Session')
def test_test_connection_success(self, mock_session_class):
"""Test test_connection method works correctly."""
diff --git a/workplans/ISSUE-WP-0004-align-with-work-record-canon.md b/workplans/ISSUE-WP-0004-align-with-work-record-canon.md
index 406be9e..1aa53d5 100644
--- a/workplans/ISSUE-WP-0004-align-with-work-record-canon.md
+++ b/workplans/ISSUE-WP-0004-align-with-work-record-canon.md
@@ -49,8 +49,8 @@ be an alternative origin.
This workplan brings issue-core's own docs, scope, and (where cheap) code
in line with that decision. It does not remove issue-core's existing
-capability — Gitea/GitHub backend CRUD stays useful — it retargets *what
-issue-core is for*.
+capability — Forgejo/GitHub backend CRUD stays useful — it retargets *what
+issue-core is for*. (Product language: Forgejo only; see ISSUE-WP-0006.)
## Task: Rewrite INTENT.md — connector, not landing zone
diff --git a/workplans/ISSUE-WP-0005-connector-alignment-implementation.md b/workplans/ISSUE-WP-0005-connector-alignment-implementation.md
index 6fd9c30..448f886 100644
--- a/workplans/ISSUE-WP-0005-connector-alignment-implementation.md
+++ b/workplans/ISSUE-WP-0005-connector-alignment-implementation.md
@@ -35,7 +35,7 @@ Close the gap between:
| Layer | State at start of this WP |
| --- | --- |
| **INTENT** | Work-record-aligned connector (2026-07-22) |
-| **SCOPE §1 shipped** | Models, SQLite/Gitea, CLI, REST TaskSpec, backend sync |
+| **SCOPE §1 shipped** | Models, SQLite/Forgejo, CLI, REST TaskSpec, backend sync |
| **SCOPE §1.8 / target** | Mapping store/API, boundary sync, work_record_uuid, dual-lifecycle rules |
Deliver a **minimum viable connector core**: durable mapping + project/link
@@ -137,14 +137,14 @@ state_hub_task_id: "027871b0-696d-5ab7-b18c-b26167e97813"
Per `docs/uuid-external-id-mapping.md`:
- Table `work_record_issue_map` (or equivalent) on local backend / dedicated
- store used even when CRUD backend is Gitea
+ store used even when CRUD backend is Forgejo
- Uniqueness: active `(backend, external_id)` and active
`(work_record_uuid, backend)`
- Domain service `MappingService`: upsert, resolve by UUID, by canonical id
(if provided), by external id, detach
- Unit tests for idempotent project and uniqueness
-**Acceptance:** Tests pass without a live Gitea; store survives reconnect;
+**Acceptance:** Tests pass without a live Forgejo; store survives reconnect;
SCOPE §1.8 “mapping store” can move toward shipped with an honest partial
note until CLI/API land.
@@ -208,7 +208,7 @@ Implement **outward-only** application of T03 rules for mapped records
- Do **not** write work-record files
- Inward sync remains out of scope for this task (document as next)
-**Acceptance:** Policy tests + one integration-style test on local/Gitea mock;
+**Acceptance:** Policy tests + one integration-style test on local/Forgejo mock;
SCOPE distinguishes backend sync vs work-record boundary sync clearly.
## Task: SCOPE inventory refresh after implementation
diff --git a/workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md b/workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md
index e59abc4..c21b802 100644
--- a/workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md
+++ b/workplans/ISSUE-WP-0006-forgejo-only-projection-boundary.md
@@ -4,18 +4,20 @@ type: workplan
title: "Forgejo-only forge + projection boundary (not ops queue)"
domain: infotech
repo: issue-core
-status: ready
+status: finished
owner: grok
topic_slug: issue-core
priority: medium
created: "2026-08-03"
-updated: "2026-08-03"
+updated: "2026-09-14"
depends_on: []
related:
- ACT-ADR-005
- ACTIVITY-WP-0022
- ISSUE-WP-0004
- ISSUE-WP-0005
+ - REIN-A-0002
+ - REINAH-WP-0005
state_hub_workstream_id: "4d465264-cbe1-56ba-84ed-bd580b649b76"
---
@@ -41,7 +43,7 @@ and so rein-aharness stops treating issue-core as the primary automation queue
```task
id: ISSUE-WP-0006-T01
-status: todo
+status: done
priority: high
state_hub_task_id: "927eee42-e22d-5c0d-a4f8-dcd36c53c8e9"
```
@@ -65,7 +67,7 @@ compatibility notes remain.
```task
id: ISSUE-WP-0006-T02
-status: todo
+status: done
priority: high
state_hub_task_id: "a1d69a48-833b-5e5e-8286-14f5aba627f3"
```
@@ -87,7 +89,7 @@ Explicit section:
```task
id: ISSUE-WP-0006-T03
-status: todo
+status: done
priority: medium
state_hub_task_id: "75eef8a3-abd7-50dd-9171-3488fda84da5"
```
@@ -107,7 +109,7 @@ as the primary automation loop.
```task
id: ISSUE-WP-0006-T04
-status: todo
+status: done
priority: low
state_hub_task_id: "5be0bce4-1816-599f-a98b-4fa1565a8b0e"
```
@@ -117,14 +119,32 @@ No code change required in issue-core if rein owns the doc cut.
**Done when:** cross-link in ISSUE-WP-0006 and REIN-A-0002.
+**Closed 2026-09-14:** REIN-A-0002 was completed as **REINAH-WP-0005**. T06
+there already marked issue-core poll as legacy/external. Cross-links added:
+
+- this workplan `related: REIN-A-0002`, `REINAH-WP-0005`
+- `~/rein-aharness/workplans/REINAH-WP-0005-ops-run-claim-loop.md` T06 note
+ + `related: ISSUE-WP-0006`
+- `~/rein-aharness/docs/task-intake.md` (legacy/external section)
+- State Hub message to `rein-aharness`
+
## Acceptance
-- [ ] No Gitea-as-product planning
-- [ ] Projection boundary clear
-- [ ] Ops claim queue explicitly out of scope for issue-core
+- [x] No Gitea-as-product planning
+- [x] Projection boundary clear
+- [x] Ops claim queue explicitly out of scope for issue-core
## Out of scope
-- Implementing ops_run (ACTIVITY-WP-0026)
-- Fixing Forgejo PAT for rest sink (only if projection needs it later)
-- GitHub/Jira connectors
+- Implementing ops_run (ACTIVITY-WP-0026) — lives in activity-core / REINAH-WP-0005
+- Fixing Forgejo PAT for rest sink (only if projection needs it later) — ISSUE-WP-0003 residual / deploy
+- GitHub/Jira connectors — product growth, not this workplan
+
+No new residual: those items already have live work records elsewhere.
+
+## Close note (2026-09-14)
+
+Product language is **Forgejo** only. The HTTP API is Gitea-compatible;
+module `issue_core.backends.gitea` and backend type `gitea` remain as
+identifiers. `FORGEJO_TOKEN` is preferred; `GITEA_*` is a deprecated alias.
+INTENT/SCOPE quote ACT-ADR-005: issue-core is not the ops claim queue.