# SSSF starter recipes. Stamped by install.py, then yours to edit. # # Deliberately small. These are the handful you need on day one: run something, # watch it, and open the trace. Add your own as your chains grow, and see the # example branch for the fuller set (orchestrator agents, kill, rosters, ipi). # `.env` reaches every ADW through this, so keys work without exporting them. set dotenv-load set positional-arguments # Every recipe passes this through, so `SSSF_CONFIG=other.yaml just sdlc "..."` # swaps the whole roster for one run. config := env_var_or_default("SSSF_CONFIG", "adws/adw_sssf_config/sssf.config.yaml") db := "adws/adw_data/sssf.db" # Where the sssf skill lives — the visualizer app ships with it. install.py # stamps the real path here at install time; edit it if you move the skill. skill_dir := "@SSSF_SKILL_DIR@" # list every recipe default: @just --list # ── first run ─────────────────────────────────────────────────────────────── # Proves the whole path works: config validated, session minted, agent ran, # envelope parsed, gates checked, trace written. Costs a few cents and changes # nothing in your repo, because both workflows are read-only. # # (`just --list` shows only the LAST comment line, so that one is the summary.) # start here: two cheap read-only runs, end to end demo: @echo "1/2 adw_prompt: one agent, one prompt" uv run adws/adw_prompt.py --config {{config}} --agent scout "reply with a one-line summary of this repo" @echo "\n2/2 adw_scout: read-only recon" uv run adws/adw_scout.py --config {{config}} "list the top-level directories in this repo and what each is for. change nothing." @echo "\nboth done. now run: just sessions (or: just obs)" # check the roster without running anything: names, prompts, models all resolve validate: uv run adws/adw_validate.py --config {{config}} # ── run a workflow ────────────────────────────────────────────────────────── # Args pass straight through: "" [--adw-id X] # one agent, one prompt: just prompt "summarize this repo" prompt *ARGS: uv run adws/adw_prompt.py --config {{config}} "$@" # read-only recon: just scout "where is auth handled" scout *ARGS: uv run adws/adw_scout.py --config {{config}} "$@" # plan only: just plan "add a /health endpoint" plan *ARGS: uv run adws/adw_plan.py --config {{config}} "$@" # planner, builder, commit: just plan-build "add a /health endpoint" plan-build *ARGS: uv run adws/adw_plan_build.py --config {{config}} "$@" # plan, build, test, commit: just sdlc "add a /health endpoint" sdlc *ARGS: uv run adws/adw_plan_build_test.py --config {{config}} "$@" # the full chain, plus review and docs: just simple-sdlc "add a /health endpoint" simple-sdlc *ARGS: uv run adws/adw_simple_sdlc.py --config {{config}} "$@" # ── watch it ──────────────────────────────────────────────────────────────── # Reads never block a running workflow, the db is WAL. Poll as hard as you like. # the last 10 runs sessions: @sqlite3 {{db}} "select adw_id, status, substr(request,1,50), total_tokens, round(total_cost,4) from sessions order by started_at desc limit 10;" # phase status in sequence: just phases phases ADW_ID: @sqlite3 {{db}} "select seq, name, kind, owner, status, attempt from phases where adw_id='{{ADW_ID}}' order by seq;" # the live event tail: just tail tail ADW_ID: @sqlite3 {{db}} "select rowid, type, name, started_at from events where adw_id='{{ADW_ID}}' order by rowid desc limit 25;" # what a run has alive right now, with pids: just procs procs ADW_ID: @sqlite3 {{db}} "select kind, name, pid, command, started_at from processes where adw_id='{{ADW_ID}}' and ended_at is null order by id;" # ── observability UI ──────────────────────────────────────────────────────── # Needs bun. The db path is passed explicitly because the server runs from the # app dir and would otherwise look for a trace db sitting next to itself. # boot the trace UI, http://localhost:4601 (api on :4600) obs: cd {{skill_dir}}/apps/visualizer && bun install && (SSSF_DB={{justfile_directory()}}/{{db}} bun run server/index.ts &) && bunx vite