Add built-in squads skill

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Naiyuan Qing
2026-06-02 19:05:22 +08:00
parent 923d895a39
commit 8fea549eaf
3 changed files with 475 additions and 0 deletions

View File

@@ -0,0 +1,247 @@
---
name: multica-squads
description: Use when creating, inspecting, updating, assigning, mentioning, or debugging Multica squads. Explains what squads are, squad/member fields, CLI commands, leader routing, issue assignment, comments, mentions, autopilot behavior, leader briefing, side effects, and product-gap handling.
user-invocable: false
allowed-tools: Bash(multica *)
---
# Multica Squads
## Quick start
If debugging why a squad did or did not run, inspect first:
```bash
multica issue get <issue-id> --output json
multica squad get <squad-id> --output json
multica squad member list <squad-id> --output json
multica issue comment list <issue-id> --recent 20 --output json
```
If the command shape is unclear, check help instead of guessing:
```bash
multica squad --help
multica squad member --help
multica issue update --help
multica issue comment add --help
```
Do not assign, comment, mention, update, delete, or record squad activity just
to test. These can mutate workspace state or trigger agent runs.
## Core model
A Multica squad is a workspace routing and coordination object.
A squad is not an agent. It does not run work by itself. Current behavior:
squad-routed work runs through the squad's `leader_id` agent.
Important consequences:
- assigning an issue to a squad routes to the leader;
- mentioning a squad routes to the leader;
- squad-assigned autopilot resolves to the leader;
- squad members are not automatically fanned out;
- squad `instructions` are leader briefing content, not member prompts.
## CLI
Squad commands:
```bash
multica squad list --output json
multica squad get <squad-id> --output json
multica squad create --name <name> --leader <agent-name-or-id> --output json
multica squad update <squad-id> --instructions "<leader coordination policy>" --output json
multica squad delete <squad-id>
```
Member commands:
```bash
multica squad member list <squad-id> --output json
multica squad member add <squad-id> --member-id <id> --type agent|member --role <role> --output json
multica squad member remove <squad-id> --member-id <id> --type agent|member
multica squad member set-role <squad-id> --member-id <id> --member-type agent|member --role <role> --output json
```
Squad leader evaluation command:
```bash
multica squad activity <issue-id> action|no_action|failed --reason "<why>" --output json
```
`activity` is a write: it records the leader's evaluation decision on an issue.
Use it only when acting as the squad leader after evaluating a trigger.
Issue/comment commands often needed with squads:
```bash
multica issue get <issue-id> --output json
multica issue update <issue-id> --help
multica issue comment list <issue-id> --output json
multica issue comment add <issue-id> --help
```
Prefer `--output json` for reads. Use `--help` before writes.
## Squad fields
- `id` — squad UUID.
- `workspace_id` — workspace the squad belongs to.
- `name` — display name; unique per workspace.
- `description` — human-facing metadata/display text. Do not assume runtime
prompt impact unless source proves a consumer.
- `instructions` — squad-level instructions added to the squad leader briefing.
They are not directly injected into every squad member.
- `avatar_url` — optional squad avatar URL.
- `leader_id` — agent ID of the squad leader; the runtime target for
squad-routed work.
- `creator_id` — creator of the squad.
- `archived_at` / `archived_by` — archive metadata. Archived squads are rejected
by assignment/autopilot routing paths.
- `member_count` — list response count of squad members.
- `member_preview` — list response preview of squad members.
Use `instructions` for leader-facing coordination policy: squad responsibility,
delegation expectations, when to ask humans, and review/handoff rules. Do not
write it as if every member automatically receives it.
## Squad member fields
- `member_type``agent` or `member`.
- `member_id` — ID of the agent or workspace member.
- `role` — roster role label. Current behavior: non-empty `role` appears in the
leader briefing roster. Do not assume it creates scheduling, permissions, or
routing behavior.
## Creation and leader membership
Creating a squad requires `leader_id`. The leader must be a workspace agent and
cannot be archived.
On create, the backend attempts to add the leader as a squad member with role
`leader`. When updating `leader_id`, if the new leader is not already a member,
the backend adds the new leader as a squad member with role `leader`.
## Leader briefing
For squad leader tasks, Multica appends a squad leader briefing to the leader
agent instructions. The briefing includes:
- Squad Operating Protocol;
- Squad Roster;
- Squad Instructions, only when `instructions` is non-empty.
Roster entries include member name, member type, mention markdown, and non-empty
role. Archived agent members are skipped from the briefing roster.
## Issue assignment behavior
Issues can be assigned to squads with:
```text
assignee_type = "squad"
assignee_id = <squad-id>
```
Current behavior:
- assignment routes work to `squad.leader_id`;
- it does not enqueue every squad member;
- assignment while status is `backlog` does not immediately start work;
- moving a squad-assigned issue out of `backlog` can trigger the leader;
- changing assignee cancels existing tasks for the issue before enqueueing the
new assignee path.
Assignment validation rejects a missing type/id pair, non-existent squad,
archived squad, archived leader, and private leader when the actor cannot access
it.
## Comment and mention behavior
If an issue is assigned to a squad, a new comment can wake the squad leader. This
is leader routing, not member fan-out.
Squad mention format:
```md
[@Squad Name](mention://squad/<squad-id>)
```
Current behavior: resolve the squad, read `leader_id`, enqueue a leader task,
and use the current comment as the trigger comment. It does not enqueue every
squad member.
## Autopilot behavior
Autopilots can be assigned to squads. For `assignee_type = "squad"`:
- executable agent resolves from `squad.leader_id`;
- admission/readiness checks run against the leader;
- archived squads fail closed / skip dispatch;
- run attribution records squad id where applicable.
For `create_issue` autopilots, the created issue keeps `assignee_type = "squad"`
and `assignee_id = <squad-id>`, while the actual executing agent is the resolved
leader. For `run_only` autopilots, no issue is created; the task is created
directly for the resolved leader agent.
## Handling complaints or product gaps
When the user says squad behavior is wrong, confusing, or disappointing, do not
immediately assume code is broken and do not defend current behavior just because
it exists. Classify first:
- expected current behavior;
- configuration issue;
- product limitation;
- actual bug.
Explain the current source-backed behavior. If the behavior is technically
correct but product-wise bad, say so and propose a scoped product/code change.
Do not silently change squad routing, member fan-out, leader briefing, autopilot
behavior, or comment-trigger behavior without confirmation. These are product
contract changes with side effects.
## Side effects
These actions can trigger agent work or mutate durable state:
- creating a squad;
- updating squad fields;
- changing `leader_id`;
- adding/removing members;
- changing member roles;
- assigning an issue to a squad;
- moving a squad-assigned issue out of backlog;
- commenting on a squad-assigned issue;
- mentioning a squad;
- creating or triggering squad-assigned autopilots;
- recording squad activity with `multica squad activity`;
- deleting/archive squad.
Do not perform side-effecting actions as tests unless the user explicitly
authorizes them.
## Common wrong assumptions
- A squad is not an agent.
- Squad work routes to `leader_id`, not every member.
- Squad mention routes to the leader, not every member.
- Squad assignment routes to the leader, not every member.
- Squad autopilot resolves to the leader as executable agent.
- `instructions` are leader briefing content, not automatic member prompts.
- `description` is not proven runtime prompt content.
- `role` is roster context, not automatic scheduling.
- Backlog assignment does not immediately start work.
## References
For source paths, tests, edge cases, and exact routing details, see:
```text
references/squad-source-map.md
```

