Compare commits

...

10 commits

Author SHA1 Message Date
dc760eb58e Add Forgejo Actions workflow templates and repo promotion helper
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s
Canonical ci-smoke, container-build-push, and multirepo build templates for
railiance01 runners. Documents adoption path for tier 1-3 repos.
2026-07-04 12:49:06 +02:00
58c3c48d00 Regenerate agent instructions: workstream -> workplan terminology
Registration guidance now prescribes file-first + fix-consistency (C-06)
instead of manual create_workplan/create_workstream calls; progress-event
examples use workplan_id; legacy field names annotated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 01:47:45 +02:00
d0e15767f6 Repo hygiene: fill stack-and-commands, normalize workplan statuses
- Fill .claude/rules/stack-and-commands.md (was an empty TODO template)
- Normalize workplan frontmatter statuses to canonical vocabulary
  (completed/done -> finished) per ADR-001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 00:21:48 +02:00
bd2913781e Normalize agent instructions and workplan frontmatter (STATE-WP-0067)
- Align agent files with on-disk workplan prefixes (infer from workplan ids)
- Set workplan domain to registered domain_slug; add topic_slug where applicable
- Repair frontmatter delimiter formatting; migrate legacy task status literals
- Regenerate AGENTS.md, CLAUDE.md, and .claude/rules from State Hub templates
2026-06-22 23:16:28 +02:00
7c663d6da5 Add .repo-classification.yaml (CUST-WP-0050 T11 agent first-pass) 2026-06-22 17:47:41 +02:00
1186415864 Add credential routing instructions for all agent runtimes
Propagate shared credential-routing section (Codex, Claude, Grok, llm-connect)
from state-hub template via scripts/propagate_credential_routing.py.
2026-06-18 22:48:39 +02:00
1d944dc497 Add capability registry scaffold (REUSE-WP-0014-T07 B05) 2026-06-16 01:58:01 +02:00
b34d08c358 Reference forge runner contract 2026-06-05 16:16:42 +02:00
b6712300c6 Clarify enablement forge handoffs 2026-06-05 15:43:13 +02:00
a9301a009c Add enablement intent 2026-06-05 00:56:34 +02:00
20 changed files with 712 additions and 73 deletions

View file

