# Projects API

Keep project-scoped context and handoff records connected to the agent workflow that created them.

- Canonical: https://docs.xmemo.dev/docs/api/projects
- Locale: en-US
- Content-Locale: en-US
- Canonical-Content-Digest: f87dd0befa0c74658bc8585d0e0cb06c2f4e66349349fea57dfb0ad50d4d972a
- Edition-Digest: 2df735ba862f24cb27956b65dbff93e3683870d972a1b59dfe4a74fbdb701dad
- Source-Revision: sha256:4feaf3bfdc42a8d043acdcde2b2c2e4c2dd59e9077168e06d562745030d51c62

## Project boundaries and base contract

The OpenAPI contract exposes project operations under /v1/projects/{project_id}; there is no top-level POST /v1/projects operation in the committed public data-plane contract. A project_id selects the project workspace, while scope, bucket, team_id, and path remain authorization and filtering fields. Authenticate with the X-API-Key header and use a token authorized for the selected project/team.

- Context: POST /v1/projects/{project_id}/context.
- Todos: POST /v1/projects/{project_id}/todos; GET /v1/projects/{project_id}/todos.
- Todo transitions: POST /v1/projects/{project_id}/todos/{todo_id}/accept; POST /v1/projects/{project_id}/todos/{todo_id}/assign; POST /v1/projects/{project_id}/todos/{todo_id}/block; POST /v1/projects/{project_id}/todos/{todo_id}/unblock; POST /v1/projects/{project_id}/todos/{todo_id}/complete; POST /v1/projects/{project_id}/todos/{todo_id}/cancel.
- Decisions: POST /v1/projects/{project_id}/decisions; GET /v1/projects/{project_id}/decisions.
- Decision transitions: POST /v1/projects/{project_id}/decisions/{decision_id}/resolve; POST /v1/projects/{project_id}/decisions/{decision_id}/supersede; POST /v1/projects/{project_id}/decisions/{decision_id}/reopen.
- Maintenance: GET /v1/projects/{project_id}/maintenance/settings; PATCH /v1/projects/{project_id}/maintenance/settings; GET /v1/projects/{project_id}/maintenance; POST /v1/projects/{project_id}/maintenance/execute.

## Project context request and response schemas

POST /v1/projects/{project_id}/context accepts ProjectContextRequest: bucket defaults to %, team_id and durable_query are nullable, max_items defaults to 100 (1..1000), max_tokens defaults to 8000 (1..50000), include_durable_context defaults to true, and recent_hours defaults to 168 (1..8760). It returns ProjectContextPackResponse with required project_scope, assembled_at, and budget, plus project_state, agent_states, action_items, decisions, timeline, recent_memories, durable_context, governance_caveats, missing_domains, incomplete_domains, and suggested_next_actions.

```http
POST /v1/projects/memory-os/context
X-API-Key: <your-assigned-api-key>
Content-Type: application/json

{
  "bucket": "work",
  "max_items": 100,
  "max_tokens": 8000,
  "include_durable_context": true,
  "recent_hours": 168
}
```

## Project todos and decisions

Todo creation accepts ProjectTodoCreateRequest with required content and optional priority, assignee_agent_id, depends_on, due_at, source_memory_id, metadata, bucket (default work), scope, path, and team_id; it returns ProjectTodo. GET todos accepts optional status and team_id and returns an array of ProjectTodo. Decision creation accepts ProjectDecisionCreateRequest with required context and optional options, impact_level, proposed_by_agent_id, supersedes, source_memory_id, due_at, metadata, bucket (default work), scope, path, and team_id; it returns ProjectDecision. Decision listing accepts status and team_id and returns an array.

```http
POST /v1/projects/memory-os/todos
X-API-Key: <your-assigned-api-key>
Content-Type: application/json

{
  "content": "Review the current API contract",
  "priority": "high",
  "bucket": "work"
}

POST /v1/projects/memory-os/decisions
X-API-Key: <your-assigned-api-key>
Content-Type: application/json

{
  "context": "Choose the public REST reference scope",
  "options": ["memory-only", "full-openapi"]
}
```

## Todo and decision lifecycle operations

The OpenAPI lifecycle operations return ProjectTodo or ProjectDecision, except supersede which returns an array of ProjectDecision. ProjectTodo requires todo_id, project_id, and content; its other declared fields include status, priority, assignee_agent_id, accepted_by_agent_id, blocked_reason, depends_on, due_at, completed_at, completion_note, source_memory_id, created_at, updated_at, audit_trail, and extra_metadata. ProjectDecision requires decision_id, project_id, and content; its other declared fields include title, decision, rationale, status, proposed_by_agent_id, resolved_by_agent_id, impact_level, supersedes, superseded_by, options, resolution, decision_context, source_memory_id, resolved_at, created_at, updated_at, audit_trail, and extra_metadata. POST /v1/projects/{project_id}/decisions/{decision_id}/resolve requires {resolution: string}; POST /v1/projects/{project_id}/decisions/{decision_id}/supersede requires context and accepts options, impact_level, proposed_by_agent_id, and resolution_note; reopen has no request body. Todo accept, unblock, and most transitions have no request body in OpenAPI; assign requires {assignee_agent_id: string}, block requires {reason: string}, complete accepts {note: string|null}, and cancel accepts {reason: string|null}.

```json
{
  "resolution": "Use the memory-only public reference."
}
```

## Project maintenance, pagination, errors, and limits

Maintenance is part of the public /v1/projects surface in OpenAPI: settings GET/PATCH use ProjectMaintenanceSettingsResponse and ProjectMaintenanceSettingsPatchRequest; the report GET accepts team_id and scan_limit (default 1000, range 1..5000) and returns ProjectMaintenanceReportResponse; execute POST accepts ProjectMaintenanceExecuteRequest with actions (1..4 strings), target_ids (up to 500 ids), and confirm_all_matching (default false), returning ProjectMaintenanceExecuteResponse. Project todo/decision lists expose status/team_id filters but no page or cursor parameters in OpenAPI. All listed operations declare HTTPValidationError for 422. Runtime authorization errors and configurable 60-second rate limits are shared with the Authentication and Memory API pages; no project-specific quota is published in OpenAPI.

