Declarative Resource Management

August 20, 2026 · View on GitHub

AgentTeams uses Kubernetes CRD-style declarative YAML to manage platform resources — Worker, Team, Human, and Manager. You describe the desired state, and the AgentTeams Controller handles creation, updates, and deletion automatically.

Core Concepts

Organization Structure

AgentTeams uses a three-tier organization that maps to real enterprise team structures:

Admin (Human administrator)

  ├── Manager (AI Agent, management entry point)
  │     ├── Team Leader A (special Worker, coordinates team tasks)
  │     │     ├── Worker A1
  │     │     └── Worker A2
  │     ├── Team Leader B
  │     │     └── Worker B1
  │     └── Worker C (standalone Worker, not part of any Team)

  └── Human Users (real people, access based on permission level)
        ├── Level 1: Admin-equivalent, can talk to all roles
        ├── Level 2: Can talk to specified Teams' Leaders + Workers
        └── Level 3: Can only talk to specified Workers

Four Resource Types

ResourceDescriptionUnderlying Entity
WorkerAI Agent execution unitDocker container + Matrix account + MinIO space
TeamCollaboration group referencing one Leader Worker and N member WorkersWorker references + Team Room
HumanReal human userMatrix account + Room permissions
ManagerCoordinator Agent (task routing, Worker/Team orchestration)Manager Agent runtime (same stack as Workers; reconciled like other CRs)

All resources share a unified API version: apiVersion: agentteams.io/v1beta1.

kubectl short names (when CRDs are installed): wk (Worker), tm (Team), hm (Human), mgr (Manager).

Worker

A Worker is the basic execution unit in AgentTeams — an AI Agent running in a Docker container with its own Matrix communication account and MinIO storage space.

Basic Configuration

apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: alice
spec:
  model: claude-sonnet-4-6        # LLM model
  identity: |                      # Worker public identity (generates IDENTITY.md)
    - Name: Alice
    - Specialization: DevOps, CI/CD pipeline management
  soul: |                          # Worker personality and values (generates SOUL.md)
    # Alice - DevOps Worker
    ## Personality
    - Methodical and detail-oriented, always double-checks before deploying
    - Proactive about potential risks, raises concerns early
    - Prefers automation over manual processes
    ## Values
    - Stability first: never sacrifice reliability for speed
    - Transparency: always explain what you're doing and why
  agents: |                        # Agent behavior rules (generates AGENTS.md)
    ## Behavior
    - Monitor CI/CD pipelines proactively
    - Alert on failures immediately
  skills:                          # AgentTeams built-in skills
    - github-operations
    - git-delegation
  mcpServers:                      # MCP servers callable via mcporter (url = full gateway endpoint)
    - name: github
      url: https://gateway.example.com/mcp-servers/github/mcp
      transport: http              # "http" (default, Streamable HTTP) or "sse"
  resources:
    requests:
      cpu: 250m
      memory: 512Mi
    limits:
      cpu: "2"
      memory: 2Gi

Field Reference

FieldTypeRequiredDefaultDescription
metadata.namestringYesWorker name, globally unique
spec.modelstringYesLLM model ID, e.g. claude-sonnet-4-6, qwen3.5-plus
spec.runtimestringNoopenclawThe current Worker CRD accepts openclaw, qwenpaw, copaw (legacy), or hermes.
spec.imagestringNoCustom image. When empty, the controller selects AGENTTEAMS_WORKER_IMAGE, AGENTTEAMS_COPAW_WORKER_IMAGE, AGENTTEAMS_QWENPAW_WORKER_IMAGE, or AGENTTEAMS_HERMES_WORKER_IMAGE by runtime. The current chart has no worker.defaultImage.qwenpaw, so set this field explicitly for a QwenPaw Worker on Kubernetes.
spec.identitystringNoWorker public identity (OpenClaw: generates IDENTITY.md; QwenPaw: merged into SOUL.md per controller)
spec.soulstringNoWorker personality and values (generates SOUL.md)
spec.agentsstringNoAgent behavior rules, used to generate AGENTS.md
spec.skills[]stringNoSkill names declaratively assigned to the Worker through the Manager, Dashboard, or API
spec.mcpServers[]objectNoMCP servers callable via mcporter. Each item: name (required, map key in mcporter-servers.json), url (required, full gateway endpoint), transport (http default or sse). The controller injects Authorization: Bearer <gatewayKey>; gateway-side authorization is out of scope.
spec.packagestringNoCustom package URI: file://, http(s)://, nacos://, or controller-resolved packages/{name}.zip after upload
spec.expose[]objectNoPorts to expose via Higress gateway (see Service Publishing)
spec.channelPolicyobjectNoAdditive/deny-list overrides for group @mentions and DMs (see Channel policy)
spec.statestringNoRunningDesired lifecycle: Running, Sleeping, or Stopped — controller reconciles containers toward this
spec.resourcesobjectNoinstall/backend defaultsCPU/memory requests and limits for this Worker Pod. Shape: requests.cpu, requests.memory, limits.cpu, limits.memory using Kubernetes quantity strings

Changing spec.resources updates the Worker spec and recreates the managed container/Pod. Avoid resource changes while a Worker is actively processing a task.

The Controller already contains an OpenHuman backend and image configuration, but the shipped Worker CRD enum does not accept openhuman. Until a separate business-code change aligns that contract, do not set spec.runtime: openhuman in Worker YAML.

identity / soul / agents vs package

There are two ways to configure a Worker's identity and behavior:

  • Inline: Define spec.identity, spec.soul, and spec.agents directly in the YAML. The Controller generates the corresponding IDENTITY.md, SOUL.md, and AGENTS.md. Best for lightweight configurations.
  • Package: Provide a ZIP via spec.package containing the full config (IDENTITY.md, SOUL.md, AGENTS.md, custom skills, Dockerfile, etc.). Best for complex setups requiring custom skills or system dependencies.

When both are set, inline fields override the corresponding files in the package. This allows you to use a package as a base template while customizing specific aspects via YAML — for example, importing a shared package but overriding soul to give the Worker a unique role definition.

Worker Skills

spec.skills records Skills declaratively assigned to a Worker through the Manager, Dashboard, or API. A referenced Skill can come from the AgentTeams Worker skill library, from a third-party Skill placed under $AGENTTEAMS_WORKSPACE_DIR/worker-skills/<skill-name>/, or from a complete package distributed by the Dashboard.

For an existing Worker, either put the complete Skill directory in the Manager workspace or send the Manager a ZIP attachment containing one complete Skill root. Then ask the Manager to install it:

Install the alert-fusion skill from ~/worker-skills/alert-fusion/ for Worker amy-ai. Verify the upload and confirm that the Worker assignment includes the skill.

For an attachment, ask the Manager to safely extract and validate the ZIP before it stages the Skill under ~/worker-skills/ and distributes it.

The Manager uploads and verifies SKILL.md before updating spec.skills. QwenPaw Workers consume the resulting runtime assignment, synchronize the selected skill into their native workspace, then refresh and enable it automatically.

The assignment can also be checked through conversation instead of a CLI command:

Check the skills assigned to Worker amy-ai and confirm whether alert-fusion is included.

You can also distribute a Skill ZIP directly to one or more Workers through the Dashboard. The Dashboard validates name and description in SKILL.md, preserves the complete package under agents/<worker-name>/skills/<skill-name>/, updates spec.skills, and attempts to restart the Worker to trigger a reload. If the restart is not confirmed, the files and declarative assignment remain in place and the UI reports a partial failure; a subsequent Controller reconcile can still make the assignment effective without another upload. See Worker Guide: Distribute through the Dashboard for the complete UI flow and ZIP constraints.

All supported Dashboard distribution paths update spec.skills. The Controller may ask the Manager to restore a missing declared Skill later, but a Dashboard-distributed Skill does not need a Manager-side source copy. If the Worker copy still exists, Manager recovery failure is ignored. If the Worker copy is missing and the Manager cannot restore it, reconciliation continues and records a non-blocking warning in Worker status. Remote Skill assignments also keep reconciliation non-blocking when a requested version or label cannot be refreshed: an existing canonical copy is retained, and Worker status records a sanitized warning that identifies the Skill and requested version or label without exposing source credentials.

You can also use spec.package to provide a Worker package containing a skills/ directory. Package skills and assigned skills are merged without conflict.

Worker with Custom Package

apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: devops-alice
spec:
  model: claude-sonnet-4-6
  runtime: openclaw
  skills: [github-operations]
  mcpServers:
    - name: github
      url: https://gateway.example.com/mcp-servers/github/mcp
  package: file://./devops-alice.zip    # Contains custom SOUL.md, skills, Dockerfile, etc.

Worker Creation Flow

When the Controller receives a Worker resource, it executes:

  1. Resolve spec.package (if present) — download and extract to a temp directory
  2. Register a Matrix account and create a communication Room (Manager + Admin + Worker)
  3. Create a MinIO user and bucket, configure Higress gateway authorization
  4. Generate openclaw.json config (including groupAllowFrom permission matrix)
  5. Push all config files (SOUL.md, skills, crons, etc.) to MinIO
  6. Update Worker status
  7. Reconcile the Worker container

