Skip to content

feat: per-step agents, subagents, teams, skills and MCP tools - #88

Merged
jflavan merged 65 commits into
mainfrom
feat/agent-setup
Oct 27, 2026
Merged

jflavan merged 65 commits into
mainfrom
feat/agent-setup

Conversation

@jflavan

@jflavan jflavan commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Lets each loop step (and chat's orchestrator and write-intent) choose its agent, subagents, teams of subagents, skills, tools and MCP tools. Setup, the console and the operator skill can all edit these settings. With no agents block, sessions start exactly as before, and tests pin that. Includes feat/mcp-tools (mcp_tools in every tool set, with MCP tools chosen during onboarding) and a merge of #87.

Spec: docs/superpowers/specs/2026-10-26-agent-setup-design.md. Plans 1–4 are in docs/superpowers/plans/, and the decisions are in docs/decisions.md.

Runtime

  • New top-level agents block, with all plus one entry per step:

    • agent, subagents and teams (named groups run parallel or by pick);
    • skills, tools and mcp_tools;
    • sources: repo, which loads only what the repo declares.

    claude.mcp_tools moved to agents.all.mcp_tools.

  • Enforced rules:

    • Read-only steps never get write tools.
    • No step gets git rules that commit, push or switch branches.
    • Fix, reconcile and revise run as the build's agent.
    • Built-in agents (Explore, Plan, …) can only be subagents.
  • Repo agent definitions are read from main's commit, so a change can't rewrite the agent that judges it. Writers given --add-dir get deny rules for that snapshot.

  • When a session starts, its init is checked against the setup. A missing agent or skill stops the step with a setup failure that says what's missing. loopstra start refuses while a step names an agent that doesn't exist.

Setup

  • loopstra setup agents sets each step's agents, subagents, teams, skills and tools. It adds skills and agents from this machine, a plugin, a git repository or folder, or a short form:
    • Copies never follow links or escape the target.
    • .git is never copied.
    • Credentials are stripped from shown URLs.
    • ssh runs in batch mode unless you configured your own.
  • The operator skill now has steps for choosing MCP tools and setting up agents.

Console

  • Settings has an Agents section that edits the same values and shows where each one comes from (step, all or default). It can also copy, fetch, create, edit and remove agent and skill files.

  • The console never writes the repo. The loop applies each agent-files request and commits it. A change is refused if:

    • the target has uncommitted, staged or untracked work;
    • the target is a link;
    • the file changed since the page read it.

    Request text can't carry control characters, so it can't forge a trailer.

  • The session page shows what a step ran as. Each subagent's work is nested under the call that started it, and a subagent's prompt is never shown as a person's message.

Verified with the real CLI (2.1.311)

  • Inline --agents with --agent keeps structured output only when the agent's tools include StructuredOutput.
  • --disallowedTools also binds subagents.
  • --setting-sources project keeps --settings hooks.
  • Subagent events carry parent_tool_use_id.

Live runs: an intake ran as an inline agent, and a change went to done with build running as a custom agent. The fix sessions kept the build's session.

Known and not addressed here

A build session can still influence later sessions of the same step through its change's .claude/skills, .claude/settings.json, CLAUDE.md or Bash. This predates the PR. Agent definitions are protected; closing the rest needs a tighter setup for judges.

Verification

bun run check passes: typecheck, lint and deadcode are clean, and 1836 tests pass. Each task was reviewed, and each of the four parts had a final review and a re-review after its fixes. Browser checks covered phone and desktop widths, light and dark.

🤖 Generated with Claude Code

jflavan and others added 30 commits October 26, 2026 22:07
…arding

Sessions load the machine's and the repo's MCP servers, but a -p session
cannot ask, so every MCP call was refused outside plan mode. MCP allow
rules in claude.mcp_tools now reach every tool set, judges included.
Entries must be mcp__ rules without commas, since the list reaches the
CLI comma-joined. The operator skill lists the MCP tools its session has
and writes the ones the engineer picks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e agents

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runPhase passes --agents, --agent, --setting-sources, --add-dir and
--forward-subagent-text when set (after the tool lists, before
--settings). checkInit judges the session's first init event that lists
agents or skills; a problem ends the session at once as a "setup"
failure. A stop or a cancel still wins; setup is not an outage and is
not retried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each attempt reads its step's setup fresh (StepContext.models now carries
agents, as it does models). An empty setup passes nothing new, so argv and
prompt stay byte-identical. Otherwise the session gets the setup's tools and
mcp_tools, its agent and every subagent and team member inline from main's
snapshot (--agents, --agent), --setting-sources project plus the user's
apiKeyHelper and env for sources: repo, main's snapshot as --add-dir for a
worktree step with skills, --forward-subagent-text with subagents or teams,
and an init check. A named agent that is not found fails the step with
reason setup before a session starts. The setup is traced as agent_setup on
the phase row; prompts carry setupLines in place of the skills line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts refused