@ -0,0 +1,50 @@
# Credential and access routing
**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect**
for inference. Run this check **before** requesting secrets, API keys, SSH access,
login tokens, or database passwords — in any repo, not only `ops-warden`.
ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every
other credential need belongs to another subsystem. **Do not** message
`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key.
### Lookup (do this first)
```bash
warden route find "<describe your need>" --json
warden route show <catalog-id> --json
```
Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`).
| Agent runtime | How to orient |
| --- | --- |
| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-enablement` is for coordination, not secret vending |
| **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
| I need… | Owner | ops-warden executes? |
| --- | --- | --- |
| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes**`warden sign` |
| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only |
| Login / OIDC / MFA | key-cape / Keycloak | No — route only |
| Authorization decision | flex-auth | No — route only |
| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` |
| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only |
### Anti-patterns (do not do these)
- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc.
- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist
- Pasting secrets into Git, State Hub, workplans, logs, or chat
### Other capabilities (reuse-surface)
Non-credential capabilities are usually discovered through **reuse-surface** federation
(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in
every repo's agent instructions because it is high-frequency, high-risk, and easy to
get wrong.
**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml`

View file

@ -1,37 +1,41 @@
## First Session Protocol
Triggered when `get_domain_summary("railiance")` shows **no workstreams**.
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/railiance/project_charter_v0.1.md` — purpose, scope
- `~/the-custodian/canon/projects/railiance/roadmap_v0.1.md` — planned phases
- `~/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 workstreams to Bernd**
Propose 13 workstreams — each a coherent strand, weeks to months, anchored to a
**Step 3 — Propose workplans to Bernd**
Propose 13 workplans — each a coherent strand, weeks to months, anchored to a
roadmap phase. **Wait for approval before creating.**
**Step 4 — Create workplan file first, then DB record (ADR-001)**
**Step 4 — Write the workplan file; fix-consistency registers it (ADR-001)**
```
workplans/railiance-enablement-WP-NNNN-<slug>.md ← write this first
workplans/RAILIANCE-WP-NNNN-<slug>.md ← write this, commit it
```
Then register in the hub:
```
create_workstream(topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", title="...", owner="...", description="...")
create_task(workstream_id="<id>", title="...", priority="high|medium|low")
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-enablement
```
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 railiance into N workstreams, M tasks",
summary="First session: structured financials into N workplans, M tasks",
event_type="milestone",
topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38",
detail={"workstreams": [...], "tasks_created": M}
detail={"workplans": [...], "tasks_created": M}
)
```

View file

@ -1,5 +1,5 @@
**Purpose:** OAS S4 Developer Enablement — CI/CD pipelines, developer portal, platform templates
**Domain:** railiance
**Domain:** financials
**Repo slug:** railiance-enablement
**Topic ID:** ca369340-a64e-442e-98f1-a4fa7dc74a38

View file

@ -1,6 +1,7 @@
## Session Protocol
State Hub: http://127.0.0.1:8000
Dev Hub (State Hub API): http://127.0.0.1:8000
MCP server name in `~/.claude.json`: `dev-hub`
**Step 1 — Orient**
@ -10,7 +11,7 @@ cat .custodian-brief.md
```
Then call the MCP tool for richer cross-domain context when MCP tools are exposed:
```
get_domain_summary("railiance")
get_domain_summary("financials")
```
If MCP tools are unavailable in the current agent session, use the REST API:
```bash
@ -39,11 +40,11 @@ curl -s -X PATCH "http://127.0.0.1:8000/messages/<id>/read" \
ls workplans/
```
For each file with `status: ready`, `active`, or `blocked`, note pending
`todo`/`in_progress` tasks.
`wait`/`todo`/`progress` tasks.
**Step 4 — Present brief**
1. **Active workstreams** for `railiance` — title, task counts, blocking decisions
1. **Active workplans** for `financials` — title, task counts, blocking decisions
2. **Pending tasks** from `workplans/` + any `[repo:railiance-enablement]` hub tasks
3. **Goal guidance** — if `goal_guidance` in summary:
- `needs_workplan`: surface as top action — *"Repo goal '{title}' has no workplan yet"*
@ -51,33 +52,42 @@ For each file with `status: ready`, `active`, or `blocked`, note pending
4. **Suggested next action** — highest-priority open item
5. **SBOM status** — flag if `last_sbom_at` is unset for this repo
If no workstreams: follow First Session Protocol (`first-session.md`).
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*. Bootstrap tools (`create_workstream`, `create_task`)
> are First Session Protocol only. Work structure belongs in repo files (ADR-001).
> 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", workstream_id="<uuid>")
add_progress_event(summary="...", topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", workplan_id="<uuid>")
```
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","workstream_id":"<uuid>","event_type":"note","summary":"what changed","author":"codex"}'
-d '{"topic_id":"ca369340-a64e-442e-98f1-a4fa7dc74a38","workplan_id":"<uuid>","event_type":"note","summary":"what changed","author":"codex"}'
```
If workplan files were modified, ensure the local copy is up to date first:
If workplan files were modified, ensure the local copy is up to date first,
then sync from the repo checkout:
```bash
git -C <repo_path> pull --ff-only
cd ~/state-hub && make fix-consistency REPO=railiance-enablement
git pull --ff-only
statehub fix-consistency
```
For repos where implementation runs on a remote machine (e.g. CoulombCore),
use the combined target which pulls before fixing:
use the pull-before-fix mode from any shell with the State Hub CLI:
```bash
cd ~/state-hub && make fix-consistency-remote REPO=railiance-enablement
statehub fix-consistency --repo railiance-enablement --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

View file

@ -1,19 +1,13 @@
## Stack
<!-- TODO: Fill in language, frameworks, and key dependencies -->
- **Language:**
- **Key deps:**
- **Language:** documentation and reusable CI/CD / platform templates (no application code yet)
- **Key deps:** none at present — S4 layer is largely unpopulated
## Dev Commands
```bash
# TODO: Fill in the standard commands for this repo
# Install dependencies
# Run tests
# Lint / type check
# Build / package (if applicable)
make help # only target currently defined
```
No build, test, or deploy commands exist yet. When S4 work starts (CI/CD
templates, SDKs, buildpacks), fill this file in the same change.

View file

@ -1,28 +1,45 @@
## Workplan Convention (ADR-001)
File location: `workplans/railiance-enablement-WP-NNNN-<slug>.md`
ID prefix: `RAILIANCE-WP`
File location: `workplans/RAILIANCE-WP-NNNN-<slug>.md`
ID prefix: `RAILIANCE-WP-`
Work items originate as files in this repo **before** being registered in the hub.
Canonical workplan/workstream frontmatter statuses are:
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-enablement-WP-NNNN-<slug>.md`. The frontmatter id remains
prefix: `YYMMDD-RAILIANCE-WP-NNNN-<slug>.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`, workstream slug `adhoc-YYYY-MM-DD`, and task ids
`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-enablement]` hub tasks —
visible at session start. Pick one up by creating the workplan file, then registering
the workstream.
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: "<uuid>" # 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.
<!-- Ralph Loop rules and HEUREKA sequence: ~/.claude/CLAUDE.md — do not duplicate here -->

View file

@ -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}"

17
.repo-classification.yaml Normal file
View file

@ -0,0 +1,17 @@
repo_classification:
standard: Repo Classification Standard
version: '1.0'
classified_at: '2026-06-22'
classified_by: agent
category: project
domain: financials
secondary_domains: []
capability_tags:
- platform
- operations
business_stake:
- technology
- operations
business_mechanics:
- coordination
- operation

View file

@ -4,7 +4,7 @@
**Purpose:** OAS S4 Developer Enablement — CI/CD pipelines, developer portal, platform templates
**Domain:** railiance
**Domain:** financials
**Repo slug:** railiance-enablement
**Topic ID:** `ca369340-a64e-442e-98f1-a4fa7dc74a38`
**Workplan prefix:** `RAILIANCE-WP-`
@ -20,6 +20,12 @@ there is no MCP server for Codex agents.
|---------|-----|
| 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
@ -27,8 +33,8 @@ there is no MCP server for Codex agents.
# Offline brief — works without hub connection
cat .custodian-brief.md
# Active workstreams for this domain
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
@ -51,20 +57,20 @@ curl -s -X POST http://127.0.0.1:8000/progress/ \
"summary": "what was done",
"event_type": "note",
"author": "codex",
"workstream_id": "<uuid>",
"workplan_id": "<uuid>",
"task_id": "<uuid>"
}'
```
Omit `workstream_id` / `task_id` when not applicable.
Omit `workplan_id` / `task_id` when not applicable.
### Update task status
```bash
curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}'
# values: todo | in_progress | done | blocked
-d '{"status": "progress"}'
# values: wait | todo | progress | done | cancel
```
### Flag a task for human review
@ -80,10 +86,10 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
## Session Protocol
**Start:**
1. `cat .custodian-brief.md` — domain goal and open workstreams (offline-safe)
1. `cat .custodian-brief.md` — domain goal and open workplans (offline-safe)
2. Check inbox: `GET /messages/?to_agent=railiance-enablement&unread_only=true`; mark read
3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks
4. Check blocked tasks: `GET /tasks/?needs_human=true`
4. Check human-needed tasks: `GET /tasks/?needs_human=true`
**During work:**
- Update task statuses in workplan files as tasks progress
@ -92,12 +98,69 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
**Close:**
1. Update workplan file task statuses to reflect progress
2. Log: `POST /progress/` with a summary of what changed
3. Note for the custodian operator: after workplan file changes, run from
`~/state-hub`:
3. After workplan file changes, run:
```bash
make fix-consistency REPO=railiance-enablement
statehub fix-consistency
```
This syncs task status from files into the hub DB.
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.
---
## Credential and access routing
**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect**
for inference. Run this check **before** requesting secrets, API keys, SSH access,
login tokens, or database passwords — in any repo, not only `ops-warden`.
ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every
other credential need belongs to another subsystem. **Do not** message
`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key.
### Lookup (do this first)
```bash
warden route find "<describe your need>" --json
warden route show <catalog-id> --json
```
Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`).
| Agent runtime | How to orient |
| --- | --- |
| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-enablement` is for coordination, not secret vending |
| **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
| I need… | Owner | ops-warden executes? |
| --- | --- | --- |
| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes**`warden sign` |
| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only |
| Login / OIDC / MFA | key-cape / Keycloak | No — route only |
| Authorization decision | flex-auth | No — route only |
| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` |
| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only |
### Anti-patterns (do not do these)
- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc.
- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist
- Pasting secrets into Git, State Hub, workplans, logs, or chat
### Other capabilities (reuse-surface)
Non-credential capabilities are usually discovered through **reuse-surface** federation
(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in
every repo's agent instructions because it is high-frequency, high-risk, and easy to
get wrong.
**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml`
<!-- REPO-AGENTS-EXTENSIONS -->
<!-- Append repo-specific agent instructions below this marker.
The state-hub template sync preserves content after this line. -->
---
@ -124,7 +187,7 @@ anything needing analysis, design, approval, dependencies, or multiple phases.
id: RAILIANCE-WP-NNNN
type: workplan
title: "..."
domain: railiance
domain: financials
repo: railiance-enablement
status: proposed | ready | active | blocked | backlog | finished | archived
owner: codex
@ -146,7 +209,7 @@ derived health labels, not frontmatter statuses.
` ` `task
id: RAILIANCE-WP-NNNN-T01
status: todo | in_progress | done | blocked
status: wait | todo | progress | done | cancel
priority: high | medium | low
state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
` ` `
@ -154,7 +217,7 @@ state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
Task description text.
```
Status progression: `todo``in_progress` → `done` (or `blocked`)
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

View file

@ -8,4 +8,5 @@
@.claude/rules/stack-and-commands.md
@.claude/rules/architecture.md
@.claude/rules/repo-boundary.md
@.claude/rules/credential-routing.md
@.claude/rules/agents.md

150
INTENT.md Normal file
View file

@ -0,0 +1,150 @@
# INTENT
> This file captures **why this repository exists**,
> the **direction it is moving toward**, and
> the **kind of system it is meant to become**.
> It is intentionally **aspirational and stable**, not a description of current implementation.
---
## One-liner
**The developer enablement layer - turning Railiance platform capabilities into paved paths for building, testing, packaging, and promoting workloads.**
---
## Why This Exists
A healthy platform does not automatically make delivery easy.
Developers and operators still need repeatable ways to build workloads, test
them, package them, route them through review, and hand them to application
release surfaces without inventing those paths from scratch each time.
Without a disciplined enablement layer:
* every workload invents a different pipeline,
* build and deployment templates drift,
* platform capabilities are hard to consume correctly,
* and application releases depend on undocumented operator memory.
This layer exists to provide **paved delivery paths**: shared automation,
templates, SDKs, build conventions, and self-service workflows that let
Railiance evolve faster without dissolving its layer boundaries.
---
## The Mission
> *Where we are going.*
To become the **canonical home for developer and delivery enablement** -
CI/CD pipelines, GitOps workflows, workload templates, SDKs, buildpacks,
developer portal surfaces, and promotion conventions that help source repos
move safely toward S5 application releases while consuming forge-provided
runners, registries, and artifact evidence.
This means:
* Common delivery paths are **automated and reusable**
* Build and deployment templates encode **Railiance platform expectations**
* Developers get fast feedback through **standard checks and pipelines**
* S5 can consume release artifacts through **clear handoff contracts**
* Forge runtime and runner substrate remain owned by **railiance-forge**
* Enablement improves delivery without taking ownership of app runtime
operation
---
## Core Principles
### 1. Paved Paths, Not One-Off Pipelines
The default way to build, test, package, and promote a workload should be
shared, documented, and easy to reuse.
### 2. Enablement, Not Applications
This layer helps applications reach production; it does not own their source
code, runtime configuration, or user-facing operations.
### 3. Platform-Aware Templates
Templates, SDKs, and buildpacks should encode the contracts exposed by S1-S3 so
consumers do not need to rediscover platform assumptions.
### 4. Clear Handoff to S5
CI/CD and promotion flows should produce artifacts, metadata, and evidence that
the application layer can deploy and verify without guessing.
### 5. Clear Handoff to Forge
Reusable workflows should state the forge capabilities they require: repository
events, runner labels, package credentials, registry endpoints, and artifact
evidence. This layer defines the reusable workflow shape; `railiance-forge`
owns the runtime and credentials behind it.
### 6. Fast Feedback
Developers should learn about broken builds, missing declarations, incompatible
interfaces, and release-readiness gaps before those problems reach live
application deployments.
### 7. Boundaries Preserve Velocity
Enablement should make the layered architecture easier to use, not become a
shortcut for mutating infrastructure, cluster, platform, or application
responsibilities.
---
## What This Is (Conceptually)
This layer is:
* a **developer enablement** layer
* a home for **CI/CD and GitOps workflow patterns**
* a source of **workload templates, SDKs, and buildpacks**
* a **promotion handoff** surface between source repos and S5 deployments
* a future **developer portal** and self-service entry point
* a place to codify delivery knowledge into **repeatable automation**
---
## What This Is Not
This layer is not:
* the infrastructure substrate
* the Kubernetes runtime
* the shared platform-services layer
* the application deployment and operations layer
* the source forge, package/container registry, or runner substrate layer
* the source-code home for business workloads
* a replacement for repo-owned workplans, ADRs, or implementation decisions
It is the **delivery machinery** that helps the rest of Railiance change
safely and repeatedly.
---
## Direction of Evolution
This layer is expected to evolve toward:
* Standard **pipeline templates** for Railiance workloads
* Reusable **build and image promotion** conventions
* GitOps workflows with clear **review and rollback** expectations
* Handoff contracts with `railiance-forge` for **runner labels, package
credentials, registry endpoints, and artifact evidence**
* Reusable templates that cite the forge-owned **runner/GitOps ownership
contract** before depending on privileged labels or credentials
* Developer-facing **self-service templates** and portal entry points
* SDKs and examples that make platform capabilities easy to consume correctly
* Release evidence that S5 can use for **deployment readiness**
---
## Guiding Question
> **How can Railiance make the correct delivery path the easiest path, so workloads can move from source to production with speed, evidence, and clear ownership?**

View file

@ -8,23 +8,33 @@
## One-liner
S4 Developer Enablement layer of the Railiance OAS Stack — owns CI/CD pipelines, developer portal, platform templates, SDKs, and buildpacks.
S4 Developer Enablement layer of the Railiance OAS Stack — owns reusable CI/CD
templates, developer portal paths, platform templates, SDKs, and buildpacks;
uses forge capabilities without owning forge runtime or runner substrate.
---
## Core Idea
Railiance is structured as five independent repos per OAS Stack layer. This repo is S4 — the tools that allow the system to evolve. S4 depends on the platform (S3) being operational before any tooling can use platform services, and in turn S5 (applications) uses S4's CI/CD pipelines and deployment templates.
Railiance is structured as independent repos per OAS Stack layer. This repo is
S4: the reusable tools and paved paths that allow the system to evolve. S4
depends on the platform (S3) being operational before tooling can use platform
services. S5 applications consume S4 templates and conventions, while
`railiance-forge` provides source hosting, registries, and runner substrate.
---
## In Scope
- CI/CD pipelines and automation tooling
- Reusable CI/CD workflow templates and automation patterns
- Developer portal (self-service deployment interface)
- Platform deployment templates for workloads
- SDKs and libraries for platform consumers
- Buildpacks and image builders
- Handoff contracts to `railiance-forge` for runner labels, artifact evidence,
and registry consumption
- Template references to forge-provided runner labels and credentials documented
in `/home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md`
---
@ -33,7 +43,10 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- OS-level concerns → railiance-infra (S1)
- Kubernetes runtime → railiance-cluster (S2)
- Platform services → railiance-platform (S3)
- Source forge runtime, container/package registries, runner deployment,
runner labels, and runner credentials → railiance-forge
- Application deployments → railiance-apps (S5)
- App-specific workflows, release charts, and source code → app/source repos
- No re-configuration of lower layers from this repo
---
@ -42,6 +55,8 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- Setting up CI/CD for the Railiance stack
- Creating or modifying developer tools and deployment templates
- Defining reusable workflow templates that run on forge-provided runners
- Defining promotion conventions and evidence formats consumed by S5
- S3 is operational and tooling layer can now be built
---
@ -50,35 +65,53 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- S3 (platform services) is not yet operational (pre-condition not met)
- Infrastructure, cluster, or platform work needed (wrong layer)
- The work is Gitea/Forgejo runtime, registry endpoint, package retention,
runner deployment, or runner secret access (use `railiance-forge`)
- The work is a concrete app release or app-specific runbook (use
`railiance-apps` or the source app repo)
---
## Current State
- Status: emerging (ArgoCD deployed; no S4 workplans yet)
- Implementation: ArgoCD is deployed in the `argocd` namespace on COULOMBCORE — installed as a cluster addon (managed from S2 for now); no S4-owned workplans yet
- Implementation: ArgoCD is deployed in the `argocd` namespace on COULOMBCORE
as a cluster addon managed from S2 for now; no S4-owned workplans yet
- Stability: n/a for S4-owned content; ArgoCD itself is operational
- Usage: ArgoCD available for GitOps deployments; formal S4 tooling work begins after S3 baseline
- Usage: ArgoCD available for GitOps deployments; formal S4 tooling work begins
after S3 baseline and should consume runner/registry capabilities from
`railiance-forge`
---
## How It Fits
- Upstream dependencies: railiance-platform (S3) must be operational
- Downstream consumers: railiance-apps (S5) uses CI/CD and templates from this layer
- Often used with: railiance-platform (S3), railiance-apps (S5)
- Adjacent forge provider: railiance-forge owns source hosting, registries, and
runner substrate used by S4 workflows
- Downstream consumers: railiance-apps (S5) uses CI/CD and templates from this
layer
- Often used with: railiance-platform (S3), railiance-forge, railiance-apps (S5)
---
## Terminology
- Preferred terms: OAS Stack Level S4, developer enablement, boundary rule
- Preferred terms: OAS Stack Level S4, developer enablement, paved path,
workflow template, promotion convention, boundary rule
- Distinguish "workflow template" from "runner substrate": templates live here;
runner deployment, labels, credentials, and health live in
`railiance-forge`.
---
## Related / Overlapping
- `railiance-platform` (S3) — pre-condition; provides services that S4 tooling depends on
- `railiance-forge` — provides source forge runtime, artifact registries, and
runner substrate consumed by S4 workflows; its runner label and GitOps
boundary contract is
`/home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md`
- `railiance-apps` (S5) — consumer of S4 CI/CD and templates
---
@ -89,13 +122,13 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
type: infrastructure
title: CI/CD pipeline automation
description: Automated build, test, and deployment pipelines for Railiance workloads — planned for when railiance-platform (S3) is operational.
keywords: [ci, cd, pipeline, automation, build, deploy, gitops]
keywords: [ci, cd, pipeline, automation, template, build, deploy, gitops]
```
```capability
type: documentation
title: Platform deployment templates and SDKs
description: Standardised deployment templates, Helm charts, and SDKs enabling consistent application deployments across the Railiance stack.
description: Standardised deployment templates, Helm chart patterns, SDKs, and promotion conventions enabling consistent application deployments across the Railiance stack while consuming forge-owned runners and registries.
keywords: [template, sdk, helm, deployment, developer, buildpack]
```

View file

@ -0,0 +1,66 @@
# Forgejo Actions Workflow Templates
Date: 2026-07-04
Owner: `railiance-enablement` (S4)
Workplans: `RAIL-HO-WP-0005-T08`, `CUST-WP-0054-T04`
## Purpose
Canonical, copy-ready Forgejo Actions workflows for the railiance01 runner
substrate (`railiance01-build-01`, ADR-004). Forgejo/Gitea Actions on our
runners do **not** support `actions/checkout@v4` on the non-root host runner;
use **archive checkout** via `wget` instead.
Templates live in `workflows/` at repo root. Consumer repos copy into
`.forgejo/workflows/` and adjust `IMAGE_NAME` / `EXTRA_REPOS` as needed.
## Runner labels
| Label | Use |
| --- | --- |
| `self-hosted` | Host runner routing smoke, lightweight probes |
| `ubuntu-latest` | Container-isolated smoke (label routing) |
| `container-build` | DinD image build + registry push |
Org secrets (set on `coulomb` org): `REGISTRY_USER`, `REGISTRY_TOKEN`.
## Templates
| File | Tier | When to use |
| --- | ---: | --- |
| `workflows/ci-smoke.yaml` | 1 | Git+CI routing drill; infra/docs repos |
| `workflows/container-build-push.yaml` | 2 | Single-repo `Dockerfile` image publish |
| `workflows/container-build-push-multirepo.yaml` | 3 prep | Docker build with named contexts (e.g. `state-hub` + `hub-core`) |
## Adoption
```bash
mkdir -p .forgejo/workflows
cp /path/to/railiance-enablement/workflows/ci-smoke.yaml .forgejo/workflows/
# For images:
cp /path/to/railiance-enablement/workflows/container-build-push.yaml .forgejo/workflows/image.yaml
# Edit IMAGE_NAME=coulomb/<repo>
git add .forgejo/workflows && git commit -m "Add Forgejo CI from enablement templates"
git push origin main
```
## Proven consumers
| Repo | Template | Evidence |
| --- | --- | --- |
| `coulomb/glas-harness` | `ci-smoke` (in-repo) | Tier 1 pilot |
| `coulomb/key-cape` | `container-build-push` (in-repo) | Tier 2 pilot |
| `coulomb/railiance-*` | `ci-smoke` | Tier 2.5 promotion (2026-07-04) |
## Constraints
- Do not use `actions/checkout@v4` on `self-hosted` / `container-build` runners.
- Static `docker` binary via wget; runner image is non-root and cannot `apk add`.
- Reusable `workflow_call` across repos is not relied on; copy templates instead.
- Runner substrate and labels: `railiance-forge/docs/ci-runner-actions-gitops-ownership.md`.
## References
- `the-custodian/docs/forgejo-repo-migration-pilot-glas-harness.md`
- `railiance-apps/docs/forgejo-on-railiance01.md`
- `docs/adr/ADR-004-forgejo-in-cluster-actions-runner.md` (in `railiance-infra`)

12
registry/README.md Normal file
View file

@ -0,0 +1,12 @@
# Capability Registry
Markdown-first capability index for federation and reuse planning.
## Authoring
1. Copy a capability entry template (see reuse-surface `templates/capability-entry.template.md`).
2. Add the row to `indexes/capabilities.yaml`.
3. Run `reuse-surface validate` from a checkout with the CLI installed.
4. Merge to `main` and verify publish with `reuse-surface establish --publish-check`.
Federation contract: reuse-surface `docs/RegistryFederation.md`.

View file

View file

@ -0,0 +1,4 @@
version: 1
updated: '2026-06-16'
domain: helix_forge
capabilities: []

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Promote a coulomb repo to Forgejo (tier 2.5): mirror, flip remotes, add ci-smoke.
set -euo pipefail
REPO="${1:?usage: promote-repo-to-forgejo.sh <repo-name> [repo-path]}"
REPO_PATH="${2:-$HOME/${REPO}}"
ORG=coulomb
FORGEJO_API="${FORGEJO_API:-https://forgejo.coulomb.social/api/v1}"
TOKEN_FILE="${FORGEJO_TOKEN_FILE:-/tmp/forgejo-tegwick-api-token}"
TEMPLATE="${PROMOTE_CI_TEMPLATE:-$HOME/railiance-enablement/workflows/ci-smoke.yaml}"
if [[ ! -f "${TOKEN_FILE}" ]]; then
echo "Missing API token at ${TOKEN_FILE}" >&2
exit 1
fi
TOKEN=$(cat "${TOKEN_FILE}")
AUTH=(-H "Authorization: token ${TOKEN}")
code=$(curl -sS -o /dev/null -w '%{http_code}' "${AUTH[@]}" "${FORGEJO_API}/repos/${ORG}/${REPO}")
if [[ "${code}" == "404" ]]; then
echo "==> Creating ${ORG}/${REPO} on Forgejo"
curl -fsS -X POST "${FORGEJO_API}/orgs/${ORG}/repos" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d "{\"name\":\"${REPO}\",\"private\":false,\"auto_init\":false}" >/dev/null
elif [[ "${code}" == "200" ]]; then
echo "==> ${ORG}/${REPO} already exists on Forgejo"
else
echo "Unexpected API status ${code} for ${ORG}/${REPO}" >&2
exit 1
fi
cd "${REPO_PATH}"
mkdir -p .forgejo/workflows
if [[ ! -f .forgejo/workflows/ci-smoke.yaml ]]; then
cp "${TEMPLATE}" .forgejo/workflows/ci-smoke.yaml
git add .forgejo/workflows/ci-smoke.yaml
git commit -m "Add Forgejo CI smoke workflow (enablement template)"
fi
if git remote get-url origin 2>/dev/null | grep -q forgejo-remote; then
echo "==> Remotes already on Forgejo"
else
git remote rename origin gitea
git remote add origin "forgejo-remote:${ORG}/${REPO}.git"
echo "==> Remotes: origin=forgejo-remote, gitea=legacy"
fi
echo "==> Pushing ${REPO_PATH} to Forgejo"
git push -u origin main
echo "==> Promoted ${REPO}"

29
workflows/ci-smoke.yaml Normal file
View file

@ -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}"

View file

@ -0,0 +1,61 @@
# Multi-repo Docker build template for tier-3 prep (e.g. state-hub + hub-core).
# Copy to: .forgejo/workflows/image.yaml and set PRIMARY_REPO + EXTRA_REPOS.
# Uses archive checkout (no actions/checkout; non-root runner has no git).
# Dockerfile must reference named contexts, e.g.:
# COPY --from=hub_core_src pyproject.toml /tmp/hub-core/pyproject.toml
name: Build and Publish Multi-Context Image
on:
push:
branches:
- main
paths:
- ".forgejo/workflows/image.yaml"
- "Dockerfile"
workflow_dispatch:
env:
REGISTRY: forgejo.coulomb.social
IMAGE_NAME: coulomb/REPLACE_ME
DOCKER_HOST: tcp://127.0.0.1:2375
# Space-separated coulomb/repo@context_name entries for extra build contexts.
# Example: "coulomb/hub-core@hub_core_src"
EXTRA_REPOS: "coulomb/hub-core@hub_core_src"
jobs:
build-and-push:
runs-on: container-build
steps:
- name: Build and push image
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -eu
REF="${GITHUB_SHA:-main}"
mkdir -p buildctx "${HOME}/bin"
wget -qO /tmp/primary.tar.gz \
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
tar xzf /tmp/primary.tar.gz -C buildctx --strip-components=1
BUILD_ARGS=()
for spec in ${EXTRA_REPOS}; do
repo="${spec%@*}"
ctx="${spec#*@}"
extra_ref="${REF}"
wget -qO "/tmp/${ctx}.tar.gz" \
"https://forgejo.coulomb.social/${repo}/archive/${extra_ref}.tar.gz"
mkdir -p "/tmp/ctx-${ctx}"
tar xzf "/tmp/${ctx}.tar.gz" -C "/tmp/ctx-${ctx}" --strip-components=1
BUILD_ARGS+=(--build-context "${ctx}=/tmp/ctx-${ctx}")
done
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
export PATH="${HOME}/bin:${PATH}"
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
SHORT="${REF:0:7}"
IMAGE="${REGISTRY}/${IMAGE_NAME}"
docker build "${BUILD_ARGS[@]}" \
-t "${IMAGE}:latest" -t "${IMAGE}:main-${SHORT}" buildctx
docker push "${IMAGE}:latest"
docker push "${IMAGE}:main-${SHORT}"
echo "pushed ${IMAGE}:latest and ${IMAGE}:main-${SHORT}"

View file

@ -0,0 +1,48 @@
# Canonical single-repo image build template (tier 2).
# Copy to: .forgejo/workflows/image.yaml and set IMAGE_NAME.
# Requires org secrets: REGISTRY_USER, REGISTRY_TOKEN
# Runner label: container-build (DinD sidecar on railiance01-build-01)
name: Build and Publish Container Image
on:
push:
branches:
- main
paths:
- ".forgejo/workflows/image.yaml"
- "Dockerfile"
- "src/**"
workflow_dispatch:
env:
REGISTRY: forgejo.coulomb.social
# Set per repo, e.g. coulomb/key-cape
IMAGE_NAME: coulomb/REPLACE_ME
DOCKER_HOST: tcp://127.0.0.1:2375
jobs:
build-and-push:
runs-on: container-build
steps:
- name: Build and push image
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -eu
REF="${GITHUB_SHA:-main}"
mkdir -p buildctx "${HOME}/bin"
wget -qO /tmp/repo.tar.gz \
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
export PATH="${HOME}/bin:${PATH}"
docker version
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
SHORT="${REF:0:7}"
IMAGE="${REGISTRY}/${IMAGE_NAME}"
docker build -t "${IMAGE}:latest" -t "${IMAGE}:main-${SHORT}" buildctx
docker push "${IMAGE}:latest"
docker push "${IMAGE}:main-${SHORT}"
echo "pushed ${IMAGE}:latest and ${IMAGE}:main-${SHORT}"