Worker Status

PhaseMeaning
PendingResource created, waiting for Controller to process
RunningContainer running, Agent online (matches desired spec.state when healthy)
SleepingDesired or actual sleep state — container stopped, can be woken
UpdatingSpec or infra change in progress
StoppedDesired stopped state reconciled
FailedCreation or runtime failure — check status.message

Status fields (subset): status.observedGeneration, status.matrixUserID, status.roomID, status.containerState, status.lastHeartbeat, status.message, status.exposedPorts (per-port domain after expose).

Team

A Team is AgentTeams's collaboration unit, consisting of one Team Leader and one or more Team Workers. The Manager delegates tasks to the Team Leader, who handles decomposition, assignment, and aggregation — achieving team-level autonomy.

Basic Configuration

apiVersion: agentteams.io/v1beta1
kind: Team
metadata:
  name: alpha-team
spec:
  description: Full-stack development team
  heartbeatEvery: 30m
  workerMembers:
    - name: alpha-lead
      role: team_leader
    - name: alpha-dev
      role: worker
    - name: alpha-qa
      role: worker

Create alpha-lead, alpha-dev, and alpha-qa as Worker resources first. Model, runtime, image, resources, identity, skills, MCP servers, package, channel policy, and lifecycle state belong only to each Worker CR.

Field Reference

Team-level fields:

FieldTypeRequiredDescription
metadata.namestringYesTeam name, globally unique
spec.descriptionstringNoTeam description
spec.peerMentionsboolNoIf true (default), team Workers may @mention each other in group rooms
spec.channelPolicyobjectNoTeam-wide overrides for group/DM allow-deny lists (same shape as Worker channelPolicy)
spec.adminobjectNoTeam-specific human admin (name required; matrixUserId optional). Defaults to global Admin when omitted
spec.humanMembers[]objectNoAdditional human Team members. In this version, role: coordinator members join the Team Room and can assign work there like the Team Admin
spec.workerMembers[]objectYesReferences to existing Worker resources; exactly one entry must have role: team_leader
spec.workerMembers[].namestringYesReferenced Worker resource name
spec.workerMembers[].rolestringYesteam_leader or worker
spec.heartbeatEverystringNoTeam Leader heartbeat interval hint

What Makes Team Leader Special

A Team Leader is essentially a Worker container, but with key differences:

  • Uses the team-leader-agent template (SOUL.md.tmpl + AGENTS.md + HEARTBEAT.md)
  • Has canonical Team Leader skills: team-coordination for strategy, project-management for Project state and ready-node resolution, and task-management for Worker task delegation
  • Does not install the older team-project-management, team-task-coordination, or team-task-management compatibility aliases into new Team Leader workspaces; existing workspaces that already copied those aliases keep their local files until explicitly upgraded or recreated
  • Does NOT have Manager-exclusive skills like worker-management or mcp-server-management
  • Referenced with role: "team_leader" in Team.spec.workerMembers
  • Follows a delegation-first principle — always assigns tasks to team Workers, never executes domain tasks itself

Team Leader AGENTS.md Assembly

The Team Leader's AGENTS.md is assembled in three layers, each managed independently:

<!-- agentteams-builtin-start -->
[Builtin: Team Leader workspace rules, task flow, skills reference]
<!-- agentteams-builtin-end -->

<!-- agentteams-team-context-start -->
## Coordination
- Upstream coordinator: @manager:{domain}
- Team Admin: @admin:{domain}
- Team: alpha-team
- Team members: alpha-dev, alpha-qa
<!-- agentteams-team-context-end -->

[User-provided content from spec.agents (if any)]
  • The builtin section is auto-managed by AgentTeams and updated on upgrades
  • The team context is auto-injected with the team name, members, coordinator info, heartbeat interval, and worker idle timeout
  • User-provided spec.agents content is placed after both sections and preserved across updates

Room Topology

Creating a Team produces the following Matrix Rooms:

Leader Room:   Manager + Global Admin + Leader        ← Manager-to-Leader communication channel
Team Room:     Leader + Team Admin + W1 + W2 + ...    ← Leader-to-Workers collaboration space
Worker Room:   Leader + Team Admin + Worker           ← Leader-to-individual-Worker private chat
Leader DM:     Team Admin ↔ Leader                    ← Team management channel

