diff --git a/.claude/rules/agents.md b/.claude/rules/agents.md new file mode 100644 index 0000000..0e8a5d9 --- /dev/null +++ b/.claude/rules/agents.md @@ -0,0 +1,20 @@ +## Kaizen Agents + +Specialized agent personas available on demand via the state-hub MCP. + +**Discover:** `list_kaizen_agents()` — returns all agents with name, description, category +**Load:** `get_kaizen_agent("tdd-workflow")` — returns full instructions; read and follow them + +Common agents: + +| Agent | Category | When to use | +|-------|----------|-------------| +| `tdd-workflow` | testing | Step-by-step TDD8 workflow for any feature | +| `code-refactoring` | quality | Code quality analysis and safe refactoring | +| `test-maintenance` | testing | Diagnose and fix failing tests | +| `requirements-engineering` | process | Prevent interface/mock mismatches upfront | +| `keepaTodofile` | process | Maintain TODO.md during work | +| `project-management` | process | Track status, determine next steps | +| `datamodel-optimization` | quality | Optimize dataclasses and data structures | + +All 17 agents: call `list_kaizen_agents()` for the full list. diff --git a/.claude/rules/architecture.md b/.claude/rules/architecture.md new file mode 100644 index 0000000..7c2a645 --- /dev/null +++ b/.claude/rules/architecture.md @@ -0,0 +1,8 @@ +## Architecture + + + +## Quick Reference + +`~/state-hub/mcp_server/TOOLS.md` — MCP tool reference diff --git a/.claude/rules/credential-routing.md b/.claude/rules/credential-routing.md index b3d8073..adb56b9 100644 --- a/.claude/rules/credential-routing.md +++ b/.claude/rules/credential-routing.md @@ -20,7 +20,7 @@ Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run wa | Agent runtime | How to orient | | --- | --- | | **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-forge` is for coordination, not secret vending | -| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workstreams; **still** use `warden route` for credential ownership | +| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workplans; **still** use `warden route` for credential ownership | | **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` | ### Quick routing table diff --git a/.claude/rules/first-session.md b/.claude/rules/first-session.md new file mode 100644 index 0000000..e4edf87 --- /dev/null +++ b/.claude/rules/first-session.md @@ -0,0 +1,42 @@ +## First Session Protocol + +Triggered when `get_domain_summary("financials")` shows **no workplans**. +The project is registered but work has not yet been structured. + +**Step 1 — Read, don't write** +- `~/the-custodian/canon/projects/financials/project_charter_v0.1.md` — purpose, scope +- `~/the-custodian/canon/projects/financials/roadmap_v0.1.md` — planned phases +- Scan repo root: README, directory structure, existing code or docs + +**Step 2 — Survey in-progress work** +Look for TODOs, open branches, half-finished files. Note done vs. started but incomplete. + +**Step 3 — Propose workplans to Bernd** +Propose 1–3 workplans — each a coherent strand, weeks to months, anchored to a +roadmap phase. **Wait for approval before creating.** + +**Step 4 — Write the workplan file; fix-consistency registers it (ADR-001)** +``` +workplans/RAILIANCE-WP-NNNN-.md ← write this, commit it +``` +Then register by running the consistency check — do **not** call +`create_workplan`/`create_task` (or legacy `create_workstream`) yourself; +manual registration duplicates what C-06 creates from the file: +```bash +statehub fix-consistency --repo railiance-forge +``` +C-06 creates the hub workplan + tasks and writes `state_hub_workstream_id` / +`state_hub_task_id` back into the file (legacy field names, kept for +compatibility — they hold workplan/task IDs). + +**Step 5 — Record the setup** +``` +add_progress_event( + summary="First session: structured financials into N workplans, M tasks", + event_type="milestone", + topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", + detail={"workplans": [...], "tasks_created": M} +) +``` + + diff --git a/.claude/rules/repo-boundary.md b/.claude/rules/repo-boundary.md new file mode 100644 index 0000000..c285418 --- /dev/null +++ b/.claude/rules/repo-boundary.md @@ -0,0 +1,8 @@ +## Repo boundary + +This repo owns **railiance-forge** only. It does not own: + + diff --git a/.claude/rules/repo-identity.md b/.claude/rules/repo-identity.md new file mode 100644 index 0000000..84122df --- /dev/null +++ b/.claude/rules/repo-identity.md @@ -0,0 +1,5 @@ +**Purpose:** Railiance forge and artifact infrastructure: current Gitea operation, future Forgejo migration, container/package registries, runner substrate, artifact lifecycle, and forge operating evidence. + +**Domain:** financials +**Repo slug:** railiance-forge +**Topic ID:** ca369340-a64e-442e-98f1-a4fa7dc74a38 diff --git a/.claude/rules/session-protocol.md b/.claude/rules/session-protocol.md new file mode 100644 index 0000000..7e966dc --- /dev/null +++ b/.claude/rules/session-protocol.md @@ -0,0 +1,94 @@ +## Session Protocol + +Dev Hub (State Hub API): http://127.0.0.1:8000 +MCP server name in `~/.claude.json`: `dev-hub` + +**Step 1 — Orient** + +Read the offline-safe brief first — it works without a live hub connection: +```bash +cat .custodian-brief.md +``` +Then call the MCP tool for richer cross-domain context when MCP tools are exposed: +``` +get_domain_summary("financials") +``` +If MCP tools are unavailable in the current agent session, use the REST API: +```bash +curl -s "http://127.0.0.1:8000/state/summary" | python3 -m json.tool +``` +If the hub is offline: `cd ~/state-hub && make api` + +**Step 2 — Check inbox** +With MCP tools: +``` +get_messages(to_agent="railiance-forge", unread_only=True) +``` +Mark read with `mark_message_read(message_id)`. Reply or act on coordination +requests before proceeding. + +Without MCP tools: +```bash +curl -s "http://127.0.0.1:8000/messages/?to_agent=railiance-forge&unread_only=true" \ + | python3 -m json.tool +curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ + -H "Content-Type: application/json" -d '{}' +``` + +**Step 3 — Scan workplans** +```bash +ls workplans/ +``` +For each file with `status: ready`, `active`, or `blocked`, note pending +`wait`/`todo`/`progress` tasks. + +**Step 4 — Present brief** + +1. **Active workplans** for `financials` — title, task counts, blocking decisions +2. **Pending tasks** from `workplans/` + any `[repo:railiance-forge]` hub tasks +3. **Goal guidance** — if `goal_guidance` in summary: + - `needs_workplan`: surface as top action — *"Repo goal '{title}' has no workplan yet"* + - `alignment_warnings`: flag if active work is not aligned with current goal +4. **Suggested next action** — highest-priority open item +5. **SBOM status** — flag if `last_sbom_at` is unset for this repo + +If no workplans: follow First Session Protocol (`first-session.md`). + +**During work:** `record_decision()` · `add_progress_event()` · `resolve_decision()` + +> State Hub is a *read model*. **Never register workplans or tasks by hand** +> (`create_workplan`, `create_task`, or the legacy `create_workstream`) — write +> the workplan file in `workplans/` and run `fix-consistency`; its C-06 check +> registers the workplan and its tasks in the hub and writes the IDs back into +> the file. Manual registration creates duplicates the moment fix-consistency +> runs. Work structure belongs in repo files (ADR-001). +> +> Terminology: "workstream" is the legacy name for workplan. Some API/frontmatter +> field names keep it for compatibility (`state_hub_workstream_id`, +> `workstream_id` params) — treat them as workplan IDs. + +**Session close:** +With MCP tools: +``` +add_progress_event(summary="...", topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", workplan_id="") +``` +Without MCP tools: +```bash +curl -s -X POST http://127.0.0.1:8000/progress/ \ + -H "Content-Type: application/json" \ + -d '{"topic_id":"ca369340-a64e-442e-98f1-a4fa7dc74a38","workplan_id":"","event_type":"note","summary":"what changed","author":"codex"}' +``` +If workplan files were modified, ensure the local copy is up to date first, +then sync from the repo checkout: +```bash +git pull --ff-only +statehub fix-consistency +``` +For repos where implementation runs on a remote machine (e.g. CoulombCore), +use the pull-before-fix mode from any shell with the State Hub CLI: +```bash +statehub fix-consistency --repo railiance-forge --remote +``` +**C-15** (DB task ahead of file) is normal in multi-machine workflows — writeback +will sync the file to match DB. **C-16** (repo behind remote) blocks all writes +until you pull — intentional to prevent clobbering remote progress. diff --git a/.claude/rules/stack-and-commands.md b/.claude/rules/stack-and-commands.md new file mode 100644 index 0000000..d3683f6 --- /dev/null +++ b/.claude/rules/stack-and-commands.md @@ -0,0 +1,18 @@ +## Stack + +- **Language:** Helm values + Kubernetes manifests, Bash Make targets +- **Key deps:** Gitea (current forge runtime), Actions runner substrate, SOPS/age; runs against the S2 cluster on railiance01 + +## Dev Commands + +```bash +make help # list all targets +make check-tools && make check-sops # preflight (read-only) +make gitea-status # forge runtime + database state (read-only) +make runner-status # Actions runner / registry probes (read-only) +make registry-docs | evidence-docs | runner-docs # print canonical docs +make gitea-deploy | gitea-ingress-deploy # production-touching +``` + +`gitea-deploy` / `gitea-ingress-deploy` change the production forge — +operator approval required. Status and docs targets are read-only. diff --git a/.claude/rules/workplan-convention.md b/.claude/rules/workplan-convention.md new file mode 100644 index 0000000..1f4b616 --- /dev/null +++ b/.claude/rules/workplan-convention.md @@ -0,0 +1,45 @@ +## Workplan Convention (ADR-001) + +File location: `workplans/RAILIANCE-WP-NNNN-.md` +ID prefix: `RAILIANCE-WP-` + +Work items originate as files in this repo **before** being registered in the hub. + +Canonical workplan frontmatter statuses are: +`proposed`, `ready`, `active`, `blocked`, `backlog`, `finished`, `archived`. +Use `proposed` for a newly drafted plan, `ready` after review against current +repo state, and `finished` when implementation is complete. `stalled` and +`needs_review` are derived health labels, not stored statuses. + +Closed workplans may be moved to `workplans/archived/` with a completion-date +prefix: `YYMMDD-RAILIANCE-WP-NNNN-.md`. The frontmatter id remains +unchanged; the prefix is only for quick visual reference. + +Small opportunistic tasks discovered during another session use **Ad Hoc Tasks**: +`workplans/ADHOC-YYYY-MM-DD.md`, workplan slug `adhoc-YYYY-MM-DD`, and task ids +`ADHOC-YYYY-MM-DD-T01`, `T02`, etc. Use adhocs only for low-risk work completed +directly. Promote anything requiring analysis, design, approval, dependencies, or +multiple planned phases into a normal workplan. + +Ecosystem todos from other agents arrive as `[repo:railiance-forge]` hub tasks — +visible at session start. Pick one up by creating the workplan file, committing, +and running `statehub fix-consistency` — C-06 registers the workplan in the hub. +Never register by hand with `create_workplan`/`create_workstream`. + +Task blocks use this shape: + +```task +id: RAILIANCE-WP-NNNN-T01 +status: wait | todo | progress | done | cancel +priority: high | medium | low +state_hub_task_id: "" # written by fix-consistency — do not edit +``` + +Status progression is `todo` → `progress` → `done`; use `wait` for waiting or +blocked work and `cancel` for stopped work. + +Workplan frontmatter carries `state_hub_workstream_id` — a legacy field name +kept for compatibility ("workstream" is the old term for workplan); it holds +the hub workplan id and is written by fix-consistency. Do not edit or rename it. + + diff --git a/.custodian-brief.md b/.custodian-brief.md index 79c84b3..e3659fc 100644 --- a/.custodian-brief.md +++ b/.custodian-brief.md @@ -1,8 +1,8 @@ # Custodian Brief — railiance-forge -**Domain:** railiance -**Last synced:** 2026-06-08 08:14 UTC +**Domain:** financials +**Last synced:** 2026-07-01 22:24 UTC **State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* ## Active Workstreams @@ -13,6 +13,6 @@ ## MCP Orientation (when available) If the state-hub MCP server is reachable, call: -`get_domain_summary("railiance")` +`get_domain_summary("financials")` This provides richer cross-domain context. If the MCP call fails, use this file as your orientation source. diff --git a/.forgejo/workflows/ci-smoke.yaml b/.forgejo/workflows/ci-smoke.yaml new file mode 100644 index 0000000..bd44c56 --- /dev/null +++ b/.forgejo/workflows/ci-smoke.yaml @@ -0,0 +1,29 @@ +# Canonical CI smoke template (tier 1 routing drill). +# Copy to: .forgejo/workflows/ci-smoke.yaml in consumer repos. +name: CI Smoke + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + host-smoke: + runs-on: self-hosted + steps: + - name: Routing probe (host runner) + run: | + set -eu + echo "repository=${GITHUB_REPOSITORY:-unknown}" + echo "sha=${GITHUB_SHA:-unknown}" + echo "runner=${RUNNER_NAME:-unknown}" + uname -a + + container-smoke: + runs-on: ubuntu-latest + steps: + - name: Routing probe (container label) + run: | + set -eu + echo "container-smoke ok for ${GITHUB_REPOSITORY:-unknown}" \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 3a89c44..e3e32fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,48 +1,54 @@ -# railiance-forge - Agent Instructions +# railiance-forge — Agent Instructions ## Repo Identity -**Purpose:** Railiance forge and artifact infrastructure - source forge runtime, -container/package registries, forge-backed runner substrate, artifact lifecycle, -and future Forgejo migration. +**Purpose:** Railiance forge and artifact infrastructure: current Gitea operation, future Forgejo migration, container/package registries, runner substrate, artifact lifecycle, and forge operating evidence. -**Domain:** railiance +**Domain:** financials **Repo slug:** railiance-forge **Topic ID:** `ca369340-a64e-442e-98f1-a4fa7dc74a38` -**Workplan prefix:** `FORGE-WP-` +**Workplan prefix:** `RAILIANCE-WP-` --- ## State Hub Integration -The Custodian State Hub tracks work across all domains. Interact via HTTP REST - +The Custodian State Hub tracks work across all domains. Interact via HTTP REST — there is no MCP server for Codex agents. | Context | URL | |---------|-----| | Local workstation | `http://127.0.0.1:8000` | | Remote via tunnel | `http://127.0.0.1:18000` | +| Optional local edge relay | http://127.0.0.1:18080 | + +When an operator has enabled the edge relay, set API_BASE to the relay URL. +Queueable writes return an explicit queued receipt if the central hub is +unreachable. Treat that as pending local evidence, then ask the operator to run +statehub outbox status/replay after connectivity returns. ### Orient at session start ```bash +# Offline brief — works without hub connection cat .custodian-brief.md -curl -s "http://127.0.0.1:8000/workstreams/?topic_id=ca369340-a64e-442e-98f1-a4fa7dc74a38&status=active" \ +# Active workplans for this domain +curl -s "http://127.0.0.1:8000/workplans/?topic_id=ca369340-a64e-442e-98f1-a4fa7dc74a38&status=active" \ | python3 -m json.tool +# Check inbox curl -s "http://127.0.0.1:8000/messages/?to_agent=railiance-forge&unread_only=true" \ | python3 -m json.tool ``` Mark a message read: - ```bash curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ -H "Content-Type: application/json" -d '{}' ``` -### Log progress at session close +### Log progress (required at session close) ```bash curl -s -X POST http://127.0.0.1:8000/progress/ \ @@ -51,12 +57,12 @@ curl -s -X POST http://127.0.0.1:8000/progress/ \ "summary": "what was done", "event_type": "note", "author": "codex", - "workstream_id": "", + "workplan_id": "", "task_id": "" }' ``` -Omit `workstream_id` / `task_id` when not applicable. +Omit `workplan_id` / `task_id` when not applicable. ### Update task status @@ -64,10 +70,9 @@ Omit `workstream_id` / `task_id` when not applicable. curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ -H "Content-Type: application/json" \ -d '{"status": "progress"}' +# values: wait | todo | progress | done | cancel ``` -Canonical task values: `wait | todo | progress | done | cancel`. - ### Flag a task for human review ```bash @@ -81,46 +86,24 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ ## Session Protocol **Start:** - -1. `cat .custodian-brief.md` - domain goal and open workstreams. -2. Check inbox: - `GET /messages/?to_agent=railiance-forge&unread_only=true`; mark read. -3. Scan workplans: `ls workplans/` and note `ready`, `active`, or `blocked` - workplans and open tasks. -4. Check blocked tasks: `GET /tasks/?needs_human=true`. +1. `cat .custodian-brief.md` — domain goal and open workplans (offline-safe) +2. Check inbox: `GET /messages/?to_agent=railiance-forge&unread_only=true`; mark read +3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks +4. Check human-needed tasks: `GET /tasks/?needs_human=true` **During work:** - -- Update task statuses in workplan files as tasks progress. -- Record significant decisions via `POST /decisions/`. -- Keep forge responsibilities separate from S4 templates and S5 app releases. - -## Verification Commands - -This repo currently contains documentation, workplans, and read-only operator -entry points. There is no app build, package install, or unit-test command yet. - -Use these checks for ordinary edits: - -```bash -git diff --check -make registry-docs -make check-tools -make -C /home/worsch/state-hub fix-consistency REPO=railiance-forge -``` - -`make gitea-status` is read-only but requires a kubeconfig pointed at a -representative Railiance cluster. +- Update task statuses in workplan files as tasks progress +- Record significant decisions via `POST /decisions/` **Close:** - -1. Update workplan file task statuses. -2. Log progress with `POST /progress/`. -3. After workplan file changes, run from `~/state-hub`: - +1. Update workplan file task statuses to reflect progress +2. Log: `POST /progress/` with a summary of what changed +3. After workplan file changes, run: ```bash - make fix-consistency REPO=railiance-forge + statehub fix-consistency ``` + Coding agents should run this directly; ask the operator only if the CLI or + State Hub API is unavailable. This syncs task status from files into the hub DB. --- @@ -146,7 +129,7 @@ Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run wa | Agent runtime | How to orient | | --- | --- | | **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-forge` is for coordination, not secret vending | -| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workstreams; **still** use `warden route` for credential ownership | +| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workplans; **still** use `warden route` for credential ownership | | **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` | ### Quick routing table @@ -174,70 +157,69 @@ every repo's agent instructions because it is high-frequency, high-risk, and eas get wrong. **Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml` + + + + --- -## Workplan Convention +## Workplan Convention (ADR-001) -Work items originate as files in this repo. State Hub indexes those files as -workstreams and task blocks. +Work items originate as files in this repo — not in the hub. The hub is a +read/cache/index layer that rebuilds from files. -**File location:** `workplans/FORGE-WP-NNNN-.md` +**File location:** `workplans/RAILIANCE-WP-NNNN-.md` -**Archived location:** `workplans/archived/YYMMDD-FORGE-WP-NNNN-.md` +**Archived location:** finished workplans may move to +`workplans/archived/YYMMDD-RAILIANCE-WP-NNNN-.md`. The `YYMMDD` prefix is +the completion/archive date; the frontmatter `id` does not change. + +**Ad Hoc Tasks:** small opportunistic fixes discovered during a session use +`workplans/ADHOC-YYYY-MM-DD.md` with task ids `ADHOC-YYYY-MM-DD-T01`, etc. Use +this only for low-risk work completed directly; create a normal workplan for +anything needing analysis, design, approval, dependencies, or multiple phases. **Frontmatter:** ```yaml --- -id: FORGE-WP-NNNN +id: RAILIANCE-WP-NNNN type: workplan title: "..." -domain: railiance +domain: financials repo: railiance-forge status: proposed | ready | active | blocked | backlog | finished | archived owner: codex -topic_slug: railiance +topic_slug: ... created: "YYYY-MM-DD" updated: "YYYY-MM-DD" -state_hub_workstream_id: "" # written by fix-consistency - do not edit +state_hub_workstream_id: "" # written by fix-consistency — do not edit --- ``` -**Task block format:** +Use `proposed` for a new draft, `ready` after review against current repo +state, and `finished` after implementation. `stalled` and `needs_review` are +derived health labels, not frontmatter statuses. -````text +**Task block format** (one per `##` section): + +``` ## Task Title -```task -id: FORGE-WP-NNNN-T01 -status: todo | progress | done | wait | cancel +` ` `task +id: RAILIANCE-WP-NNNN-T01 +status: wait | todo | progress | done | cancel priority: high | medium | low -state_hub_task_id: "" # written by fix-consistency - do not edit -``` +state_hub_task_id: "" # written by fix-consistency — do not edit +` ` ` Task description text. -```` +``` -Status progression: `todo` -> `progress` -> `done`, or `wait` / `cancel`. +Status progression: `todo` → `progress` → `done`; use `wait` for waiting/blocked work and `cancel` for stopped work. To create a new workplan: - -1. Write the file following the format above. -2. Run from `~/state-hub`: - - ```bash - make fix-consistency REPO=railiance-forge - ``` - ---- - -## Repository Boundaries - -This repo owns forge runtime and artifact infrastructure. It does not own: - -- OS/host provisioning (`railiance-infra`); -- Kubernetes runtime primitives (`railiance-cluster`); -- shared database/storage/secret platforms (`railiance-platform`); -- generic CI/CD templates and developer portal paths (`railiance-enablement`); -- user-facing application releases (`railiance-apps`); -- source application code. +1. Write the file following the format above +2. Notify the custodian operator to run `make fix-consistency REPO=railiance-forge` + (or send a message to the hub agent via `POST /messages/`) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..aa1d61e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,12 @@ +# railiance-forge — Claude Code Instructions + +@SCOPE.md +@.claude/rules/repo-identity.md +@.claude/rules/session-protocol.md +@.claude/rules/first-session.md +@.claude/rules/workplan-convention.md +@.claude/rules/stack-and-commands.md +@.claude/rules/architecture.md +@.claude/rules/repo-boundary.md +@.claude/rules/credential-routing.md +@.claude/rules/agents.md diff --git a/Makefile b/Makefile index f847034..a3e0f9d 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,9 @@ runner-docs: ## Print Gitea Actions runner substrate docs and evidence runner-status: ## Read-only Actions runner, host, and inter-hub registry probes bash tools/gitea-runner-status.sh +forgejo-runner-status: ## Read-only Forgejo Actions runner and endpoint probes + bash tools/forgejo-runner-status.sh + check-runner-tools: ## Check local tools used by runner inspection targets @missing=0; \ for tool in curl ssh docker; do \ @@ -109,4 +112,4 @@ help: ## Show this help /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } \ /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST) -.PHONY: check-tools check-sops registry-docs evidence-docs runner-docs runner-status check-runner-tools gitea-deploy gitea-ingress-deploy gitea-status help +.PHONY: check-tools check-sops registry-docs evidence-docs runner-docs runner-status forgejo-runner-status check-runner-tools gitea-deploy gitea-ingress-deploy gitea-status help diff --git a/docs/forgejo-actions-runner-substrate.md b/docs/forgejo-actions-runner-substrate.md new file mode 100644 index 0000000..3b5586f --- /dev/null +++ b/docs/forgejo-actions-runner-substrate.md @@ -0,0 +1,80 @@ +# Forgejo Actions Runner Substrate + +Last reviewed: 2026-07-03 + +Status: **in-cluster runner on railiance01** (ADR-004). Supersedes interim coulombcore +host runner. + +## Purpose + +Forge-owned Actions runner for `https://forgejo.coulomb.social` so `coulomb` +organization repos build and publish without workstation or legacy-host Docker. +Label contract aligns with `docs/gitea-actions-runner-substrate.md` and +`docs/ci-runner-actions-gitops-ownership.md`. + +## Production Runner (ADR-004) + +| Field | Value | +| --- | --- | +| Runner name | `railiance01-build-01` | +| Scope | `coulomb` organization | +| Placement | `forgejo` namespace, railiance01 k3s | +| Manifest | `railiance-apps/manifests/forgejo-runner.yaml` | +| Images | `code.forgejo.org/forgejo/runner:6.3.1`, `docker:27-dind` | +| Job runtime | DinD sidecar (`DOCKER_HOST=tcp://127.0.0.1:2375`) | +| State PVC | `forgejo-runner-data` | +| Cluster deploy authority | Not included | + +### Labels + +```text +self-hosted:host,linux:host,linux_amd64:host,container-build:host,registry-publish:host,railiance01:host,ubuntu-latest:docker://node:20-bookworm,docker:docker://node:20-bookworm +``` + +## Operator Commands + +```bash +# S5 deploy (railiance-apps) +cd ~/railiance-apps +make forgejo-runner-registration-deploy # after SOPS encrypt +make forgejo-runner-deploy +make forgejo-runner-status + +# Endpoint smoke +make forgejo-smoke + +# Generate registration token (in cluster; do not log token) +KUBECONFIG=~/.kube/config-hosteurope kubectl exec -n forgejo deploy/forgejo-gitea -- \ + forgejo actions generate-runner-token --scope coulomb +``` + +## Secret Boundaries + +- `forgejo-runner-registration` Kubernetes Secret — registration token only. +- Repo/org registry credentials — Forgejo Actions secrets, not in Git. +- No kubeconfig or OpenBao tokens on the runner pod by default. + +## Retired: Interim coulombcore Host Runner + +`railiance-coulombcore-build-01` on coulombcore was a scheduling proof only. +Disable after in-cluster runner is healthy: + +```bash +ssh coulombcore 'sudo systemctl disable --now forgejo-runner' +``` + +## Evidence + +- Host probe (2026-07-03): `coulomb/forgejo-actions-probe` workflow `success`. +- In-cluster (2026-07-03): `railiance01-build-01` 2/2 Ready; `container-probe` + and `image-build` workflows `success`. Image-build uses static docker-cli on + the non-root runner host + `DOCKER_HOST=tcp://127.0.0.1:2375` (DinD); org + secrets `REGISTRY_USER` / `REGISTRY_TOKEN`; pushes to + `forgejo.coulomb.social/coulomb/forgejo-actions-probe`. +- `actions/checkout@v4` failed on the host runner — use `git clone` in job steps + until checkout action compatibility is confirmed. + +## References + +- `railiance-infra/docs/adr/ADR-004-forgejo-in-cluster-actions-runner.md` +- [Forgejo runner installation](https://forgejo.org/docs/v11.0/admin/actions/runner-installation/) \ No newline at end of file diff --git a/registry/capabilities/capability.railiance.forge-infrastructure.md b/registry/capabilities/capability.railiance.forge-infrastructure.md new file mode 100644 index 0000000..9dc21e2 --- /dev/null +++ b/registry/capabilities/capability.railiance.forge-infrastructure.md @@ -0,0 +1,129 @@ +--- +id: capability.railiance.forge-infrastructure +name: Railiance Forge And Artifact Infrastructure +summary: Source forge, registry, and automation-runner infrastructure for Railiance, separated out from + railiance-apps/railiance-enablement; covers current Gitea operation, the Forgejo migration, container/package + registries, and Actions runner substrate. +owner: railiance-forge +status: draft +domain: financials +tags: +- railiance +- forgejo +- forge +- ci-runner +maturity: + discovery: + current: D3 + target: D5 + confidence: medium + rationale: README and SCOPE.md explicitly name 'current Gitea operation, future Forgejo migration, + container and package registries, Actions runner substrate, artifact lifecycle' as the scope; status + noted as 'active forge extraction' with canonical registry operation docs already landed. + availability: + current: A1 + target: A3 + confidence: medium + rationale: README explicitly states 'no live Helm deploy or Kubernetes apply was run as part of the + move' — documentation and operator targets exist, but this repo is mid-extraction; has .gitea CI + (not yet migrated to .forgejo itself, notably, despite owning the migration). +external_evidence: + completeness: + level: C1 + confidence: low + basis: scope_vs_intent_and_consumer_expectations + satisfied_expectations: + - scope separation from railiance-apps/railiance-enablement documented + - canonical registry operation docs and runner ownership contracts + broken_expectations: [] + out_of_scope_expectations: [] + reliability: + level: R0 + confidence: low + basis: consumer_quality_signals + known_reliability_risks: + - repo is actively being founded/extracted; no live deploy yet by its own account + - directly relevant to REUSE-WP-0019 but hasn't migrated its own CI to .forgejo/ yet +discovery: + intent: Own source forge, artifact registry, and CI runner substrate responsibilities for Railiance, + separated from application (railiance-apps) and enablement (railiance-enablement) concerns, across + the Gitea-to-Forgejo transition. + includes: + - forge operation (current Gitea, migrating to Forgejo) + - container/package registries + - Actions runner substrate + - artifact lifecycle + excludes: + - application workload deployment (railiance-apps) + - CI/CD templates for consuming repos (railiance-enablement) + assumptions: [] + use_cases: [] + research_memos: [] +availability: + current_level: A1 + target_level: A3 + current_artifacts: + - operator docs and tools/ (extraction in progress) + target_artifacts: [] + consumption_modes: + - cli (operator tooling) + - documentation/runbooks +relations: + depends_on: [] + supports: [] + related_to: [] +evidence: + documentation: + - README.md + - SCOPE.md + tests: [] + consumer_feedback: [] + bug_reports: [] + incidents: [] +consumer_guidance: + recommended_for: + - Railiance operators managing forge/registry/runner infrastructure, especially during the Gitea-to-Forgejo + transition + not_recommended_for: + - treating this as production-stable — the repo's own README states the extraction is active and no + live deploy has run yet + known_limitations: + - actively being founded; no live Helm/k8s deploy has run as part of the extraction yet; own CI still + under .gitea/ pending its own Forgejo migration +promotion_history: [] +--- + +# Railiance Forge And Artifact Infrastructure + +## Overview + +`railiance-forge` is being founded to separate source forge, artifact registry, and CI/Actions runner responsibilities from `railiance-apps` and `railiance-enablement`. It directly owns the current Gitea operation and the future Forgejo migration — of particular relevance to REUSE-WP-0019 — though by its own account no live deploy has run yet. + +## Assessment notes + +### Discovery + +README and SCOPE.md explicitly name 'current Gitea operation, future Forgejo migration, container and package registries, Actions runner substrate, artifact lifecycle' as the scope; status noted as 'active forge extraction' with canonical registry operation docs already landed. + +### Availability + +README explicitly states 'no live Helm deploy or Kubernetes apply was run as part of the move' — documentation and operator targets exist, but this repo is mid-extraction; has .gitea CI (not yet migrated to .forgejo itself, notably, despite owning the migration). + +### Completeness + +First-pass honest assessment from the REUSE-WP-0017 coverage campaign +(reuse-surface). No external consumer feedback exists yet; levels reflect +scope-vs-intent documentation quality, not internal code quality. + +### Reliability + +No production consumer telemetry exists yet; reliability level is +intentionally conservative pending REUSE-WP-0019 reuse-telemetry evidence. + +## Promotion checklist + +- [x] ID follows `capability..` pattern +- [x] Maturity enums match `specs/CapabilityMaturityStandard.md` +- [x] `external_evidence` is populated separately from `maturity` +- [ ] Relations reference valid capability IDs (none yet) +- [x] Index entry added in `registry/indexes/capabilities.yaml` diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml index f944e47..6437991 100644 --- a/registry/indexes/capabilities.yaml +++ b/registry/indexes/capabilities.yaml @@ -1,4 +1,22 @@ version: 1 -updated: '2026-06-16' +updated: '2026-07-06' domain: helix_forge -capabilities: [] +capabilities: +- id: capability.railiance.forge-infrastructure + name: Railiance Forge And Artifact Infrastructure + summary: Source forge, registry, and automation-runner infrastructure for Railiance, separated out from + railiance-apps/railiance-enablement; covers current Gitea operation, the Forgejo migration, container/package + registries, and Actions runner substrate. + vector: D3 / A1 / C1 / R0 + domain: financials + status: draft + owner: railiance-forge + path: registry/capabilities/capability.railiance.forge-infrastructure.md + tags: + - railiance + - forgejo + - forge + - ci-runner + consumption_modes: + - cli (operator tooling) + - documentation/runbooks diff --git a/tools/forgejo-runner-status.sh b/tools/forgejo-runner-status.sh new file mode 100755 index 0000000..70a0f9f --- /dev/null +++ b/tools/forgejo-runner-status.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -u + +FORGEJO_URL="${FORGEJO_URL:-https://forgejo.coulomb.social}" +FORGEJO_KUBECONFIG="${FORGEJO_KUBECONFIG:-${HOME}/.kube/config-hosteurope}" +RUNNER_HOST="${RUNNER_HOST:-}" +RUNNER_SSH_USER="${RUNNER_SSH_USER:-}" +RUNNER_SSH_KEY="${RUNNER_SSH_KEY:-}" +SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-5}" + +section() { printf '\n## %s\n' "$1"; } +have() { command -v "$1" >/dev/null 2>&1; } +http_code() { curl -sS -m 8 -o /dev/null -w '%{http_code}' "$1" 2>/dev/null || printf 'error'; } + +section "Tool availability" +for tool in curl ssh; do + if have "$tool"; then printf 'ok: %s\n' "$tool"; else printf 'missing: %s\n' "$tool"; fi +done + +section "Forgejo endpoint checks" +if have curl; then + printf 'forgejo root: %s\n' "$(http_code "${FORGEJO_URL}/")" + printf 'forgejo api version: %s\n' "$(http_code "${FORGEJO_URL}/api/v1/version")" + printf 'forgejo registry /v2 (GET): %s\n' "$(curl -sS -m 8 -o /dev/null -w '%{http_code}' -X GET "${FORGEJO_URL}/v2/")" +else + echo "curl missing; skipping endpoint checks" +fi + +section "In-cluster runner (railiance01)" +if have kubectl && [ -r "${FORGEJO_KUBECONFIG}" ]; then + KUBECONFIG="${FORGEJO_KUBECONFIG}" kubectl get deploy,pods,pvc -n forgejo -l app.kubernetes.io/name=forgejo-runner --ignore-not-found 2>/dev/null || true + KUBECONFIG="${FORGEJO_KUBECONFIG}" kubectl logs -n forgejo deploy/forgejo-runner -c runner --tail=5 2>/dev/null || true +else + echo "kubectl or kubeconfig missing; skipping in-cluster probe" +fi + +section "Legacy host runner probe (optional)" +if [ -n "${RUNNER_HOST}" ] && have ssh; then + ssh_target="${RUNNER_HOST}" + if [ -n "${RUNNER_SSH_USER}" ]; then ssh_target="${RUNNER_SSH_USER}@${RUNNER_HOST}"; fi + ssh_args=(-o BatchMode=yes -o ConnectTimeout="${SSH_CONNECT_TIMEOUT}") + if [ -n "${RUNNER_SSH_KEY}" ]; then ssh_args+=(-i "${RUNNER_SSH_KEY}"); fi + ssh "${ssh_args[@]}" "${ssh_target}" ' + set -u + echo "host=$(hostname)" + if command -v forgejo-runner >/dev/null 2>&1; then forgejo-runner -v || true; else echo "missing: forgejo-runner"; fi + if command -v docker >/dev/null 2>&1; then docker --version || true; else echo "missing: docker"; fi + if command -v systemctl >/dev/null 2>&1; then + systemctl is-active forgejo-runner 2>/dev/null || true + fi + if [ -f /var/lib/forgejo-runner/.runner ]; then echo "ok: /var/lib/forgejo-runner/.runner present"; fi + ' +elif [ -n "${RUNNER_HOST}" ]; then + echo "ssh missing; skipping legacy host probe" +else + echo "RUNNER_HOST unset; skipping legacy host probe" +fi \ No newline at end of file diff --git a/workplans/FORGE-WP-0001-repository-foundation.md b/workplans/archived/260702-FORGE-WP-0001-repository-foundation.md similarity index 99% rename from workplans/FORGE-WP-0001-repository-foundation.md rename to workplans/archived/260702-FORGE-WP-0001-repository-foundation.md index b34676e..7cb765c 100644 --- a/workplans/FORGE-WP-0001-repository-foundation.md +++ b/workplans/archived/260702-FORGE-WP-0001-repository-foundation.md @@ -2,7 +2,7 @@ id: FORGE-WP-0001 type: workplan title: "railiance-forge repository foundation" -domain: railiance +domain: financials repo: railiance-forge status: finished owner: codex diff --git a/workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md b/workplans/archived/260702-FORGE-WP-0002-registry-docs-and-readonly-ops.md similarity index 99% rename from workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md rename to workplans/archived/260702-FORGE-WP-0002-registry-docs-and-readonly-ops.md index bf21513..c97127a 100644 --- a/workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md +++ b/workplans/archived/260702-FORGE-WP-0002-registry-docs-and-readonly-ops.md @@ -2,7 +2,7 @@ id: FORGE-WP-0002 type: workplan title: "Canonical registry docs and read-only forge operations" -domain: railiance +domain: financials repo: railiance-forge status: finished owner: codex diff --git a/workplans/FORGE-WP-0003-actions-runner-substrate.md b/workplans/archived/260702-FORGE-WP-0003-actions-runner-substrate.md similarity index 99% rename from workplans/FORGE-WP-0003-actions-runner-substrate.md rename to workplans/archived/260702-FORGE-WP-0003-actions-runner-substrate.md index 16779fc..9a28b1b 100644 --- a/workplans/FORGE-WP-0003-actions-runner-substrate.md +++ b/workplans/archived/260702-FORGE-WP-0003-actions-runner-substrate.md @@ -2,7 +2,7 @@ id: FORGE-WP-0003 type: workplan title: "Gitea Actions runner substrate for Railiance workloads" -domain: railiance +domain: financials repo: railiance-forge status: finished owner: codex diff --git a/workplans/FORGE-WP-0004-public-gitea-root-endpoint.md b/workplans/archived/260702-FORGE-WP-0004-public-gitea-root-endpoint.md similarity index 99% rename from workplans/FORGE-WP-0004-public-gitea-root-endpoint.md rename to workplans/archived/260702-FORGE-WP-0004-public-gitea-root-endpoint.md index cf86955..b510fa9 100644 --- a/workplans/FORGE-WP-0004-public-gitea-root-endpoint.md +++ b/workplans/archived/260702-FORGE-WP-0004-public-gitea-root-endpoint.md @@ -2,7 +2,7 @@ id: FORGE-WP-0004 type: workplan title: "Standard public Gitea HTTPS root endpoint" -domain: railiance +domain: financials repo: railiance-forge status: finished owner: codex diff --git a/workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md b/workplans/archived/260702-FORGE-WP-0005-remove-gitea-nodeport-side-door.md similarity index 99% rename from workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md rename to workplans/archived/260702-FORGE-WP-0005-remove-gitea-nodeport-side-door.md index f2cfb1d..a914b86 100644 --- a/workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md +++ b/workplans/archived/260702-FORGE-WP-0005-remove-gitea-nodeport-side-door.md @@ -2,7 +2,7 @@ id: FORGE-WP-0005 type: workplan title: "Remove public Gitea NodePort side door" -domain: railiance +domain: financials repo: railiance-forge status: finished owner: codex