Files
sentryagent-idp/openspec/changes/phase-1-mvp-implementation/specs/agent-registry/spec.md
SentryAgent.ai Developer d3530285b9 feat: Phase 1 MVP — complete AgentIdP implementation
Implements all P0 features per OpenSpec change phase-1-mvp-implementation:
- Agent Registry Service (CRUD) — full lifecycle management
- OAuth 2.0 Token Service (Client Credentials flow)
- Credential Management (generate, rotate, revoke)
- Immutable Audit Log Service

Tech: Node.js 18+, TypeScript 5.3+ strict, Express 4.18+, PostgreSQL 14+, Redis 7+
Standards: OpenAPI 3.0 specs, DRY/SOLID, zero `any` types
Quality: 18 unit test suites, 244 tests passing, 97%+ coverage
OpenAPI: 4 complete specs (14 endpoints total)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:14:41 +00:00

5.7 KiB

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