A setup changes how a session runs only when the step's agent settings
give it something; a stage's skills alone are the prompt's first line, as
before (no snapshot, --add-dir or init check). {{commands}} also lists the
Bash rules from the step's setup tools. A built-in agent as a step's (or
all's) agent is a config error: its fixed tools have no StructuredOutput.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mpt unchanged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riters out of the snapshot

A writing session that loads skills gets main's snapshot as an added dir, and --add-dir also lets
it edit there; later phases of the same step read their agent files from that snapshot, so a
revise session could rewrite the reviewer the next review round runs as.

- A loop step's repository agent files are read from the step's commit of main (git cat-file),
  never a checkout. Personal and plugin files are still read from disk; chat still reads the main
  checkout.
- A session given the snapshot as an added dir also gets Edit, Write and NotebookEdit denied under
  it (`//<path>/**`), returned by setupSession as `deny` and added to the loop's own deny list.
- setupSession's run options are typed to what the setup sets (SetupRunOptions), and chat spreads
  them before its own fields, so its allow and deny lists, folder and environment always stand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain's snapshot cannot be made

The agent check ran before the lock, so a second start made and removed a snapshot under the
running loop's .loopstra/snapshots/, and an unresolvable main_branch threw a stack trace. It now
runs once the lock is taken (the lock is let go when it refuses), and a failure making or reading
the snapshot is a refusal that names main_branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It sat inside `claude:` at two spaces, so uncommenting it gave claude.agents, an unknown key. It
is now its own paragraph at column 0 after `stages:`, and a test pins that it is the template's
top-level placeholder and loads once uncommented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
checkAgentSetup repeated build's missing agent for fix, reconcile and revise (which run as build's)
and agents.all's for every step. The agent a step runs as is now checked where it is set: once
under "all" for agents.all's, and not again for the steps that continue the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A non-empty agents or skills list without a single string (a shape Loopstra does not know) was
taken as "present and empty", so every named agent or skill looked missing. It now counts as
absent, like an event without the list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…order mark

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le the plugin

A plugin that is installed but not enabled is not looked in, so its agents and skills read as
missing. With sources: all, the text for a `plugin:name` now says to enable the plugin in Claude
Code (a repo-only setup never loads plugins, so it does not).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art check under the lock

Records that --settings still applies under --setting-sources project (checked live on CLI
2.1.311: a PreToolUse hook passed in --settings ran), so the test-protection hook holds with
sources: repo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (lint)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter regex

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jflavan and others added 23 commits October 27, 2026 00:57
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…line text

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rding

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/agents shows each step's own, inherited and stage agent setup,
the teams, the library with who uses each item, and the setup check's
problems. GET /api/agents/source clones a git repository or folder into
a temporary folder, lists its agents and skills, and removes the folder.
POST /api/agents/files turns copy, fetch, new, edit and remove into an
agent-files request with bases read from the checkout, refusing early
what the loop would refuse (in use, already there, stale, links,
uncommitted files).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A remove, and a copy, fetch or new that replaces, now names the version
of the agent file or SKILL.md the page read; a stale one is refused, and
the request's base takes the page's version (an edit's too) rather than
reading the file again. Files added new are based as absent. Both
settings views share one readConfig; only agents named as Loopstra names
them are editable; AgentField is exported for the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under the models: the agent setup problems (fails first), where steps find
agents and skills, each step's six fields with their effective value and
where it comes from, the teams, and the library (in the repo, on this
machine, from plugins) with add, edit, remove, adding from a git
repository or folder, and a new agent. Every write goes through the
page's one pending change, with Cancel, as the models do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tools and MCP tools inputs showed example rules as placeholders on
every row, which read as configured values. An empty field now shows what
the step gets beside it (the inherited value and where from, or none);
only the All steps row keeps a neutral "comma-separated" hint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…other name or edit it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing needs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nce, where it is set

A name a step gets only through agents.all is checked and reported once under
all, a stage's skills once under stage <name>, and what a step sets itself under
that step: setup --check, start and the console no longer repeat one line per step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… step gets, problems show names as code

Adding from a git repository or folder asks "Replace it?" before it replaces the
repo's items. A list picker's summary is the step's effective list with inherited
names marked. The problems callout shows backticked names as code, as a status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With --forward-subagent-text a subagent's events carry the id of the
Agent/Task call that started it. toItems now marks each of their rows
with that id (parent) and turns the subagent's first event, its prompt,
into a delegated row rather than a person's message. The page nests
those rows under the call: a collapsible "Handing off to <agent>:
<description>" block holding the prompt (closed), the subagent's words
and calls, then the call's result. Rows whose call is not on the page
stay where they are and say they come from a subagent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e chat context names a subagent's prompt

The transcript's one grid column was as wide as its widest row, so a
subagent's summary or prompt line widened every row past a phone's
width. It is now as wide as the box, and long targets ellipsize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s todos out of the session's, label its lines for chat

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/agent-library.ts Fixed
jflavan and others added 4 commits October 27, 2026 14:10
…README

How it works now opens with a diagram of the statuses and gates, and has a
table of every step, a gate diagram and table, the build and review loops,
and where sessions read and write. A new Agents for each step section holds
what the Configuration bullet said, with diagrams of how a step's setup is
built and how subagents and teams are used, and a table of the flags each
setting becomes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL (js/file-system-race): a skill file was checked with lstat and then
read again by its path, so a file swapped for a link in between would be
followed. Each file is now opened once without following links or waiting
on a pipe, and whether it is a plain file, its size, whether it is binary
and its text all come from that open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- --agents and --settings go to the CLI as owner-only files in a temporary
  folder per session, removed when it ends: the user's env and apiKeyHelper
  no longer show in the process list, and a large agent setup no longer
  passes the limit on an argument's length. Checked live on 2.1.311.
- The git rule check sees wildcards (Bash(git c*), Bash(g* push *)) and git
  after env, command, sudo and the like or VAR=value.
- A read-only step refuses every match-all Bash rule (Bash(:*), Bash(**))
  and MultiEdit.
- A subagent's todo list is a row in its block instead of being dropped.
- The agent_setup event records each team's members, and the session's
  facts show them with their models.
- Only a step that names skills makes the snapshot of main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jflavan
jflavan merged commit fe27f4e into main Oct 27, 2026
13 checks passed
@jflavan
jflavan deleted the feat/agent-setup branch October 27, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants