# Agent Orchestration Schema (SSOT)

`config/agent_registry.yml` is the only source of truth.

## Per-Agent Block

Use this block for every top-level agent:

```yaml
orchestration:
  mode: llm_only | crew_only | hybrid
  crew:
    enabled: true|false
    default_profile: default
    profile_hints:
      profile_name: ["keyword1", "keyword2"]
    profiles:
      default:
        team_name: "Agent Team"
        parallel_roles: true
        max_concurrency: 3
        synthesis:
          role_context: "Agent Orchestrator"
          system_prompt_ref: "roles/<agent>/orchestrator_synthesis.md"
          llm_profile: reasoning
        team:
          - id: role_id
            role_context: "Role Name"
            system_prompt_ref: "roles/<agent>/role.md"
            llm_profile: science
            skills: [optional, for router summary only]
        delegation:
          enabled: false
          max_hops: 2
          forbid_self: true
          allow_top_level_agents: []
  a2a:
    enabled: false
    allow_top_level_agents: []
    max_hops: 2
    forbid_self: true
  response_contract:
    user_visible_speaker: self
    crew_roles_user_visible: false
```

## Generation Rules

- `tools/agents generate` builds `config/crewai_agents.json` from `orchestration.*`.
- Router uses `crewai_agents.json` only for light decision metadata.
- Optional generation target: `config/crewai_teams.generated.yml` (feature flag `generate_crewai_teams`).
- Runtime `services/crewai-service/app/registry_loader.py` remains bound to `crewai_teams.yml` until final cutover.

## Validation Rules

- `mode` must be one of: `llm_only`, `crew_only`, `hybrid`.
- If `mode in [crew_only, hybrid]`, then `crew.enabled` must be `true`.
- If `crew.enabled=true`, then:
  - `crew.profiles` must be non-empty.
  - `crew.default_profile` must exist in `crew.profiles`.
  - default profile must have either:
    - non-empty `team`, or
    - `delegation.enabled=true` (delegation-only orchestrator).
- `response_contract.crew_roles_user_visible` must be `false`.
- For top-level agents, user-facing response speaker is always `self`.

## Migration Notes

- Legacy `crewai` block is still supported by generator as fallback.
- Recommended path:
  1. define `orchestration` for all top-level agents,
  2. enable `generate_crewai_teams`,
  3. switch CrewAI runtime to generated teams file,
  4. remove legacy `crewai` block.