Key design: the Team Room does NOT include the Manager, establishing a delegation boundary. The Manager communicates with the Leader only through the Leader Room and never reaches into the team directly.

Task Flow

Admin assigns task → Manager

Manager semantically chooses a matching Team from its name, description, Leader, and Workers

Manager creates task spec, @mentions Leader

Leader decomposes into sub-tasks, assigns to team Workers

Workers complete execution, @mention Leader

Leader aggregates results, @mentions Manager

Manager notifies Admin

Team matching is not backed by structured team-level matching/filtering fields such as domain, expertise, or capabilities on the Team object. Worker-level skills can still describe individual members, but Manager delegation is based on semantic judgement over the Team name, spec.description, Leader name, and Worker names rather than a structured Team filter.

Team Status

PhaseMeaning
PendingResource created, waiting for Controller to process
ActiveLeader and Workers reconciled successfully
DegradedSome Workers unavailable or not ready; Leader may still run
FailedReconciliation error — check status.message

Status fields: teamRoomID, leaderDMRoomID, leaderReady, readyWorkers, totalWorkers, workerExposedPorts (map of worker name → exposed port statuses).

Team Admin

You can assign a dedicated admin (Team Admin) for a Team, replacing the global Admin for team management:

spec:
  admin:
    name: pm-zhang
    matrixUserId: "@pm-zhang:domain"

If not specified, the global Admin is used by default. The Team Admin is invited to the Team Room and Leader DM, and can communicate directly with the Leader on team matters.

Team Members

Use spec.humanMembers to add human members who are part of the Team but are not Workers. The first supported member role is coordinator: the member is invited to the Team Room, and Leader/Workers accept their @mentions there as authorized task assignment. Leader DM remains limited to the Team Admin and Leader.

spec:
  admin:
    name: pm-zhang
    matrixUserId: "@pm-zhang:domain"
  humanMembers:
    - name: tech-lead-li
      matrixUserId: "@tech-lead-li:domain"
      role: coordinator

Manager

The Manager resource describes the AgentTeams Manager Agent — the coordinator that receives instructions from Admin and orchestrates Workers and Teams. It uses the same API group/version as other resources and is reconciled by agentteams-controller (update image, SOUL/AGENTS, MCP authorization, optional package, and desired state).

Basic configuration

apiVersion: agentteams.io/v1beta1
kind: Manager
metadata:
  name: default
spec:
  model: qwen3.5-plus
  runtime: openclaw
  soul: |
    # Manager — coordination focus
  agents: |
    # Optional AGENTS.md overrides
  mcpServers:
    - name: github
      url: https://gateway.example.com/mcp-servers/github/mcp
  config:
    heartbeatInterval: 15m
    workerIdleTimeout: 720m
    notifyChannel: admin-dm
  resources:
    requests:
      cpu: 500m
      memory: 1Gi
    limits:
      cpu: "3"
      memory: 5Gi
  # state: Running   # optional: Running | Sleeping | Stopped

Field reference

