feat(registration): add --codex flag and AGENTS.md template

- register_project.sh: parse --additional/--codex as named flags (not
  positional), skip MCP check in codex mode, generate AGENTS.md from
  agents-codex.template instead of CLAUDE.md + .claude/rules/
- agents-codex.template: new template for Codex repos — HTTP REST session
  protocol, inbox/progress curl examples, ADR-001 workplan convention
- Makefile: add register-codex-project target

Driven by onboarding repo-registry (first non-Claude-Code repo, first
repo under the capabilities domain).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 13:17:50 +02:00
parent 4091b5c8ed
commit 1a8afaa371
3 changed files with 264 additions and 62 deletions

View File

@@ -1,23 +1,24 @@
#!/usr/bin/env bash
# register_project.sh — register a project/repo with the Custodian State Hub
#
# Usage: scripts/register_project.sh <domain> <project_path> [--additional]
# Usage: scripts/register_project.sh <domain> <project_path> [flags]
# domain: slug of an active domain (e.g. custodian, railiance)
# project_path: absolute path to the project directory
# --additional: add a second repo to an existing domain; skip CLAUDE.md generation
# --additional: add a second repo to an existing domain; skip agent file generation
# --codex: generate AGENTS.md (HTTP API) instead of CLAUDE.md + .claude/rules/
#
# Example:
# Examples:
# scripts/register_project.sh railiance /home/worsch/railiance
# scripts/register_project.sh railiance /home/worsch/railiance-infra --additional
# scripts/register_project.sh capabilities /home/worsch/my-repo --codex
#
# What it does:
# 1. Verify the API is reachable
# 2. Verify the domain exists via GET /domains/{slug}/
# 3. Look up the topic ID for the domain (first active topic)
# 4. Check that state-hub is in ~/.claude.json; warn if missing
# 5. Write CLAUDE.md + .claude/rules/*.md (modular @-import structure)
# - If CLAUDE.md already exists, writes .claude/rules/ only and appends
# an @-import comment block to the existing CLAUDE.md
# 4. Check that state-hub is in ~/.claude.json (skipped with --codex)
# 5a. [default] Write CLAUDE.md + .claude/rules/*.md (modular @-import structure)
# 5b. [--codex] Write AGENTS.md from agents-codex.template + SCOPE.md
# 6. POST to /repos/ to register the repo
# 7. POST /repos/{slug}/paths/ to register this machine's local path (host_paths)
# 8. POST a progress event recording the registration
@@ -26,7 +27,14 @@ set -euo pipefail
DOMAIN="${1:-}"
PROJECT_PATH="${2:-}"
ADDITIONAL="${3:-}"
ADDITIONAL=false
CODEX_MODE=false
for arg in "${@:3}"; do
case "$arg" in
--additional) ADDITIONAL=true ;;
--codex) CODEX_MODE=true ;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STATE_HUB_DIR="$(dirname "$SCRIPT_DIR")"
RULES_TEMPLATES_DIR="$SCRIPT_DIR/project_rules"
@@ -92,8 +100,11 @@ else
fi
# ── Step 4: Check MCP registration ────────────────────────────────────────────
echo "==> Checking MCP server registration ..."
MCP_OK="$(python3 -c "
if [[ "$CODEX_MODE" == "true" ]]; then
echo "==> Codex mode: skipping MCP registration check (Claude Code-specific)"
else
echo "==> Checking MCP server registration ..."
MCP_OK="$(python3 -c "
import json
from pathlib import Path
f = Path.home() / '.claude.json'
@@ -103,11 +114,12 @@ else:
d = json.loads(f.read_text())
print('OK' if 'state-hub' in d.get('mcpServers', {}) else 'NOT_REGISTERED')
")"
case "$MCP_OK" in
MISSING_FILE) echo "WARNING: ~/.claude.json not found. MCP server not registered." ;;
NOT_REGISTERED) echo "WARNING: 'state-hub' not in ~/.claude.json. See global CLAUDE.md §MCP Server Registration." ;;
*) echo " MCP OK" ;;
esac
case "$MCP_OK" in
MISSING_FILE) echo "WARNING: ~/.claude.json not found. MCP server not registered." ;;
NOT_REGISTERED) echo "WARNING: 'state-hub' not in ~/.claude.json. See global CLAUDE.md §MCP Server Registration." ;;
*) echo " MCP OK" ;;
esac
fi
# ── Helper: render a template with variable substitution ──────────────────────
render_template() {
@@ -122,39 +134,65 @@ render_template() {
"$tmpl"
}
# ── Step 5: Write .claude/rules/ + CLAUDE.md ──────────────────────────────────
if [[ "$ADDITIONAL" != "--additional" ]]; then
RULES_DIR="$PROJECT_PATH/.claude/rules"
CLAUDE_MD="$PROJECT_PATH/CLAUDE.md"
echo "==> Writing .claude/rules/ ..."
mkdir -p "$RULES_DIR"
for rule in repo-identity session-protocol first-session workplan-convention \
stack-and-commands architecture repo-boundary agents; do
tmpl="$RULES_TEMPLATES_DIR/${rule}.template"
out="$RULES_DIR/${rule}.md"
if [[ -f "$tmpl" ]]; then
render_template "$tmpl" > "$out"
echo " .claude/rules/${rule}.md"
else
echo "WARNING: template missing: $tmpl"
fi
done
# ── Step 5: Write agent instruction files ─────────────────────────────────────
if [[ "$ADDITIONAL" != "true" ]]; then
SCOPE_MD="$PROJECT_PATH/SCOPE.md"
if [[ ! -f "$SCOPE_MD" ]]; then
echo "==> Writing SCOPE.md stub ..."
render_template "$RULES_TEMPLATES_DIR/scope.template" > "$SCOPE_MD"
echo " SCOPE.md written (stub — fill with scope-analyst agent)."
echo " SCOPE.md written (stub — fill in purpose and boundaries)."
else
echo "==> SCOPE.md already exists — skipping."
fi
if [[ -f "$CLAUDE_MD" ]]; then
if [[ "$CODEX_MODE" == "true" ]]; then
# ── 5b: Codex — write AGENTS.md from HTTP-API template ────────────────
AGENTS_MD="$PROJECT_PATH/AGENTS.md"
CODEX_TMPL="$RULES_TEMPLATES_DIR/agents-codex.template"
if [[ ! -f "$CODEX_TMPL" ]]; then
echo "ERROR: agents-codex.template not found at $CODEX_TMPL"
exit 1
fi
if [[ -f "$AGENTS_MD" ]]; then
echo "==> AGENTS.md already exists — skipping (manual merge may be needed)."
else
echo "==> Writing AGENTS.md (Codex / HTTP API mode) ..."
render_template "$CODEX_TMPL" > "$AGENTS_MD"
echo " AGENTS.md written."
fi
echo ""
echo "==> CLAUDE.md already exists — appending @-import suggestion."
cat >> "$CLAUDE_MD" << 'SUGGESTION'
echo "Files needing manual content:"
echo " AGENTS.md — fill in purpose description and stack/commands sections"
echo " SCOPE.md — fill in scope boundaries"
else
# ── 5a: Claude Code — write .claude/rules/ + CLAUDE.md ────────────────
RULES_DIR="$PROJECT_PATH/.claude/rules"
CLAUDE_MD="$PROJECT_PATH/CLAUDE.md"
echo "==> Writing .claude/rules/ ..."
mkdir -p "$RULES_DIR"
for rule in repo-identity session-protocol first-session workplan-convention \
stack-and-commands architecture repo-boundary agents; do
tmpl="$RULES_TEMPLATES_DIR/${rule}.template"
out="$RULES_DIR/${rule}.md"
if [[ -f "$tmpl" ]]; then
render_template "$tmpl" > "$out"
echo " .claude/rules/${rule}.md"
else
echo "WARNING: template missing: $tmpl"
fi
done
if [[ -f "$CLAUDE_MD" ]]; then
echo ""
echo "==> CLAUDE.md already exists — appending @-import suggestion."
cat >> "$CLAUDE_MD" << 'SUGGESTION'
<!-- ── Custodian State Hub Integration (added by register_project.sh) ──────
The rule files in .claude/rules/ contain the full integration content.
@@ -172,20 +210,21 @@ if [[ "$ADDITIONAL" != "--additional" ]]; then
@.claude/rules/repo-boundary.md
-->
SUGGESTION
echo " Suggestion appended to existing CLAUDE.md."
else
echo "==> Writing CLAUDE.md ..."
render_template "$RULES_TEMPLATES_DIR/claude-md.template" > "$CLAUDE_MD"
echo " CLAUDE.md written."
fi
echo " Suggestion appended to existing CLAUDE.md."
else
echo "==> Writing CLAUDE.md ..."
render_template "$RULES_TEMPLATES_DIR/claude-md.template" > "$CLAUDE_MD"
echo " CLAUDE.md written."
fi
echo ""
echo "Rule files needing manual content:"
echo " .claude/rules/repo-identity.md — update purpose description"
echo " .claude/rules/stack-and-commands.md — language, deps, dev commands"
echo " .claude/rules/architecture.md — design overview"
echo " .claude/rules/repo-boundary.md — what this repo does NOT own"
echo " .claude/rules/workplan-convention.md — verify WP prefix: $WP_PREFIX"
echo ""
echo "Rule files needing manual content:"
echo " .claude/rules/repo-identity.md — update purpose description"
echo " .claude/rules/stack-and-commands.md — language, deps, dev commands"
echo " .claude/rules/architecture.md — design overview"
echo " .claude/rules/repo-boundary.md — what this repo does NOT own"
echo " .claude/rules/workplan-convention.md — verify WP prefix: $WP_PREFIX"
fi
fi
# ── Step 6: Register repo in State Hub ────────────────────────────────────────
@@ -246,18 +285,26 @@ echo " Event recorded."
echo ""
echo "Registration complete!"
echo " Project: $PROJECT_NAME"
echo " Domain: $DOMAIN"
echo " Repo slug: $REPO_SLUG"
[[ "$TOPIC_ID" != "(none)" ]] && echo " Topic ID: $TOPIC_ID"
echo " WP prefix: $WP_PREFIX (update .claude/rules/workplan-convention.md if wrong)"
echo " Project: $PROJECT_NAME"
echo " Domain: $DOMAIN"
echo " Repo slug: $REPO_SLUG"
[[ "$TOPIC_ID" != "(none)" ]] && echo " Topic ID: $TOPIC_ID"
echo " WP prefix: $WP_PREFIX"
echo " Agent mode: $([[ "$CODEX_MODE" == "true" ]] && echo "codex (AGENTS.md)" || echo "claude (CLAUDE.md + .claude/rules/)")"
echo ""
echo "Next steps:"
echo " 1. Fill in TODO stubs in .claude/rules/"
echo " 2. Restart Claude Code for the MCP server to be available in this project"
if [[ "$CODEX_MODE" == "true" ]]; then
echo "Next steps:"
echo " 1. Fill in purpose description in AGENTS.md"
echo " 2. Fill in stack and build commands in AGENTS.md"
echo " 3. Write workplan files, then run: make fix-consistency REPO=$REPO_SLUG"
else
echo "Next steps:"
echo " 1. Fill in TODO stubs in .claude/rules/"
echo " 2. Restart Claude Code for the MCP server to be available in this project"
fi
# ── Optional: SBOM ingest ─────────────────────────────────────────────────────
if [[ "$ADDITIONAL" != "--additional" ]]; then
if [[ "$ADDITIONAL" != "true" ]]; then
echo ""
read -r -p "==> Run SBOM ingest now? [y/N] " INGEST_NOW </dev/tty || INGEST_NOW="N"
if [[ "$INGEST_NOW" =~ ^[Yy]$ ]]; then