#!/usr/bin/env bash # create-project.sh — scaffold a NEW project that uses a harness. # # Produces a self-contained project repo: the chosen harness vendored as the `engine/` submodule at # a pinned ref, plus a harness config scaffolded by the harness's own `init`. The project contains # NO project-orchestrator / fleet metadata — knowledge is one-directional (PO → project). Registering # the project in the PO's fleet.toml is a SEPARATE, PO-side step (use --register, or edit fleet.toml # by hand); nothing about the fleet ever lands inside the project repo. # # Usage: # scripts/create-project.sh [options] # # Options: # --dir parent directory to create the project under (default: ./projects) # --engine-url harness repo to vendor as engine/ (default: the agent-orchestrator repo) # --ref harness ref to pin the submodule at (default: v0.1.0) # --prefix session_prefix to write into the project's config (default: -) # --register also append a [[project]] entry to this PO's fleet.toml (PO-side only) # --no-commit leave the project tree uncommitted (default: make an initial commit) # # Drive it by hand afterwards, exactly like any project: # cd / && python3 engine/agents.py status set -euo pipefail die() { echo "create-project: $*" >&2; exit 1; } [ $# -ge 1 ] || die "usage: create-project.sh [--dir P] [--engine-url U] [--ref R] [--prefix X] [--register] [--no-commit]" NAME="$1"; shift [[ "$NAME" =~ ^[a-z0-9][a-z0-9-]*$ ]] || die "name must be kebab-case (got: $NAME)" PO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" PARENT="$PO_ROOT/projects" ENGINE_URL="https://git.autonomic.zone/recipe-maintainers/agent-orchestrator.git" REF="v0.1.0" PREFIX="" REGISTER=0 COMMIT=1 while [ $# -gt 0 ]; do case "$1" in --dir) PARENT="$2"; shift 2;; --engine-url) ENGINE_URL="$2"; shift 2;; --ref) REF="$2"; shift 2;; --prefix) PREFIX="$2"; shift 2;; --register) REGISTER=1; shift;; --no-commit) COMMIT=0; shift;; *) die "unknown option: $1";; esac done PREFIX="${PREFIX:-${NAME}-}" command -v git >/dev/null || die "git not on PATH" command -v python3 >/dev/null || die "python3 not on PATH" DEST="$PARENT/$NAME" [ -e "$DEST" ] && die "$DEST already exists — refusing to overwrite" mkdir -p "$PARENT" echo "create-project: scaffolding '$NAME' at $DEST (engine $ENGINE_URL @ $REF)" git init -q -b main "$DEST" cd "$DEST" # 1) vendor the harness as a pinned submodule under engine/ git -c protocol.version=2 submodule add -q "$ENGINE_URL" engine ( cd engine && git fetch -q --tags origin && git checkout -q "$REF" ) git add .gitmodules engine # 2) scaffold the harness config + prompts via the harness's OWN init (no PO/fleet metadata) python3 engine/agents.py init . >/dev/null # stamp the chosen session_prefix into the scaffolded config (keeps namespaces unique per project) python3 - "$PREFIX" <<'PY' import re, sys, pathlib prefix = sys.argv[1] p = pathlib.Path("agents.toml") txt = p.read_text() txt = re.sub(r'session_prefix\s*=\s*"[^"]*"', f'session_prefix = "{prefix}"', txt, count=1) p.write_text(txt) PY # 3) ignore runtime state; the project knows nothing about any PO cat > .gitignore <<'EOF' # runtime state + logs (never committed) .ao-state/ *.log __pycache__/ *.pyc result EOF git add agents.toml prompts .gitignore 2>/dev/null || true if [ "$COMMIT" -eq 1 ]; then git -c user.name="project-orchestrator" -c user.email="po@localhost" \ commit -q -m "init: scaffold $NAME (engine @ $REF)" fi echo "create-project: done — $DEST" echo " engine pinned at: $(cd engine && git rev-parse HEAD) ($REF)" echo " config: agents.toml (session_prefix = $PREFIX)" echo " verify it: ( cd $DEST && python3 engine/agents.py status )" if [ "$REGISTER" -eq 1 ]; then echo "create-project: registering '$NAME' in $PO_ROOT/fleet.toml" cat >> "$PO_ROOT/fleet.toml" <