View File

@@ -0,0 +1,185 @@
# Squad Source Map
This file records source evidence for `multica-squads/SKILL.md`.
Use this when the task requires exact source paths, edge-case behavior, tests, or contract verification.
## Object Model
### DB shape
Source:
```text
server/migrations/084_squad.up.sql
server/migrations/088_squad_instructions.up.sql
server/pkg/db/queries/squad.sql
packages/core/types/squad.ts
```
Key facts:
- `squad` stores `name`, `description`, `leader_id`, `creator_id`, archive metadata, and `instructions`.
- `squad_member` stores `member_type`, `member_id`, and `role`.
- `member_type` is constrained to `agent` or `member`.
- issue `assignee_type` supports `squad`.
## CLI
Source:
```text
server/cmd/multica/cmd_squad.go
```
Commands:
```bash
multica squad list
multica squad get <squad-id>
multica squad create
multica squad update <squad-id>
multica squad delete <squad-id>
multica squad activity <issue-id> <outcome>
multica squad member list <squad-id>
multica squad member add <squad-id>
multica squad member remove <squad-id>
multica squad member set-role <squad-id>
```
Use `--help` for exact flags before writes.
## Create / Update
Source:
```text
server/internal/handler/squad.go
```
Contracts:
- create requires `leader_id`;
- leader must be workspace agent;
- archived leader is rejected;
- leader is auto-added as member with role `leader`;
- updating `leader_id` auto-adds new leader as member if missing.
## Leader Briefing
Source:
```text
server/internal/handler/squad_briefing.go
server/internal/handler/daemon.go
```
Contracts:
- squad leader tasks append briefing to leader agent instructions;
- briefing includes operating protocol, roster, and optional instructions;
- `instructions` section appears only when non-empty;
- archived agent members are skipped from roster;
- no traced behavior injects `instructions` into every squad member.
## Issue Assignment
Source:
```text
server/internal/handler/issue.go
server/internal/handler/squad.go
server/internal/service/task.go
```
Contracts:
- `assignee_type="squad"` routes to `squad.leader_id`;
- backlog assignment does not immediately enqueue;
- moving out of backlog can enqueue leader;
- assignee change cancels existing issue tasks first;
- private leader access is checked;
- pending task dedup is applied.
## Comment / Mention
Source:
```text
server/internal/handler/comment.go
server/internal/handler/squad.go
server/internal/service/task.go
```
Contracts:
- commenting on a squad-assigned issue can wake the leader;
- explicit `mention://squad/<id>` resolves squad and enqueues leader;
- squad mention does not fan out to members;
- leader task uses `is_leader_task=true`;
- leader self-trigger loops are guarded.
## Autopilot
Source:
```text
server/internal/service/autopilot.go
```
Contracts:
- squad autopilot resolves executable agent from `squad.leader_id`;
- readiness/admission checks target the leader;
- archived squad fails closed / skips dispatch;
- `create_issue` keeps the issue assigned to the squad;
- `run_only` creates task directly for leader.
## Child-done Parent Trigger
Source:
```text
server/internal/handler/issue_child_done.go
```
Contracts:
- when child issue completes and parent is assigned to squad, parent squad leader can be triggered;
- routing is leader-only;
- loop guards skip same squad, same effective leader, and shared-leader cross-squad cases.
## Private Leader Access
Source:
```text
server/internal/handler/agent_access.go
```
Contracts:
- public leaders pass;
- agent-to-agent traffic is allowed;
- private leader access for members is limited to owner/admin or agent owner;
- system triggers are treated like agent triggers for squad leader enqueue.
## Tests
Relevant test groups:
```text
server/internal/handler/squad_assign_trigger_test.go
server/internal/handler/squad_comment_trigger_test.go
server/internal/handler/squad_briefing_test.go
server/internal/handler/squad_private_leader_test.go
server/internal/handler/autopilot_private_leader_test.go
server/internal/handler/squad_no_action_test.go
```
Verification command:
```bash
go test ./internal/handler -run 'Test.*Squad|Test.*squad|Test.*Autopilot.*Squad|Test.*ChildDone.*Squad'
```

