generated from coulomb/repo-seed
W1: Document user-scope MCP config location in ~/.claude/CLAUDE.md —
adds verification and re-registration commands, warns against
settings.json (saves ~12K tokens per registration session).
W2: scripts/register_project.sh + make register-project —
5-step automation: API health → topic lookup → MCP check →
CLAUDE.md from template → progress event.
W3: state-hub/scripts/project_claude_md.template —
parameterised CLAUDE.md with {PROJECT_NAME}/{DOMAIN}/{TOPIC_ID}
placeholders; used by register_project.sh.
W4: Add custodian_topic_id + domain to all 6 canon project charters —
lets agents grep for topic IDs without touching the API.
W5: state-hub/mcp_server/TOOLS.md — compact 30-line tool reference
card; replaces reading the full server.py (~350 lines).
W6: Switch .mcp.json to absolute path + PYTHONPATH env so cwd is not
required; add scripts/patch_mcp_cwd.py for post-registration fix.
Update ~/.claude.json to match (cwd kept for belt-and-suspenders).
W7 (SessionStart hook) deferred: no SessionStart hook type in Claude
Code; PreToolUse with empty matcher fires before every tool call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
5.4 KiB
Bash
Executable File
146 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# register_project.sh — register a new project with the Custodian State Hub
|
||
#
|
||
# Usage: scripts/register_project.sh <domain> <project_path>
|
||
# domain: one of custodian|railiance|markitect|coulomb_social|personhood|foerster_capabilities
|
||
# project_path: absolute path to the project directory
|
||
#
|
||
# Example:
|
||
# scripts/register_project.sh railiance /home/worsch/railiance
|
||
#
|
||
# What it does:
|
||
# 1. Verify the API is reachable
|
||
# 2. Look up the topic ID for the domain
|
||
# 3. Check that state-hub is in ~/.claude.json; warn if missing
|
||
# 4. Write $project_path/CLAUDE.md from the template (skip if exists)
|
||
# 5. POST a progress event recording the registration
|
||
|
||
set -euo pipefail
|
||
|
||
DOMAIN="${1:-}"
|
||
PROJECT_PATH="${2:-}"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
STATE_HUB_DIR="$(dirname "$SCRIPT_DIR")"
|
||
API_BASE="${API_BASE:-http://127.0.0.1:8000}"
|
||
|
||
# ── Validate args ──────────────────────────────────────────────────────────────
|
||
if [[ -z "$DOMAIN" || -z "$PROJECT_PATH" ]]; then
|
||
echo "Usage: $0 <domain> <project_path>"
|
||
echo " domain: custodian|railiance|markitect|coulomb_social|personhood|foerster_capabilities"
|
||
echo " project_path: absolute path to project directory"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -d "$PROJECT_PATH" ]]; then
|
||
echo "ERROR: project_path does not exist: $PROJECT_PATH"
|
||
exit 1
|
||
fi
|
||
|
||
PROJECT_NAME="$(basename "$PROJECT_PATH")"
|
||
|
||
# ── Step 1: API health check ───────────────────────────────────────────────────
|
||
echo "==> Checking API at $API_BASE ..."
|
||
if ! curl -sf "$API_BASE/state/health" > /dev/null; then
|
||
echo "ERROR: State Hub API is not reachable."
|
||
echo " Start it: cd $STATE_HUB_DIR && make api"
|
||
echo " (requires postgres: make db first)"
|
||
exit 1
|
||
fi
|
||
echo " API OK"
|
||
|
||
# ── Step 2: Look up topic ID ───────────────────────────────────────────────────
|
||
echo "==> Looking up topic for domain '$DOMAIN' ..."
|
||
TOPICS_JSON="$(curl -sf "$API_BASE/topics/?status=active")"
|
||
|
||
TOPIC_ID="$(echo "$TOPICS_JSON" | python3 -c "
|
||
import json, sys
|
||
topics = json.load(sys.stdin)
|
||
match = next((t for t in topics if t.get('domain') == sys.argv[1]), None)
|
||
if not match:
|
||
print('NOT_FOUND')
|
||
else:
|
||
print(match['id'])
|
||
" "$DOMAIN")"
|
||
|
||
if [[ "$TOPIC_ID" == "NOT_FOUND" ]]; then
|
||
echo "ERROR: No active topic found for domain '$DOMAIN'."
|
||
echo " Known domains: custodian railiance markitect coulomb_social personhood foerster_capabilities"
|
||
exit 1
|
||
fi
|
||
echo " topic_id: $TOPIC_ID"
|
||
|
||
# ── Step 3: Check MCP registration ────────────────────────────────────────────
|
||
echo "==> Checking MCP server registration ..."
|
||
MCP_OK="$(python3 -c "
|
||
import json
|
||
from pathlib import Path
|
||
f = Path.home() / '.claude.json'
|
||
if not f.exists():
|
||
print('MISSING_FILE')
|
||
else:
|
||
d = json.loads(f.read_text())
|
||
servers = d.get('mcpServers', {})
|
||
print('OK' if 'state-hub' in servers else 'NOT_REGISTERED')
|
||
")"
|
||
|
||
if [[ "$MCP_OK" == "MISSING_FILE" ]]; then
|
||
echo "WARNING: ~/.claude.json not found. MCP server is not registered."
|
||
echo " To register:"
|
||
echo " MСPCFG=\$(cat $STATE_HUB_DIR/../.mcp.json | python3 -c \"import json,sys; print(json.dumps(json.load(sys.stdin)['mcpServers']['state-hub']))\")"
|
||
echo " claude mcp add-json -s user state-hub \"\$MCPCFG\""
|
||
echo " python3 $SCRIPT_DIR/patch_mcp_cwd.py"
|
||
elif [[ "$MCP_OK" == "NOT_REGISTERED" ]]; then
|
||
echo "WARNING: 'state-hub' not found in ~/.claude.json."
|
||
echo " To register, see CLAUDE.md MCP Server Registration section."
|
||
else
|
||
echo " MCP OK"
|
||
fi
|
||
|
||
# ── Step 4: Write CLAUDE.md ────────────────────────────────────────────────────
|
||
CLAUDE_MD="$PROJECT_PATH/CLAUDE.md"
|
||
TEMPLATE="$SCRIPT_DIR/project_claude_md.template"
|
||
|
||
if [[ -f "$CLAUDE_MD" ]]; then
|
||
echo "==> CLAUDE.md already exists at $CLAUDE_MD — skipping."
|
||
else
|
||
echo "==> Writing CLAUDE.md to $CLAUDE_MD ..."
|
||
sed \
|
||
-e "s|{PROJECT_NAME}|$PROJECT_NAME|g" \
|
||
-e "s|{DOMAIN}|$DOMAIN|g" \
|
||
-e "s|{TOPIC_ID}|$TOPIC_ID|g" \
|
||
"$TEMPLATE" > "$CLAUDE_MD"
|
||
echo " Written."
|
||
fi
|
||
|
||
# ── Step 5: Record progress event ─────────────────────────────────────────────
|
||
echo "==> Recording registration event ..."
|
||
EVENT_JSON="$(python3 -c "
|
||
import json
|
||
payload = {
|
||
'topic_id': '$TOPIC_ID',
|
||
'event_type': 'milestone',
|
||
'summary': 'Project registered with State Hub: $PROJECT_NAME ($DOMAIN)',
|
||
'author': 'custodian',
|
||
'detail': {
|
||
'project_path': '$PROJECT_PATH',
|
||
'claude_md': '$CLAUDE_MD',
|
||
'domain': '$DOMAIN',
|
||
},
|
||
}
|
||
print(json.dumps(payload))
|
||
")"
|
||
|
||
curl -sf -X POST "$API_BASE/progress/" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$EVENT_JSON" > /dev/null
|
||
|
||
echo " Event recorded."
|
||
echo ""
|
||
echo "Registration complete!"
|
||
echo " Project: $PROJECT_NAME"
|
||
echo " Domain: $DOMAIN"
|
||
echo " Topic ID: $TOPIC_ID"
|
||
echo " CLAUDE.md: $CLAUDE_MD"
|
||
echo ""
|
||
echo "Next: restart Claude Code for the MCP server to be available in this project."
|