mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
Add built-in squads skill
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
247
server/internal/service/builtin_skills/multica-squads/SKILL.md
Normal file
247
server/internal/service/builtin_skills/multica-squads/SKILL.md
Normal 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
|
||||
```
|
||||
@@ -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'
|
||||
```
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user