feat: extract reforge engine into a standalone consumable flake
The forgejo-sandbox / reforge harness, lifted out of the machine config into a host-agnostic, generic engine anyone can consume with Nix. Two layers: - engine (this repo) — nixosModules.reforge stands up the sandbox forge, provisions role accounts + tokens, enforces branch protection, and puts the reforge-* CLI + forgejo-mcp on PATH. Carries no project specifics. - run config — per-project manifest/charter/agenda/issues an adopter fills in; scaffold one with the `reforge` flake template. Portability fixes vs the in-config version: - forgejo-mcp resolved from $REFORGE_MCP_BIN or PATH, never a named host (kills the nixosConfigurations.omni hardcode). - all instance data + paths parameterized via REFORGE_* env, baked into the reforge-scripts wrappers from module options (configDir, agentsDir, refsDir, org, port, tokenOwner, ...). - option namespace neutral (reforge.* not omni.packs.*); settings policies carry no absolute /etc/nixos paths. - role briefs + orchestrator playbook genericized: all project specifics point at the charter; refs corpus optional. Validated: nix flake check (eval) + builds of forgejo-mcp, reforge-scripts, and a module-eval check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
df0fd9a9ba
32 changed files with 2698 additions and 0 deletions
91
scripts/reforge-role.sh
Normal file
91
scripts/reforge-role.sh
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env bash
|
||||
# Launch an agent session as a reforge role (docs/reforge.md,
|
||||
# docs/architecture.md). One terminal per role.
|
||||
#
|
||||
# reforge-role <role> [agent args...]
|
||||
#
|
||||
# Prepares $REFORGE_TEAM_DIR/<role>/ as the session workdir, fresh on every
|
||||
# launch (policy and briefs come from the engine / your config — hand-edits
|
||||
# to the runtime copies are overwritten):
|
||||
#
|
||||
# .claude/settings.json <- $REFORGE_SETTINGS_DIR/role-settings.json
|
||||
# .mcp.json forge MCP wired to the ROLE's token — same server
|
||||
# name as any admin-scope instance, so the role
|
||||
# token SHADOWS admin in this dir
|
||||
# CLAUDE.md role brief <- $REFORGE_AGENTS_DIR/{common,<role>}.md
|
||||
#
|
||||
# Isolation is best-effort (same unix user): the policy denies the obvious
|
||||
# escapes (ssh, git remotes, non-localhost clones/pushes, curl, other MCP
|
||||
# servers) and GIT_SSH_COMMAND=false blocks git's internal ssh — but this is
|
||||
# a discipline boundary, not a security one.
|
||||
set -euo pipefail
|
||||
|
||||
FORGE_URL=${REFORGE_FORGE_URL:-http://localhost:3030}
|
||||
ORG=${REFORGE_ORG:-sandbox-team}
|
||||
TOKENS_DIR=${REFORGE_TOKENS_DIR:-/var/lib/forgejo-sandbox/tokens}
|
||||
AGENTS_DIR=${REFORGE_AGENTS_DIR:?set REFORGE_AGENTS_DIR to the agent briefs dir}
|
||||
SETTINGS_DIR=${REFORGE_SETTINGS_DIR:?set REFORGE_SETTINGS_DIR to the permission-policy dir}
|
||||
TEAM_DIR=${REFORGE_TEAM_DIR:-$HOME/sandbox-team}
|
||||
AGENT_CMD=${REFORGE_AGENT_CMD:-claude}
|
||||
|
||||
usage() {
|
||||
echo "usage: reforge-role <role> [agent args...]" >&2
|
||||
echo -n "roles:" >&2
|
||||
for f in "$AGENTS_DIR"/*.md; do
|
||||
b=$(basename "$f" .md)
|
||||
case $b in common | orchestrator) ;; *) echo -n " $b" >&2 ;; esac
|
||||
done
|
||||
echo >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
ROLE=${1:-}
|
||||
[ -n "$ROLE" ] || usage
|
||||
shift
|
||||
BRIEF="$AGENTS_DIR/$ROLE.md"
|
||||
case $ROLE in common | orchestrator) usage ;; esac
|
||||
[ -f "$BRIEF" ] || usage
|
||||
|
||||
TOKEN_FILE="$TOKENS_DIR/$ROLE.token"
|
||||
if [ ! -r "$TOKEN_FILE" ]; then
|
||||
echo "reforge-role: no readable token at $TOKEN_FILE — is the sandbox provisioned (and does the role exist)?" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# forgejo-mcp binary: explicit override, else whatever is on PATH (the
|
||||
# NixOS module installs it). No named-host / flake resolution.
|
||||
MCP_BIN=${REFORGE_MCP_BIN:-$(command -v forgejo-mcp || true)}
|
||||
if [ -z "$MCP_BIN" ]; then
|
||||
echo "reforge-role: no forgejo-mcp — set REFORGE_MCP_BIN or put forgejo-mcp on PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WORKDIR="$TEAM_DIR/$ROLE"
|
||||
mkdir -p "$WORKDIR/.claude"
|
||||
|
||||
cp "$SETTINGS_DIR/role-settings.json" "$WORKDIR/.claude/settings.json"
|
||||
sed -e "s|@ROLE@|$ROLE|g" \
|
||||
-e "s|@FORGE_URL@|$FORGE_URL|g" \
|
||||
-e "s|@FORGE_HOST@|${FORGE_URL#*://}|g" \
|
||||
-e "s|@ORG@|$ORG|g" \
|
||||
-e "s|@TOKENS_DIR@|$TOKENS_DIR|g" \
|
||||
"$AGENTS_DIR/common.md" "$BRIEF" >"$WORKDIR/CLAUDE.md"
|
||||
|
||||
cat >"$WORKDIR/.mcp.json" <<EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"forgejo-sandbox": {
|
||||
"type": "stdio",
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"-c",
|
||||
"FORGEJO_ACCESS_TOKEN=\$(cat $TOKEN_FILE) FORGEJO_URL=$FORGE_URL exec $MCP_BIN --transport stdio"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "→ launching $ROLE session in $WORKDIR"
|
||||
cd "$WORKDIR"
|
||||
exec "$AGENT_CMD" "$@"
|
||||
Loading…
Add table
Add a link
Reference in a new issue