- name
- squad-sdk-authoring
- description
- Author one portable, project-owned and traceable OpenCorvus Expert Squad through the Generate Expert Squads workflow and canonical SDK writer.
# Generate Expert Squads authoring method
Define one narrow domain, explicit selection guidance, and only the dynamic agents that perform real work.
This Skill is the shared readable contract for the scheduler, source analyst, package architect, and contract reviewer. Loading it never grants a mutation tool. Only the scheduler projection owns `expert_squad_author`; projected workers use this Skill and its supporting definition contract to produce or review evidence, then follow their own role prompt without attempting the scheduler-only mutation.
## Conversation contract
Choose the smallest team that can deliver and verify the actual outcome. Begin with one capable execution owner; add independent verification where correctness or risk requires it. Add a Planner or parallel specialist only for a concrete shared decision, distinct information source, permission boundary, or useful independent result that the existing owner cannot handle efficiently. Use `virtual_workflows: {}` for direct dispatch and a binding graph for real ordered or parallel responsibilities. Every dependency must identify an actual evidence or settled-state prerequisite. Every declared workflow node is a Task-level, once-per-Task node.
When the Task contains operator-visible Goals, treat them as versioned Delivery Slice contracts. Dispatch adapters that support Slice subjects receive explicit `goal_ids` only as work and evidence subjects; dispatch lineage persists those values as exact Delivery Slice revision IDs. Never multiply a workflow node per Slice, infer readiness from a Slice, or give a Slice scheduling, retry, workspace, or lifecycle ownership. Do not generate a Requirements -> Architect -> Implementer chain as the default authoring shape; the Planner owns that bounded planning synthesis and parallel workers own execution partitions.
## Agent fact and Turn contract
Every projected Agent extends the platform fact/Turn protocol selected by its `base_role`. Package prompts add domain rules; they must not redefine physical completion, introduce a submit/finalizer tool, require a terminal report, or copy Host observations into an Agent-owned result.
- Domain tools record durable facts and remain ordinary tool calls.
- A normal stream end is only a physical Turn observation.
- The visible final assistant message is natural narration of work, limitations, and blockers; it is not durable evidence transport.
- Git changes, command/test exits, process facts, and attachment consumption remain Host observations.
- Execution attempts and dispatch lineage are immutable physical evidence identities. Exact Delivery Slice revision IDs are optional evidence subjects, never scheduling locks.
- The Orchestrator owns Task lifecycle judgment. Each completion atomically appends one typed decision artifact with the exact message/tool identity, typed EvidenceLocators, every intentionally delivered Artifact locator, every accepted current Delivery Slice revision ID, the exact selected workflow ID (`null` only for direct dispatch), and the active package revision scope, project identity, namespace, manifest ID, version, and package digest. Empty deliverable or Delivery Slice lists are valid only when the Task truthfully has none. Reopen preserves earlier decisions without an active/current pointer or acceptance aggregate; only the decision written at the Task's current terminal completion time governs current progress and workflow binding.
- Every projected worker automatically receives the Core-owned `artifact_search`, `artifact_read`, `artifact_select`, `artifact_snapshot`, and `artifact_publish` transport. A scheduler receives `artifact_search`, `artifact_read`, `artifact_select`, and read-only `artifact_snapshot` only by declaring `capability:capability_set:platform:tool-registry:scheduler-transport` in its `capability_refs`; schedulers do not receive generic `artifact_publish`. Package tools must not shadow, wrap, or replace platform Artifact Tools, and an undeclared scheduler Tool is never implied.
- A projected worker publishes canonical current-Task primary-project files with `artifact_snapshot`, then passes the returned exact `resource_set` locator to `artifact_publish`. A Build-owned final role working in a managed worktree must write and reread the deliverable, verify it, commit it, call `merge_back`, require `status: "merged"`, completely read the final deliverable from the exact immutable returned `primary_head`, and pass that same value as `artifact_snapshot.source_commit` before invoking the typed publisher and any Interactive Artifact publisher from those exact commit bytes. `artifact_snapshot` never reads the mutable managed worktree, and its explicit commit authority remains stable if another Task later advances the primary worktree. `merge_back` is the last Git-affecting action, not the last tool action; immutable commit reads and publication may follow, but no file write or Git mutation may follow. A caller-owned primary-project Build role without `merge_back` omits `source_commit` and snapshots the reread primary-project file directly. The model-facing `artifact_publish` ABI carries the complete evidence value only in `payload_json` as strict JSON text with unique object keys; `resource_set` is required and must be `null` when there are no files. The Host verifies the content-addressed manifest and expands its exact refs in canonical UTF-8 byte path order inside the trusted boundary before sending the structured value through the same canonical publisher used by typed and package tools.
- Keep the two Engine Artifact publication surfaces explicit. A model-facing worker invokes the projected `artifact_publish` tool. TypeScript inside a package tool instead calls `context.host.engineArtifacts.publish({ artifact_type, schema_version, label, payload, resources })`; it never invokes or wraps the model-facing tool. Separately, package tools publish immutable Task Artifact files through `context.host.taskArtifacts.stage(...)` followed by `context.host.taskArtifacts.publish(...)` and return the typed snapshot locator. An ordinary package-tool `return string` is only the visible tool result and never publishes an Artifact.
- Every package Engine Artifact publisher declares one stable namespaced `artifact_type`, positive `schema_version`, stable `label`, canonical JSON `payload`, and Host-resolved immutable resources. It does not declare sources: a publisher names its predecessors by completely reading each one and calling `context.host.engineArtifacts.select(...)`, and the Host stamps that selected set onto the publication. Never expose a locator as a model-facing tool argument — the model cannot hand-build one, and a tool that asks for it produces calls no input can satisfy. A model-facing package publisher accepts one exact `resource_set` locator (`null` when no files), resolves it through `TaskArtifactHost.resources`, and never accepts expanded refs from the model. Return only a compact receipt containing the published `locator` and `sha256`; consumers discover the Artifact through `artifact_search`, then completely `artifact_read` and `artifact_select` the exact locator rather than treating the receipt as evidence transport. A package Task Artifact publisher instead returns its typed immutable snapshot locator; it does not invent an Engine Artifact envelope for the snapshot.
- Package Engine and Task Artifact publication is always idempotent at the ToolHost boundary. Package code does not supply an `idempotent` flag and cannot opt out of stable exact retries.
- Package tools may set a visible title and custom result metadata through `context.metadata(...)`; custom values are exposed only inside `package_metadata`. Top-level provenance, truncation, and lifecycle-control metadata is Host-owned and cannot be replaced by package code.
- A worker without a typed domain-output producer calls `artifact_publish` with canonical JSON `expert_output` type `<active-squad-id>/...` and publication-specific `source_read_refs` returned by complete `artifact_read` calls in that Turn. The Host resolves complete canonical locators and derives Task, Session, Agent, active-Squad, projection, observed, and selected provenance. Existing typed domain-output and package tools remain their domain's sole publishers and must not duplicate the same fact.
- Treat every domain Artifact consumed by another declared workflow node as a package ABI. Define one package-owned codec and typed publisher for that Artifact; make every downstream typed publisher completely read, validate, and select the exact predecessor locator. Reserve generic model-facing `artifact_publish` for terminal evidence that no declared node consumes. Prove the producer-consumer chain with real projected package-tool tests. Do not add prompt keyword lint or a Host workflow gate: the generic SDK validator cannot infer domain semantics from type strings.
- Ordinary dispatch outcomes and Agent messages carry work intent and scope, never domain Artifact inventories, locators, or bodies. Consumers use queryless search to enumerate the same-Task catalog, choose by immutable producer/type/workflow/node provenance, read exact locators to completion, and call `artifact_select` for every semantic source of a typed output. Complete but unselected reads remain observed audit facts; zero selections are valid. A user-pinned locator must be read exactly and cannot be replaced by search. For Cross-Task evidence, Mission references a completed source with `{authority: "completion_decision", source_task_id}` in `artifact_sources`; the Host imports that decision's complete deliverable set without copied locator IDs. Failed/cancelled recovery uses `{authority: "terminal_lifecycle", source_task_id, locator}`. The receiving catalog exposes a target-owned imported Engine Artifact preserving source type, schema, payload, and copied resources, with immutable `import_lineage`. Zero matches and missing optional fields are valid, while missing selected evidence, wrong ownership/path/digest, corruption, and unreadable text remain explicit errors.
## SDK authoring path
Before constructing a package, completely read both supporting contracts:
- Load `references/authoring-quality-method.md` to decide reuse, upgrade, composition, or creation; review professional sources and licenses; define non-generic role contracts; derive evidence dependencies; and publish one authoring decision. Stop before blueprint construction when that method returns reuse or composition, exposes a renamed duplicate, lacks professional asset authority, or leaves any rejection unresolved.
- Load `references/definition-contract.json` only after a create or upgrade decision. Its `runtime_template_ids` array is the complete legal `base_role` set, and its `tool_input` member is one complete positive tool-call example. Replace only the semantic identities, projections, workflow, files, and prompts required by the accepted decision. Do not copy the outer contract object or `runtime_template_ids` into the tool input.
Treat the authoring decision as the evidence contract for the blueprint. Every Agent must have a distinct required input, exclusive domain judgment, durable output, exact capability projection, and blocker. Justify each additional role by the distinct contribution it makes to the outcome, and keep genuinely independent producers parallel. Every additional dependency must represent a real evidence prerequisite; independent producers remain in the same frontier and a genuine join waits for every mandatory predecessor. Do not create workers to meet a headcount or add edges to manufacture topology metrics.
Every created or upgraded Expert Squad includes at least one substantive package-local `skills/<skill-id>/SKILL.md`, supporting domain assets, and exact scheduler/worker projections. Reuse only a fixed and audited source whose applicable license permits redistribution; otherwise author clean-room and record the rejected sources and professional limits. A placeholder Skill, generic checklist, copied prompt fragment, filename-only asset, unprojected Skill, or role-only package fails authoring review.
Build one compact structured blueprint and call `expert_squad_author` once. Identity, README, selector, scheduler, Agents, and workflows are explicit; installation scope and generation provenance are not inputs because the Host always installs successful generations beneath the current project's `.opencorvus` catalog and records the exact Task and scheduler Session. README, selector instructions, scheduler prompt, and Agent prompts are inline strings. The Host alone projects those values to canonical manifest paths and the package file tree. There is no `manifest`, `definition`, `files`, or top-level `tools` wrapper. A shared package tool is declared exactly once by placing its TypeScript entrypoint at `extra_files["tools/<tool-id>.ts"]` and granting `capability:tool:package:<squad-id>:<percent-encoded-package-ref>` through each owning scheduler or Agent's `capability_refs`; an Agent-private tool uses the corresponding `agents/<agent-id>/tools/<tool-id>.ts` path and encoded private ref. Supporting shared or private TypeScript/JSON belongs beneath `lib/` or `agents/<agent-id>/lib/` and must be statically reachable from a projected tool. Empty `capability_refs` may be omitted only when runtime-owned transport is sufficient; empty `capability_sets`, workflow-node `depends_on`, and `extra_files` may also be omitted because the authoring schema canonicalizes them before the SDK validator runs. Never omit a nonempty capability declaration. The Host constructs the SDK `ExpertSquadPackageDefinition`, calls `validateExpertSquadPackageDefinition`, materializes it only through `writeExpertSquadPackage` from `@opencorvus-ai/sdk/expert-squad-authoring`, validates the temporary source folder through the Registry, and explicitly imports it into the canonical project root through the Manager transaction. Never handwrite the final package tree, ask the user's project to install the SDK, discover an internal runtime path, or create a second manifest writer.
Set optional `name` when the Squad needs a Chinese or English human-readable name distinct from `label`. When omitted, OpenCorvus uses the required `label` as the catalog, Market, and UI display name. Keep `id` as the sole logical selection identity; never use `name` or `label` as an alias or lookup key.
`base_role` selects only the runtime upper bound and grants no Tool. Add the exact matching platform base CapabilitySet to each scheduler or worker `capability_refs` when that projection needs its members. Worker Task transport is appended by the platform; scheduler Task transport is the separate exact `scheduler-transport` CapabilitySet and must be declared when needed. Do not redeclare platform capabilities such as `websearch`, `webfetch`, or Exa as package tools. Select a research-capable worker base role, explicitly grant its matching base set, and describe the required platform-default websearch behavior in its prompt.
`fact-check` can verify exactly one already-existing assistant message per workflow node. Give each `fact-check` node exactly one upstream producer dependency. To verify several independent messages, declare one `fact-check` Agent/node per message, or first use a non-`fact-check` synthesis node to produce one combined message and verify that single output. Use `deep-research` for an independent initial evidence frontier. This is an authoring contract, not a Host topology gate: the Task may already provide an exact target message outside the declared workflow, and `depends_on` alone never proves that a target exists.
Preserve every explicit user boundary in the package, including scope limits, unknown-data rules, legal or safety disclaimers, and “not advice” language. Put delivery-wide boundaries in README, selector instructions, scheduler prompt, and the final delivery Agent prompt so the eventual artifact cannot drop them.
After `expert_squad_author` returns a successful receipt, reply with that receipt directly. Do not call `memory`, write another file, activate the new Squad, begin its workflow, or make any other state change unless the user explicitly requested that additional action.
Omit `expected_current_package_digest` for creation. The tool has no installation-scope or provenance field: a successful receipt always reports `installationScope: "project"`, a target beneath the current project's `.opencorvus/expert-squads`, and the Host-owned `generation` trace. To replace an existing exact project installation, supply the digest returned by the latest exact-scope read; a stale digest is a typed conflict and must not be retried with a guessed value. Treat the result's `id`, `installationScope`, `generation`, `agents`, `workflowTopology`, `fileCount`, `targetRoot`, `replaced`, and `mutationOperation` fields as the authoritative mutation receipt. `workflowTopology` is a read-only SDK analysis of initial frontiers, dependency-depth waves, join nodes, critical-path node count, maximum parallel width, structural classification, exact Planner node, and its parallel worker frontier. Use it to inspect the coordination cost and justify each real dependency; do not invent dependencies merely to shape the metrics or treat the report as Runtime state.
## Checklist
- Keep `prompt_profile.active` as the only active squad selection source.
- Treat each `capability_projection.agents.<agentID>` key as the runtime and dispatch identity.
- Use `base_role` only to select an existing OpenCorvus core prompt, tool set, Session kind, and adapter template. It does not add a terminal report/finalizer protocol.
- Declare each worker prompt as `agents/<agentID>/system.md` on that same projection.
- Keep scheduler configuration fixed under `capability_projection.scheduler` with `base_role: orchestrator`.
- Treat `universal-build` as a platform scheduler-only capability. Never declare it under `capability_projection.agents` or reference it from `virtual_workflows`. Every production Squad that owns a complete Mission phase must declare one package-owned Build-template final-delivery owner for its domain and route recoverable phase closure to that identity. A verification-only Squad remains read-only and must not claim product recovery ownership.
- Set manifest `version` to `YYYY.MM.DD.N`, where `N` is the positive ordinal of this Squad's revision on that date. Increment `N` for another revision on the same day; never use arbitrary SemVer or a raw timestamp.
- Use the smallest sufficient execution and verification graph, with `virtual_workflows: {}` for direct dispatch. A Planner and extra workers require a specific shared decision or independent contribution, not a default headcount. Give every nonempty workflow one applicability description that names all mandatory inputs; separate conditional variants instead of presenting labels as combinable capabilities. Every node executes once for the Task and may cite exact Delivery Slice revision subjects. The SDK validates references and acyclicity and reports whether the graph is `flat_planner_parallel_workers`, `parallel_workers_join`, or a richer `dependency_dag`; every selected node remains mandatory.
- For cross-squad composition, let Mission create one dependent fixed-profile Task per independently accepted squad stage. Validate exact squad/workflow/dependency/evidence/stage ownership with `validateExpertSquadCollaboration`, require `stage_execution: "mission_task"`, use separate collaboration definitions for conditional stage/squad graphs, keep Delivery Slices inside their owning stage Task, and keep next-squad routing out of domain prompts.
- Use collaboration `consumes` and `produces` only as semantic evidence-topology labels. They are not tool declarations, Artifact inventories, locator transport, payload transport, or renderers.
- When importing an external source capability set, keep one repository-owned source contract and validate its exact imports, native replacements, projected role owners, and collaboration definitions with `validateExpertSquadSourceCapabilities`.
- Project package skills, tools, and Model Context Protocol refs explicitly.
- Apply every mandatory decision and rejection rule in `references/authoring-quality-method.md`; do not create a package when reuse, upgrade, or composition owns the request more accurately.
- Require at least one real package-local Skill and dedicated domain asset in every generated package. Record whether the Skill was adapted from a fixed open-source revision or authored clean-room, and verify its license, executable/dependency/network surface, supporting files, package closure, and exact scheduler/worker projections before authoring.
- Keep model-readable supporting files inside their Skill directory. Keep immutable tool-only templates, configuration, and data under `assets/` and statically import them from package tools so project and global installations behave identically.
- When a scheduler-projected package tool materializes durable authority, make its prompt search the exact current Artifact type and label before invoking the tool. On a complete zero-match result it may invoke the publisher once, then search again, completely read, and select the published locator. On resume, reuse one discovered current authority without republishing; ambiguous matches or incomplete/provider-error catalogs are blockers. Downstream workers search, read, and select that authority and never invoke a scheduler-only publisher.
- Do not resolve package installation paths, read a source repository at runtime, copy one asset into multiple authorities, or add environment/path fallback.
- Delete unused projections and their agent directories before release.
- Call `expert_squad_author` with the complete definition. Its SDK hook owns manifest v2 shape, typed ref/set closure, generic graph integrity, package entrypoints, and atomic source materialization; Registry adds runtime/resource/filesystem closure validation, and Manager owns installation. Every new package must use this one authoring path.
Reject aliases, inferred identities, package workflow engines, hidden dispatch, fallback resources, terminal-report gates, copied Host observations, and any second active state.
View on GitHub