## ADDED Requirements ### Requirement: Register a new AI agent The system SHALL create a new agent identity record with a system-assigned immutable UUID (`agentId`) when a valid `CreateAgentRequest` is received. The `email` field SHALL be unique across all agents. The agent SHALL be created with `status: active`. The system SHALL enforce a free-tier limit of 100 registered agents per account. #### Scenario: Successful agent registration - **WHEN** a POST request to `/agents` is received with a valid `CreateAgentRequest` body and a valid Bearer token - **THEN** the system creates the agent, assigns a UUID `agentId`, sets `status` to `active`, sets `createdAt` and `updatedAt` to the current timestamp, and returns `201` with the full `Agent` object #### Scenario: Duplicate email rejected - **WHEN** a POST request to `/agents` is received with an `email` that is already registered - **THEN** the system returns `409 Conflict` with `code: AGENT_ALREADY_EXISTS` #### Scenario: Free tier limit enforced - **WHEN** a POST request to `/agents` is received and the account already has 100 registered agents - **THEN** the system returns `403 Forbidden` with `code: FREE_TIER_LIMIT_EXCEEDED` and `details.limit: 100` #### Scenario: Invalid request body rejected - **WHEN** a POST request to `/agents` is received with a missing required field or invalid field value (e.g. invalid semver, invalid email, invalid capability pattern) - **THEN** the system returns `400 Bad Request` with `code: VALIDATION_ERROR` and `details` identifying the failing field ### Requirement: Retrieve a single agent by ID The system SHALL return the full `Agent` record for a given `agentId`. #### Scenario: Agent found - **WHEN** a GET request to `/agents/{agentId}` is received with a valid Bearer token and a UUID that exists in the registry - **THEN** the system returns `200 OK` with the full `Agent` object #### Scenario: Agent not found - **WHEN** a GET request to `/agents/{agentId}` is received with a UUID that does not exist - **THEN** the system returns `404 Not Found` with `code: AGENT_NOT_FOUND` ### Requirement: List agents with pagination and filtering The system SHALL return a paginated list of agents, orderd by `createdAt` descending, optionally filtered by `owner`, `agentType`, and/or `status`. #### Scenario: Successful paginated list - **WHEN** a GET request to `/agents` is received with optional `page`, `limit`, `owner`, `agentType`, `status` query parameters and a valid Bearer token - **THEN** the system returns `200 OK` with a `PaginatedAgentsResponse` containing `data`, `total`, `page`, and `limit` #### Scenario: Invalid pagination parameters rejected - **WHEN** a GET request to `/agents` is received with `limit` greater than 100 or `page` less than 1 - **THEN** the system returns `400 Bad Request` with `code: VALIDATION_ERROR` ### Requirement: Update agent metadata The system SHALL partially update a mutable agent record. `agentId`, `email`, and `createdAt` SHALL be immutable. Setting `status` to `decommissioned` SHALL be a one-way irreversible operation. #### Scenario: Successful partial update - **WHEN** a PATCH request to `/agents/{agentId}` is received with a valid partial `UpdateAgentRequest` body and a valid Bearer token - **THEN** the system updates only the provided fields, sets `updatedAt` to the current timestamp, and returns `200 OK` with the full updated `Agent` object #### Scenario: Attempt to modify immutable field rejected - **WHEN** a PATCH request to `/agents/{agentId}` contains the `email` field - **THEN** the system returns `400 Bad Request` with `code: IMMUTABLE_FIELD` and `details.field: email` #### Scenario: Decommissioned agent cannot be updated - **WHEN** a PATCH request to `/agents/{agentId}` targets an agent with `status: decommissioned` - **THEN** the system returns `403 Forbidden` with `code: AGENT_DECOMMISSIONED` ### Requirement: Decommission (soft-delete) an agent The system SHALL set an agent's `status` to `decommissioned` and revoke all of its active credentials. The agent record SHALL be retained for audit purposes. This operation SHALL be irreversible. #### Scenario: Successful decommission - **WHEN** a DELETE request to `/agents/{agentId}` is received with a valid Bearer token and the agent exists and is not already decommissioned - **THEN** the system sets `status` to `decommissioned`, revokes all active credentials for this agent, and returns `204 No Content` #### Scenario: Already decommissioned agent rejected - **WHEN** a DELETE request to `/agents/{agentId}` is received for an agent that is already `decommissioned` - **THEN** the system returns `409 Conflict` with `code: AGENT_ALREADY_DECOMMISSIONED` ### Requirement: Authentication required on all agent endpoints All agent endpoints SHALL require a valid Bearer JWT in the `Authorization` header. #### Scenario: Missing token rejected - **WHEN** any request to `/agents` or `/agents/{agentId}` is received without an `Authorization: Bearer` header - **THEN** the system returns `401 Unauthorized` with `code: UNAUTHORIZED` #### Scenario: Invalid token rejected - **WHEN** any request to `/agents` or `/agents/{agentId}` is received with an expired, malformed, or revoked Bearer token - **THEN** the system returns `401 Unauthorized` with `code: UNAUTHORIZED` ### Requirement: Rate limiting on all agent endpoints The system SHALL enforce a rate limit of 100 requests per minute per authenticated client. Rate limit state SHALL be tracked in Redis. #### Scenario: Rate limit exceeded - **WHEN** a client sends more than 100 requests to any agent endpoint within a 60-second window - **THEN** the system returns `429 Too Many Requests` with `X-RateLimit-Limit`, `X-RateLimit-Remaining: 0`, and `X-RateLimit-Reset` headers