Skip to content

# TASK_PHASE_AGENT_MANAGEMENT_v1

## Title

TASK_PHASE_AGENT_MANAGEMENT_v1 — Agent Create/Delete + Crew Teams Integration

## 1. Overview

Implement full lifecycle management for DAARION agents:

- Create agent
- Delete agent
- Assign to:
- Node
- MicroDAO
- District (city zone)
- Crew (team)
- Prepare room integration for CrewAI teams (each crew has its own room).

This task does not change runtime orchestration logic (NATS, Router, etc.) — only registry & UI.

## 2. Current State

- Database:
- Table `agents` already exists (used by city-service).

- There is a `sync-node2-dagi-agents.py` script populating 50 agents for NODE2 from `agents_city_mapping.yaml`.

- Backend:

- `repo_city.get_node_agents(node_id)` returns agents for Node Cabinet.
- `repo_city.get_agents(...)` provides listing for `/agents` UI.

- Existing fields:

  - `node_id`
  - `district`
  - `primary_room_slug`
  - `model`
  - `is_public`
  - `home_node_id`
  - `home_microdao_id`
  - `crew_team_key`

- Frontend:

- `/agents` page lists agents with:
  - status (online/offline)
  - node badge (НОДА1 / НОДА2)
  - visibility badges (Personal / Public)
- `/agents/[slug]` has Identity tab with visibility toggles.
- No button to create or delete an agent from UI.

## 3. Goals

1. Create agent from UI:
2. Minimal form.

3. Pre-fill microDAO/context when creation initiated from MicroDAO.

4. Delete agent from UI:

5. Soft-delete (mark as deleted/archived).

6. Crew / Team attribute:

7. Each agent may belong to a `crew_team_key`.

8. Prepare for Crew rooms integration:

9. For each crew (unique `crew_team_key`) we can later auto-create a room.

## 4. Database & Backend Tasks

### 4.1. Verify agents table fields

Existing fields to use: * `node_id` - which node agent belongs to * `home_node_id` - home node * `home_microdao_id` - home MicroDAO * `district` - city district key * `crew_team_key` - crew/team key * `is_archived` - soft delete flag * `deleted_at` - deletion timestamp

### 4.2. Models & Repo

`services/city-service/models_city.py`:

    class CreateAgentRequest(BaseModel):
        slug: str
        display_name: str
        kind: str = "assistant"
        role: Optional[str]
        model: Optional[str]
        node_id: Optional[str]
        home_microdao_id: Optional[str]
        district: Optional[str]
        crew_team_key: Optional[str]
        is_public: bool = False
        avatar_url: Optional[str]
        color_hint: Optional[str]

`services/city-service/repo_city.py`:

    async def create_agent(data: dict) -> dict:
        """Create new agent in database"""
        pool = await get_pool()
        # INSERT INTO agents ...

    async def delete_agent(agent_id: str) -> bool:
        """Soft delete agent (set is_archived=true, deleted_at=now())"""
        pool = await get_pool()
        # UPDATE agents SET is_archived = true, deleted_at = NOW() WHERE id = $1

### 4.3. API routes

`services/city-service/routes_city.py`:

    @router.post("/city/agents")
    async def create_agent(body: CreateAgentRequest):
        """Create new agent"""
        # Validate slug uniqueness
        # Insert into database
        # Return created agent

    @router.delete("/city/agents/{agent_id}")
    async def delete_agent(agent_id: str):
        """Soft delete agent"""
        # Set is_archived = true, deleted_at = now()
        return {"ok": True, "message": "Agent archived"}

## 5. Frontend Tasks

Files: * `apps/web/src/app/agents/page.tsx` * `apps/web/src/app/agents/new/page.tsx` (new) * `apps/web/src/app/microdao/[slug]/page.tsx` * `apps/web/src/app/agents/[agentId]/page.tsx`

### 5.1. API client

    // lib/api/agents.ts
    export async function createAgent(payload: CreateAgentPayload) {
      return apiClient.post('/city/agents', payload);
    }

    export async function deleteAgent(id: string) {
      return apiClient.delete(`/city/agents/${id}`);
    }

### 5.2. "New Agent" page

1. On `/agents` page:
2. Add button `+ Новий агент` in header.

3. Click → navigate to `/agents/new`.

4. New page `/agents/new`:

Form fields: * Ім'я (`display_name`, required) * Slug (auto-generated from name, editable) * Роль / Title (optional) * Тип агента (`kind`: orchestrator, assistant, specialist, etc.) * Нода (select: NODE1, NODE2 — fetch from `/nodes`) * MicroDAO (dropdown, fetch from `/microdao`) * Район (dropdown: leadership, security, engineering, etc.) * Команда / Crew (free text or dropdown) * Модель (optional: list of Swapper models) * Видимість: * `is_public` (switch, default false) * Аватар URL (optional) * Колір (optional color picker)

On submit: * POST `/city/agents` * Redirect to `/agents/[slug]`.

### 5.3. "Create Agent" from MicroDAO

On `/microdao/[slug]`:

- In "Агенти MicroDAO" section, add button:

    <Link href={`/agents/new?microdao=${microdaoId}`}>
      <Button>
        <Plus className="w-4 h-4 mr-2" />
        Створити агента
      </Button>
    </Link>

- On `/agents/new`:
- If query `?microdao=...` present — pre-fill MicroDAO field.

### 5.4. Delete Agent action

On `/agents/[agentId]`:

- Add "Видалити агента" button in settings/danger section.

Flow: * Confirm dialog: "Видалити агента? Його не буде видно у місті." * On confirm → `DELETE /city/agents/{id}`. * After success: redirect to `/agents` with toast.

## 6. Crew Teams (Preparation)

This task prepares data for Crew rooms:

- Each agent can have `crew_team_key`.
- Display `crew_team_key` as badge on agent card.
- Later: auto-create room for each unique `crew_team_key`.

## 7. Acceptance Criteria

1. `/agents` page has `+ Новий агент` button.
2. `/agents/new` allows creating a new agent.
3. `/microdao/[slug]` has "Створити агента" button.
4. `/agents/[agentId]` has "Видалити агента" button.
5. Deleted agents disappear from listings.
6. `crew_team_key` is visible on agent cards.