View File

@@ -354,6 +354,40 @@ func TestCreatingAgentsSkillCoversAgentCreationContracts(t *testing.T) {
}
}
func TestSquadsSkillCoversLeaderRoutingContract(t *testing.T) {
skill, ok := findSkill(t, "multica-squads")
if !ok {
return
}
fm, body, _ := splitFrontmatter(skill.Content)
if got := strings.TrimSpace(fm["user-invocable"]); got != "false" {
t.Errorf("user-invocable = %q, want false (squad guidance triggers from context)", got)
}
if got := strings.TrimSpace(fm["allowed-tools"]); !strings.Contains(got, "Bash(multica *)") {
t.Errorf("allowed-tools = %q, want access to the Multica CLI", got)
}
mustContain := []string{
"A squad is not an agent",
"squad's `leader_id` agent",
"squad members are not automatically fanned out",
"multica squad member set-role",
"mention://squad/<squad-id>",
"recording squad activity",
"references/squad-source-map.md",
}
for _, want := range mustContain {
if !strings.Contains(body, want) {
t.Errorf("squads skill missing %q", want)
}
}
if !skillHasFile(skill, "references/squad-source-map.md") {
t.Errorf("squads skill missing supporting file references/squad-source-map.md")
}
}
func findSkill(t *testing.T, name string) (AgentSkillData, bool) {
t.Helper()
for _, s := range loadBuiltinSkills() {
@@ -365,6 +399,15 @@ func findSkill(t *testing.T, name string) (AgentSkillData, bool) {
return AgentSkillData{}, false
}
func skillHasFile(skill AgentSkillData, path string) bool {
for _, f := range skill.Files {
if f.Path == path {
return true
}
}
return false
}
// splitFrontmatter returns the top-level scalar keys of a leading YAML
// frontmatter block, the body after it, and whether a block was found. It only
// understands flat `key: value` lines — enough for the template's frontmatter.