Port the sssf skill from ~/.agents/skills/sssf into this repo so it can be distributed and installed with the skills CLI (skills add INDigitalStudio/skills --skill sssf). - Copy the skill (SKILL.md, cookbooks, references, scripts, templates, and the visualizer app source) into sssf/. - Gitignore build/runtime artifacts: the visualizer's node_modules/ and dist/, Python bytecode, and the machine-specific repos.json. - Make the skill location-independent: install.py now stamps the skill's real path into the stamped justfile's skill_dir (replacing the hardcoded ~/.agents/skills/sssf), so 'just obs' finds the visualizer wherever the CLI installed the skill. - Update cookbooks to use <skill>/scripts/... instead of the hardcoded path, and document the skills CLI install command. - Update the repo README with install instructions.
5.6 KiB
Update Config
Add or retune agents in sssf.config.yaml.
Retune model or thinking
Edit the agent's entry in place:
- name: builder
model: google/gemini-3.6-flash # ALWAYS provider/model-id
thinking: high # was medium
Write the model as provider/model-id, never a bare id. The same model is usually carried by several providers, and an ambiguous pattern raises in agents.validate() — grounding every agent that inherits it. See references/config.md.
Thinking levels are Pi's reasoning effort: off | minimal | low | medium | high | xhigh | max. It only bites when the model is registered with reasoning: true in ~/.pi/agent/models.json.
A model change means a fresh session. agent_map.json records the model each coding-agent session was created with. When a joined run (--adw-id) finds the config's model no longer matches the recorded one, that agent starts a new session rather than resuming — the map is updated, never a bad resume. Thinking changes do not invalidate a session; model changes do. Expect the agent to lose its accumulated context window on the first run after the change.
Recolor an agent's lane
- name: builder
color: "#22d3ee" # hex; the starter roster ships violet/cyan/amber/green
Purely cosmetic and safe to change mid-project: the color rides the agent_start event and the agent_sessions row, so the visualizer picks it up on the next run without touching past sessions. Omit the key to let the UI's fallback palette choose.
Retune tools
Pi's seven builtins: read, bash, edit, write, grep, find, ls. The last three are off in bare Pi, so an agent that doesn't name them will shell out through bash to search and list.
Set the roster-wide floor in defaults, then narrow per agent:
defaults:
tools: [read, bash, edit, write, grep, find, ls]
agents:
- name: reviewer
tools: # explicit list wins over defaults
- read
- grep
- find
- ls
- bash
- write
Resolution: the agent's own list wins → else it inherits defaults.tools → else None, meaning all tools. An empty list is not "all tools"; it is a tool-less agent, and it will stall.
Narrow by role, not by reflex:
- Any agent that must produce a
context_handoff/artifact needswrite— without it, it falls back to abashheredoc to create the file the gate checks for. - Withhold
edit/writeonly where the restriction is the guarantee. The reviewer's contract is "change nothing", so withholdingeditmakes that structural instead of merely prompted. - Recon agents should get the full read surface (
read,grep,find,ls) — cheaper and more legible in the trace than the equivalentbashcalls.
Extension tools count against the allowlist. --tools filters built-in, extension, and custom tools alike. Once an agent has a tools list — its own, or inherited from defaults — a tool registered by one of its harness_engineering extensions is dropped unless it is named there. Nothing errors: the extension loads, the run passes, the tool is just never offered. Any agent with a tool-registering extension must list that tool by name.
Add harness extensions
harness_engineering:
- .pi/extensions/json_guard.ts # a pi extension FILE PATH
Entries are pi extension file paths, passed through as pi -e <path>, applied to that agent only. Reach for an output-tightening extension when an agent keeps wrapping its envelope in prose and burning correction retries. The starter roster ships with none — this is an escape hatch, not a default.
Adding a tool-registering extension is a two-part edit. The extension path goes in harness_engineering, and the tool name it registers goes in that agent's tools list:
- name: reviewer
harness_engineering:
- .pi/extensions/ast_query.ts # registers tool: ast_query
tools:
- read
- grep
- find
- ls
- bash
- ast_query # REQUIRED — or the extension loads and its tool is filtered out
Skip the second half and it fails silently: extension loaded, run green, tool never available to the model. Extensions that only shape output or register flags — no new tool — need no tools change.
Add a new agent
Three steps, all required — skipping any one fails agents.validate() at ADW startup, before anything spawns:
- Prompts. Create
adws/adw_data/prompt_engineering/{name}/system.md(Purpose + Instructions — the agent's static identity, nothing else) anduser.md(an h3 per incoming datum:{{prompt}},{{previous_envelope}},{{context_handoff_dir}}, then the task, then a## Reportsection showing the exact output JSON). Copy an existing pair as the shape. - Config entry. Name, purpose, prompt refs, plus anything that differs from
defaults. - An output type. Every agent call parses against a concrete Pydantic model in
adw_modules/data_types.py. If none ofPlanOutput,BuildOutput,ScoutOutput,ReviewOutput,DocumentOutputfits the new agent's report, add one — seeupdate_modules.md. The user prompt'sReportsection must show exactly that JSON shape.
Then name the agent in an ADW's REQUIRED_AGENTS and call it.
Rules that do not bend
- ADW scripts name agents, never models. Swapping a model is a config edit and touches no Python.
- One agent, one prompt, one purpose. If an entry needs two purposes, it is two agents.
- Output types never appear in config — they live at the call site, paired with the user prompt.
Full spec: references/config.md.