Captures friction points surfaced during RAIL-PL-WP-0001 T01 execution: missing SSH key, no credential.helper, manual MCP registration, no bootstrap script. Collects them into a repeatable onboarding journey. Tasks: - T01: git credential.helper for Gitea (libsecret/store/cache) - T02: SSH key generation and host authorization automation - T03: Claude Code MCP registration make target - T04: idempotent bootstrap-env.sh (high priority) - T05: onboarding guide (operator + collaborator personas) - T06: state hub multi-user model (deferred, low priority) Workstream: a28d9e29-4119-4b73-9469-f921920253ef Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.5 KiB
id, type, title, domain, repo, status, owner, topic_slug, state_hub_workstream_id, created, updated
| id | type | title | domain | repo | status | owner | topic_slug | state_hub_workstream_id | created | updated |
|---|---|---|---|---|---|---|---|---|---|---|
| CUST-WP-0012 | workplan | Multi-User Onboarding and Environment Bootstrap | custodian | the-custodian | active | custodian | custodian | a28d9e29-4119-4b73-9469-f921920253ef | 2026-03-11 | 2026-03-11 |
Multi-User Onboarding and Environment Bootstrap
Goal
Make the Custodian system accessible to collaborators beyond the primary operator. A new user (or a new machine for the existing operator) should be able to go from zero to a productive Claude Code session with full State Hub MCP connectivity in a single session, without manual steps or undocumented tribal knowledge.
Context
Several friction points surfaced during the 2026-03-11 session:
- No SSH key for Railiance01 on WSL2 → blocked
make tunnel-loop - No
~/.railiance_gitea.conf→ blocked repo creation script - Token missing
read:userscope → blocked org repo creation - No
git credential.helper→ credentials required on every push - MCP registration is manual and documented only in
CLAUDE.md
Each of these is a solved problem in isolation. This workstream collects them into a repeatable, documented bootstrap experience.
Scope
Two personas:
| Persona | Access level | Typical machine |
|---|---|---|
| Primary operator | Full access, all domains | WSL2 workstation |
| Domain collaborator | Read + write to one domain | COULOMBCORE, remote laptop |
Tasks
T01 — Git credential.helper for Gitea access
id: CUST-WP-0012-T01
state_hub_task_id: 71628269-9a75-4dae-a347-e64a86040322
status: todo
priority: medium
Document and automate git credential.helper setup for Gitea
(http://92.205.130.254:32166). Recommend libsecret (keyring-backed)
on machines that support it; fall back to credential.helper=store
(persistent, plaintext ~/.git-credentials) on headless servers.
Include in bootstrap script (T04) and onboarding guide (T05).
# Preferred: libsecret (GNOME keyring, WSL2 with keyring daemon)
sudo apt-get install -y libsecret-1-0 libsecret-1-dev
sudo make -C /usr/share/doc/git/contrib/credential/libsecret
git config --global credential.helper \
/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
# Fallback: store (plaintext, suitable for headless servers)
git config --global credential.helper store
# Headless server alternative: cache (in-memory, 1h timeout)
git config --global credential.helper 'cache --timeout=3600'
Done when: included in bootstrap script; push to Gitea works without re-entering credentials on second attempt.
T02 — SSH key generation and authorization automation
id: CUST-WP-0012-T02
state_hub_task_id: fea965e9-8a8f-439c-9096-8f7756eb71ed
status: todo
priority: medium
Script or Ansible task that:
- Generates an
ed25519key pair on the new machine if none exists - Displays the public key with copy instructions
- Authorizes it on all managed hosts (Railiance01, COULOMBCORE) via
ssh-copy-idor Ansibleauthorized_keymodule
Surfaced by: RAIL-PL-WP-0001 T01 — no SSH key on WSL2 blocked
make tunnel-loop HOST=tegwick@92.205.62.239.
# Generate if missing
[[ -f ~/.ssh/id_ed25519 ]] || ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
# Authorize on a target host (requires existing access once)
ssh-copy-id -i ~/.ssh/id_ed25519.pub tegwick@92.205.62.239
ssh-copy-id -i ~/.ssh/id_ed25519.pub tegwick@92.205.130.254
Done when: included in bootstrap script; documented in onboarding guide.
T03 — Claude Code MCP registration automation
id: CUST-WP-0012-T03
state_hub_task_id: 60318e9a-972e-45c8-afde-82ed0625f594
status: todo
priority: medium
Automate the state-hub MCP server registration on a new machine.
Currently this is a multi-step manual process documented in
~/.claude/CLAUDE.md. It should be a single make target or script:
# In the-custodian/state-hub/
make register-mcp # idempotent; safe to re-run
The script should:
- Detect whether
state-hubis already in~/.claude.json - Extract the server config from
.mcp.json - Run
claude mcp add-json -s user state-hub <config> - Run
patch_mcp_cwd.pyto restore the cwd field - Print instructions to restart Claude Code
Should also detect whether the state hub is reachable directly
(http://127.0.0.1:8000) or needs a tunnel (via ops-bridge), and emit
a warning if neither is available.
Done when: make register-mcp works on a clean machine; documented
in onboarding guide.
T04 — Environment bootstrap script
id: CUST-WP-0012-T04
state_hub_task_id: 84a94761-e424-4470-a9a2-64d9cabadb7f
status: todo
priority: high
Single idempotent script: state-hub/scripts/bootstrap-env.sh
Checks/installs prerequisites and configures the environment:
| Step | What |
|---|---|
| Prerequisites | git, sops, age, helm, kubectl, uv, claude CLI |
| Git credential | credential.helper (libsecret or store) |
| SSH key | Generate ed25519 if missing; display public key |
| MCP registration | make register-mcp (T03) |
| Gitea config | Prompt for token; write ~/.railiance_gitea.conf |
| Health check | curl /state/health; warn if tunnel needed |
Design constraints:
- Idempotent: safe to run on an already-configured machine
- No silent failures: each step prints ✓ / ✗ / ⚠
- Minimal dependencies: bash + curl only to get started
Done when: running the script on a clean Ubuntu 24.04 machine produces a working Custodian environment with no additional manual steps.
T05 — Onboarding guide and user journey documentation
id: CUST-WP-0012-T05
state_hub_task_id: b0839802-659a-475b-8b84-ab7341ea3d15
status: todo
priority: medium
Write docs/onboarding.md in the-custodian covering the full journey
for both personas:
Primary operator (new machine):
- Prerequisites (git, SSH client)
- Clone
the-custodian - Run
make bootstrap-env(T04) - Restart Claude Code → verify MCP is active
- First session:
get_state_summary()→ orient → work
Domain collaborator (new person):
- Prerequisites + Gitea account
ssh-copy-idto get access to Railiance01 (or just COULOMBCORE)- Set up ops-bridge tunnel to reach state hub
- Clone domain repo
- First Claude Code session with MCP via tunnel
- Contributing a workplan (ADR-001 convention)
Done when: a new collaborator can follow the guide without clarification from the primary operator.
T06 — State Hub multi-user model (deferred)
id: CUST-WP-0012-T06
state_hub_task_id: d5df3302-67b9-4765-a8d8-ea2df53dff6e
status: todo
priority: low
Design a lightweight user/role model for the state hub:
| Role | Permissions |
|---|---|
| Primary operator | Full read/write, all domains |
| Domain collaborator | Read all; write to own domain only |
| Observer | Read-only |
Decision needed: enforce at API layer (HTTP Basic / token auth per domain) or rely on Gitea repo permissions as the authoritative boundary (simpler — the hub is a read model anyway).
Deferred until: first external collaborator is actively onboarding. Implement T01–T05 first; multi-user access control is only needed when there is more than one user.
References
- ops-bridge repo:
ops-bridge(tunnel lifecycle management) - MCP registration:
~/.claude/CLAUDE.md(current manual procedure) - Gitea repo creation:
railiance-cluster/tools/create_railiance_repo.sh - ADR-001: workplans as repo artefacts
- Surfaced by: RAIL-PL-WP-0001 T01 execution, 2026-03-11