Make review crew slot-based (arbitrary workers, incl. duplicate agent+model) · Entire
Make review crew slot-based (arbitrary workers, incl. duplicate agent+model)
1481e83→main·
dipree·1mo ago·3 files·+251 added/-75 removed
Reframe crew configuration around worker slots rather than "per agent". A slot is an agent + model; you can define any number, including the same agent multiple times on different OR identical models (e.g. 5 Claude slots). The data model already supported this (profile.Agents is keyed by an arbitrary worker name, disambiguated by workerIDForAgentModel) — this change updates the two config surfaces that were still agent-keyed.
Picker: replace the per-agent model grid with a slot list — seeded with one default-model slot per launchable agent, then add/remove/duplicate slots (each add = pick agent → pick model/Default/Custom).
Scripted: add repeatable --set-slot agent[=model]. --set-agents
stays as the one-default-slot-per-agent shorthand (keeps --set-model
targeting). Duplicate slots are allowed and become distinct workers.
Sessions
Changes
3
cmd/entire/cli/review
Mcmd.go+30/-5
Mconfigure_test.go+30
Mpicker.go+191/-70
var setMaster string
var setTask string
var setModels []string
var setSlots []string
cmd := &cobra.Command{
Use: "review",
--set-master with --configure: master agent that writes the final report
--set-task with --configure: the profile's canonical task text
--set-model with --configure: per-worker model as agent=model (repeatable)
--set-slot with --configure: a worker slot as agent[=model] (repeatable;
the same agent/model may repeat to run it multiple times)
--edit re-open the advanced review profile skill picker
--findings browse local review findings
--agent NAME run only one worker from the selected profile
}
Test Cases
TestBuildConfiguredProfile_FromSlots_AllowsDuplicateAgents
func TestBuildConfiguredProfile_FromSlots_AllowsDuplicateAgents(t *testing.T) {
deps := configureTestDeps("claude-code", "codex")
profile, err := buildConfiguredProfile(
context.Background(),
"general",
reviewConfigureOptions{
Slots: []string{"claude-code=opus", "claude-code=sonnet", "claude-code", "claude-code"},
},
&settings.EntireSettings{},
deps,
)
if err != nil {
t.Fatalf("buildConfiguredProfile: %v", err)
}
// Four distinct workers: two different models + two identical default slots.
if len(profile.Agents) != 4 {
t.Fatalf("agents = %d, want 4: %#v", len(profile.Agents), profile.Agents)
}
models := map[string]int{}
for _, cfg := range profile.Agents {
if cfg.Agent != "claude-code" {
t.Errorf("worker agent = %q, want claude-code", cfg.Agent)
}
models[cfg.Model]++
}
if models["opus"] != 1 || models["sonnet"] != 1 || models[""] != 2 {
t.Errorf("model distribution = %#v, want opus:1 sonnet:1 default:2", models)
}
}
Building the Crew Profile
func buildCrewProfile(ctx context.Context, profileName string, slots []crewSlot) settings.ReviewProfileConfig {
profile := settings.ReviewProfileConfig{
Task: profileTask(profileName, settings.ReviewProfileConfig{}),
Agents: map[string]settings.ReviewConfig{},
Agents: make(map[string]settings.ReviewConfig, len(slots)),
}
for _, s := range slots {
cfg := defaultReviewAgentConfig(profileName, s.agent)
// Set Agent explicitly so the worker is valid even when the agent has no default skills/prompt.
cfg.Agent = s.agent
cfg.Model = s.model
profile.Agents[workerIDForAgentModel(s.agent, s.model, profile.Agents)] = cfg
}
return profile
}