FieldTypeRequiredDefaultDescription
metadata.namestringYesManager resource name (often default for the primary instance)
spec.modelstringYesLLM model ID
spec.runtimestringNoinstall/backend defaultOpenClaw (openclaw) or CoPaw/QwenPaw (qwenpaw; copaw is a legacy compatibility alias). Hermes is not a supported Manager runtime.
spec.imagestringNoCustom Manager image; empty uses deployment default
spec.soulstringNoCustom SOUL.md content
spec.agentsstringNoCustom AGENTS.md content
spec.mcpServers[]objectNoMCP servers callable via mcporter. Each item: name, url, transport (http/sse). Gateway-side authorization is out of scope.
spec.packagestringNoPackage URI (file://, http(s)://, nacos://)
spec.statestringNoRunningDesired lifecycle: Running, Sleeping, Stopped
spec.resourcesobjectNoinstall/backend defaultsCPU/memory requests and limits for the Manager Pod. Shape: requests.cpu, requests.memory, limits.cpu, limits.memory
spec.config.heartbeatIntervalstringNoHeartbeat check interval (e.g. 15m)
spec.config.workerIdleTimeoutstringNoIdle timeout before auto-sleep (e.g. 720m)
spec.config.notifyChannelstringNoNotification channel (e.g. admin-dm)

Manager status

PhaseMeaning
PendingAwaiting first successful reconcile
RunningManager Agent healthy
Sleeping / StoppedDesired lifecycle states
UpdatingSpec or rollout in progress
FailedError — see status.message

Other status fields: observedGeneration, matrixUserID, roomID, containerState, version.

Human

A Human resource represents a real person. Upon creation, a Matrix account is automatically registered and the user is invited to the appropriate Rooms based on their permission level, enabling human-AI collaboration.

Basic Configuration

apiVersion: agentteams.io/v1beta1
kind: Human
metadata:
  name: john
spec:
  displayName: John Doe
  email: john@example.com
  permissionLevel: 2
  accessibleTeams: [alpha-team]
  accessibleWorkers: []
  note: Frontend lead

Field Reference

FieldTypeRequiredDefaultDescription
metadata.namestringYesUser identifier, globally unique
spec.displayNamestringYesDisplay name
spec.emailstringNoEmail for sending credentials
spec.permissionLevelintYesPermission level: 1, 2, or 3
spec.accessibleTeams[]stringNoAccessible Team list (effective for L2)
spec.accessibleWorkers[]stringNoAccessible standalone Worker list (effective for L2/L3)
spec.notestringNoNotes

Three-Level Permission Model

Permission levels are inclusive — higher levels include all permissions of lower levels.

Level 1 — Admin Equivalent

Can talk to all roles in the system, including Manager, all Team Leaders, and all Workers. accessibleTeams and accessibleWorkers fields are ignored.

Use case: CTO, VP of Engineering.

spec:
  permissionLevel: 1

Level 2 — Team-Scoped

Can talk to specified Teams' Leaders and all their Workers, plus specified standalone Workers.

Use case: Product manager, team member.

spec:
  permissionLevel: 2
  accessibleTeams: [alpha-team, beta-team]
  accessibleWorkers: [standalone-dev]

Level 3 — Worker-Only

Can only talk to specified Workers. accessibleTeams field is ignored.

Use case: External collaborator, specialized staff.

spec:
  permissionLevel: 3
  accessibleWorkers: [alice, bob]

How Permissions Work

Human permissions are enforced through two mechanisms:

  1. Room invitations: The Human is invited to the corresponding Matrix Rooms
  2. groupAllowFrom: The Human's Matrix ID is added to the openclaw.json config of the corresponding Agents — Agents only respond to @mentions from whitelisted users
LevelgroupAllowFrom ChangesRoom Invitations
L1Added to Manager + all Leaders + all WorkersAll Rooms
L2Added to specified Teams' Leaders + Workers + specified standalone WorkersSpecified Team Rooms + Worker Rooms
L3Added to specified WorkersSpecified Worker Rooms

Human Creation Flow

  1. Register a Matrix account (random password auto-generated)
  2. Calculate which Agents need modification based on permissionLevel
  3. Update groupAllowFrom in each affected Agent's openclaw.json
  4. Invite the Human to the corresponding Rooms
  5. Update Human status
  6. Push updated configs to MinIO
  7. Send a welcome email (if SMTP and email are configured)

Automatic Welcome Email

When spec.email is set and SMTP is configured, a welcome email is automatically sent after the Human account is created, containing all the information needed to log in:

Subject: Welcome to AgentTeams - Your Account Details

Hi {displayName},

Your AgentTeams account has been created:

  Username: {matrix_user_id}
  Password: {generated_password}
  Login URL: {element_web_url}

Please log in and change your password immediately.

— AgentTeams

SMTP is configured via environment variables in the Manager container:

VariableDescription
AGENTTEAMS_SMTP_HOSTSMTP server address
AGENTTEAMS_SMTP_PORTSMTP port
AGENTTEAMS_SMTP_USERSMTP username
AGENTTEAMS_SMTP_PASSSMTP password
AGENTTEAMS_SMTP_FROMSender address

If SMTP is not configured or spec.email is empty, email sending is skipped without affecting account creation. The initial password is still recorded in status.initialPassword and can be retrieved via agt get human <name>.

Notes

  • Humans don't need containers, MinIO spaces, or Higress authorization — only a Matrix account and Room permissions
  • Target Teams must exist before creating an L2 Human
  • Target Workers must exist before creating an L3 Human
  • Changing permissionLevel triggers a full recalculation of groupAllowFrom

Package URI

Both Workers and Team Workers support custom configuration packages via spec.package. Three URI formats are supported:

FormatExampleDescription
file://file://./alice.zipLocal file, transferred via docker cp
http(s)://https://example.com/worker.zipRemote download
nacos://nacos://host:8848/ns/worker-xxx/v1Pulled from Nacos
(upload)packages/<name>.zipAfter POST /api/v1/packages, the controller returns a URI under packages/ consumed by spec.package

Nacos URI format: nacos://[user:pass@]host:port/{namespace}/{agentspec-name}[/{version}|/label:{label}]

Package Directory Structure

Regardless of URI format, the extracted package follows a unified structure:

{package}/
├── manifest.json           # Package metadata (required)
├── Dockerfile              # Custom image build (optional)
├── config/
│   ├── SOUL.md             # Worker identity and role definition
│   ├── AGENTS.md           # Agent behavior rules
│   ├── MEMORY.md           # Long-term memory
│   └── memory/             # Memory files directory
├── skills/                 # Custom skills
│   └── <skill-name>/
│       └── SKILL.md
└── crons/
    └── jobs.json           # Scheduled tasks

manifest.json

{
  "version": "1.0",
  "source": {
    "openclaw_version": "2026.3.x",
    "hostname": "my-server",
    "os": "Ubuntu 22.04",
    "created_at": "2026-03-18T10:00:00Z"
  },
  "worker": {
    "suggested_name": "my-worker",
    "model": "qwen3.5-plus",
    "runtime": "openclaw",
    "base_image": "agentteams/worker-agent:latest",
    "apt_packages": ["ffmpeg"],
    "pip_packages": [],
    "npm_packages": []
  }
}

worker.runtime (openclaw, qwenpaw, copaw (legacy), or hermes) is honored by agt apply worker --zip and overridden by an explicit --runtime flag.

Operations

Runs on the host, copying YAML into the Manager container and invoking agt apply -f …:

# Create/update resources (each document is POST or PUT in order)
bash install/agentteams-apply.sh -f worker.yaml

# Multi-document file (use --- separators)
bash install/agentteams-apply.sh -f company-setup.yaml
OptionDescription
-f <path>YAML resource file (required); multiple -f flags allowed

agt apply -f walks YAML documents in file order and calls the REST API per kind (Worker/api/v1/workers, Team/api/v1/teams, Human/api/v1/humans, Manager/api/v1/managers). Put dependencies first yourself (e.g. define Teams before Humans that reference accessibleTeams). --prune and --dry-run are not implemented in the current CLI — remove extras with agt delete … or equivalent APIs.

agentteams-import.sh — Imperative Import

For importing Workers from ZIP packages:

# Import from local ZIP
bash install/agentteams-import.sh worker --name alice --zip ./alice.zip

# Import from URL
bash install/agentteams-import.sh worker --name alice --zip https://example.com/alice.zip

# Import from Nacos
bash install/agentteams-import.sh worker --name alice --package nacos://host:8848/ns/alice/v1
bash install/agentteams-import.sh worker --name alice --package nacos://host:8848/ns/alice/label:latest

# Create without a package
bash install/agentteams-import.sh worker --name bob --model claude-sonnet-4-6 \
    --skills github-operations,git-delegation

# Note: mcpServers must be configured via YAML manifest (see Worker spec above).
#       The --mcp-servers flag has been removed — the new schema requires
#       {name, url, transport} per server and is not expressible as a CSV string.

agt CLI — In-Container Management

Operate directly inside the Manager container (or via docker exec):

# List all resources
docker exec agentteams-manager agt get workers
docker exec agentteams-manager agt get teams
docker exec agentteams-manager agt get humans
docker exec agentteams-manager agt get managers

# View a single resource
docker exec agentteams-manager agt get worker alice

# Delete a resource
docker exec agentteams-manager agt delete worker alice
docker exec agentteams-manager agt delete team alpha-team
docker exec agentteams-manager agt delete human john
docker exec agentteams-manager agt delete manager default

HTTP API — Cloud Management

The agentteams-controller exposes a REST API (default :8090) used by the agt CLI. Typical resources:

GET    /api/v1/workers
POST   /api/v1/workers
PUT    /api/v1/workers/{name}
DELETE /api/v1/workers/{name}

GET    /api/v1/teams
POST   /api/v1/teams
...

GET    /api/v1/managers
POST   /api/v1/managers
PUT    /api/v1/managers/{name}
DELETE /api/v1/managers/{name}

GET    /api/v1/projects
GET    /api/v1/projects/{id}/workflow

The project endpoints are read-only workflow inspection. GET /api/v1/projects lists projects across team (teams/{team}/shared/projects/) and standalone (shared/projects/) prefixes, sorted with an optional ?team= filter; GET /api/v1/projects/{id}/workflow returns a LangGraph-aligned workflow view (nodes / edges / next / interrupts / values / loop) derived from the project meta.json. Admin/Manager roles see all projects; a Team Leader sees only their own team's projects. agt get projects <id> --mermaid renders the workflow as a Mermaid flowchart.

Note: In typical embedded deployments, port 8090 is reachable from inside the Manager container (localhost:8090). In Kubernetes (AGENTTEAMS_KUBE_MODE=incluster), expose the controller via a Service as needed.

Batch Deployment

Use --- separators to define multiple resources in one file. agt apply -f applies documents sequentially in the order they appear — it does not sort by kind. Create every referenced Worker before its Team, then put Teams before Humans that list accessibleTeams.

Deletion order is not automatic: use agt delete per resource (respect dependencies: e.g. delete Humans before Teams they reference, if your deployment requires it).

# company-setup.yaml

# --- Workers ---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: product-lead
spec:
  model: claude-sonnet-4-6
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: backend-dev
spec:
  model: claude-sonnet-4-6
  skills: [github-operations, git-delegation]
  mcpServers:
    - name: github
      url: https://gateway.example.com/mcp-servers/github/mcp
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: frontend-dev
spec:
  model: claude-sonnet-4-6
  skills: [github-operations]
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: qa-engineer
spec:
  model: claude-sonnet-4-6
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: ops-lead
spec:
  model: claude-sonnet-4-6
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: monitor
spec:
  model: claude-sonnet-4-6
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: admin-assistant
spec:
  model: claude-sonnet-4-6
---
# --- Team definitions ---
apiVersion: agentteams.io/v1beta1
kind: Team
metadata:
  name: product-team
spec:
  description: Product development team
  workerMembers:
    - name: product-lead
      role: team_leader
    - name: backend-dev
      role: worker
    - name: frontend-dev
      role: worker
    - name: qa-engineer
      role: worker
---
apiVersion: agentteams.io/v1beta1
kind: Team
metadata:
  name: ops-team
spec:
  description: Operations team
  workerMembers:
    - name: ops-lead
      role: team_leader
    - name: monitor
      role: worker
---
# --- Human users ---
apiVersion: agentteams.io/v1beta1
kind: Human
metadata:
  name: zhang-san
spec:
  displayName: Zhang San
  email: zhangsan@example.com
  permissionLevel: 2
  accessibleTeams: [product-team]
  note: Product manager
---
apiVersion: agentteams.io/v1beta1
kind: Human
metadata:
  name: li-si
spec:
  displayName: Li Si
  email: lisi@example.com
  permissionLevel: 2
  accessibleTeams: [product-team]
  note: Backend developer
---
apiVersion: agentteams.io/v1beta1
kind: Human
metadata:
  name: wang-wu
spec:
  displayName: Wang Wu
  email: wangwu@example.com
  permissionLevel: 3
  accessibleWorkers: [admin-assistant]
  note: Administrative staff

One-command deployment:

bash install/agentteams-apply.sh -f company-setup.yaml

For subsequent changes, edit the YAML and re-apply. To remove a resource, use agt delete <kind> <name> (or the REST API).

Controller Architecture

Processing Flow

Entry point (agentteams-apply.sh / HTTP API / agt CLI)

YAML written to MinIO agentteams-config/{kind}/{name}.yaml

mc mirror syncs to local filesystem (10-second interval)

fsnotify detects file changes → parses YAML → writes to kine (SQLite)

controller-runtime informer detects changes → triggers Reconciler

Reconciler executes scripts (create-worker.sh / create-team.sh / create-human.sh)

Reconciler Actions

ReconcilerCREATEUPDATEDELETE
WorkerCreate container + Matrix account + MinIO spacemodel change → regenerate config; skills change → re-pushStop container + clean up resources
TeamValidate and link existing Workers + create Team RoomworkerMembers change → update membership and coordination contextRemove Team Room and coordination context; preserve Worker CRs and runtimes
HumanRegister Matrix account + configure permissions + send emailpermissionLevel change → recalculate groupAllowFromRemove from all groupAllowFrom → kick from Rooms
ManagerProvision/update Manager Agent config + runtimemodel/package/state → reconcileTear down managed Manager resources per backend

All resources use the Kubernetes finalizer pattern to ensure cleanup before deletion.

Service Publishing

Workers can expose HTTP services running inside their containers to the outside world via the Higress gateway. Add spec.expose to a Worker's configuration to publish container ports — the Controller automatically creates the necessary Higress domain, DNS service source, and route.

How It Works

Each exposed port gets an auto-generated domain:

worker-{name}-{port}-local.agentteams.io

For example, worker alice exposing port 8080 becomes accessible at worker-alice-8080-local.agentteams.io.

The Controller creates three Higress resources per exposed port:

  1. Domain: worker-{name}-{port}-local.agentteams.io
  2. DNS Service Source: points to the worker container via network alias {name}.local
  3. Route: forwards all requests on the domain to the worker's port

When the expose configuration is removed or the Worker is deleted, all associated Higress resources are automatically cleaned up.

Configuration

apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: alice
spec:
  model: qwen3.5-plus
  expose:
    - port: 8080
    - port: 3000

Expose field reference:

FieldTypeRequiredDefaultDescription
expose[].portintYesContainer port to expose
expose[].protocolstringNohttpProtocol: http or grpc

Workers referenced by a Team

expose remains Worker-owned. Configure it on the Worker CRs, then reference those Workers from the Team:

apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: lead
spec:
  model: qwen3.5-plus
---
apiVersion: agentteams.io/v1beta1
kind: Worker
metadata:
  name: backend
spec:
  model: qwen3.5-plus
  expose:
    - port: 8080
---
apiVersion: agentteams.io/v1beta1
kind: Team
metadata:
  name: dev-team
spec:
  workerMembers:
    - name: lead
      role: team_leader
    - name: backend
      role: worker

CLI Usage

# Expose ports via CLI flag
agt apply worker --name alice --model qwen3.5-plus --expose 8080,3000

# Remove exposed ports (re-apply without --expose)
agt apply worker --name alice --model qwen3.5-plus

Use Cases

  • Web App Preview: A Worker develops a web application and exposes it for the Admin or other team members to preview
  • API Service: A Worker runs a backend API that other Workers or external systems need to access
  • Development Server: Expose a dev server for real-time testing during development

Notes

  • The worker container must be running and the service must be listening on the specified port before it can be accessed
  • Domains are auto-generated; custom domains are not yet supported
  • No authentication is configured on exposed routes (public access within the network)
  • Removing a port from spec.expose and re-applying will clean up the corresponding Higress resources

Two Deployment Modes

Dimensionembedded (default)incluster (K8s)
Config storageMinIO agentteams-config/K8s etcd (CRDs stored directly in K8s)
Controller detectionfsnotify → kine → informercontroller-runtime watches K8s API directly
Switch viaAGENTTEAMS_KUBE_MODE=embeddedAGENTTEAMS_KUBE_MODE=incluster

Channel policy (Worker and Team)

channelPolicy augments the default allow lists used when generating Agent configs (group @mentions and DMs). It is additive and subtractive on top of defaults, not a full replacement.

FieldPurpose
groupAllowExtraExtra Matrix user IDs (or short names resolved by the controller) allowed for group @mentions
groupDenyExtraDeny list for group @mentions (deny wins over allow)
dmAllowExtraExtra IDs allowed for direct messages
dmDenyExtraDeny list for DMs

Set spec.channelPolicy on a Worker for per-member policy, and spec.channelPolicy on a Team for Team-wide policy.

Communication Permission Matrix

AgentTeams uses the groupAllowFrom field in openclaw.json to control which @mentions each Agent accepts, enabling fine-grained communication permissions.

RolegroupAllowFrom includes
ManagerAdmin, all Team Leaders, all standalone Workers, Human L1
Team LeaderManager, Admin, all team Workers, Human L1, Human L2 for this Team
Team WorkerLeader, Admin, Human L1, Human L2 for this Team, specified Human L3
Standalone WorkerManager, Admin, Human L1, specified Human L2/L3

Key rules:

  • Manager does not penetrate Teams — communicates only with the Leader, never directly with team Workers
  • Team Workers only recognize their Leader — groupAllowFrom does not include Manager
  • Permissions are inclusive — Human L1 > L2 > L3, higher levels include all lower-level permissions
  • Standalone Workers maintain the existing pattern — communicate directly with Manager

FAQ

Q: Can Teams and standalone Workers coexist?

Yes. Teams and standalone Workers coexist in the same AgentTeams instance. The Manager decides whether to delegate to a Team Leader or assign directly to a standalone Worker based on the task domain.

Q: What happens when a Human's permissionLevel is changed?

The Controller recalculates the Human's groupAllowFrom across all affected Agents, removes old permissions, adds new ones, and updates Room invitations.

Q: Can a Team Worker belong to multiple Teams?

No. Each Worker can only belong to one Team (or be a standalone Worker).

Q: What if the target Team doesn't exist yet when creating an L2 Human?

The Controller marks the Human as Pending and automatically backfills permissions once the target Team is created.

Q: Is there a --prune mode for declarative apply?

Not in the current agt apply CLI. List resources with agt get … and delete explicitly, or automate against the REST API.