Closedloop.ai

Project Management

Create, retrieve, update, and reorder projects — the top-level containers for documents

Overview

Projects (PRO-*) are the top-level containers in Closedloop. Every document — PRD, implementation plan, or feature — belongs to a project. Projects are typically weekly or thematic (e.g. a sprint week or an "Enterprise" theme).

All project tools accept either a UUID or a human-readable slug (e.g. PRO-7). Pass the slug verbatim — the API resolves it server-side. Newly created projects return an assigned PRO-* slug, which is the preferred handle for follow-up calls.

FieldValuesDescription
priorityLOW, MEDIUM, HIGH, URGENTProject priority
statusNOT_STARTED, IN_PROGRESS, COMPLETED, ARCHIVEDProject lifecycle status

Listing Projects

Use list-projects to retrieve the projects available to the authenticated user. The returned slug values (PRO-*) are the preferred user-facing handles for follow-up calls.

Tool: list-projects Underlying API: GET /projects

list-projects(
  limit?: number,   // 1–100, default 25
  offset?: number   // Pagination offset, default 0
)

The response is a paginated envelope. Each item includes id, name, slug, status, and updatedAt:

{
  "total": 12,
  "offset": 0,
  "limit": 25,
  "returned": 12,
  "hasMore": false,
  "nextOffset": null,
  "items": [
    {
      "id": "...",
      "name": "5/11–15",
      "slug": "PRO-25",
      "status": "IN_PROGRESS",
      "updatedAt": "2025-01-15T10:00:00Z"
    }
  ]
}

Fetching a Single Project

Use get-project to read one project by UUID or slug. When the user references a project by its slug (e.g. "tell me about PRO-7"), pass that slug as projectId directly.

Tool: get-project Underlying API: GET /projects/:projectId

get-project(
  projectId: string   // PRO-* slug or UUID
)

Listing Teams

Every project belongs to a team, so list-teams is where the teamId that create-project requires comes from. Teams are identified by UUID only — there is no slug form.

Tool: list-teams Underlying API: GET /teams

list-teams(
  limit?: number,   // 1–100, default 25
  offset?: number   // Pagination offset, default 0
)

The response is the same paginated envelope list-projects returns. Each item includes id, name, slug, memberCount, projectCount, and updatedAt:

{
  "total": 2,
  "offset": 0,
  "limit": 25,
  "returned": 2,
  "hasMore": false,
  "nextOffset": null,
  "items": [
    {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "name": "Platform",
      "slug": "platform",
      "memberCount": 6,
      "projectCount": 12,
      "updatedAt": "2025-01-15T10:00:00Z"
    }
  ]
}

The organization is resolved from the connection you authenticated with, so a caller only ever sees its own organization's teams.


Creating a Project

Use create-project to create a new top-level container for documents. The assigned slug (PRO-*) is returned in the response and is the preferred handle for future calls.

A project must belong to a team. Pass teamId. A project with no team has no URL in the web app, so a human cannot open it or see the documents inside it.

Tool: create-project Underlying API: POST /projects

create-project(
  name: string,
  teamId?: string,     // UUID; required in practice — see below
  description?: string,
  priority?: "LOW" | "MEDIUM" | "HIGH" | "URGENT",
  status?: "NOT_STARTED" | "IN_PROGRESS" | "COMPLETED" | "ARCHIVED"
)

teamId is optional in the tool schema so that a call without one still reaches the server, where it is refused with a 400 that lists the teams in this organization — so a wrong call self-corrects without a prior lookup. That message is bounded by a character budget; when an organization has more teams than fit, the error says how many were omitted and points at list-teams, which is the complete set.

Example workflow:

1. create-project(
     name: "Enterprise Onboarding",
     teamId: "7c9e6679-7425-40de-944b-e07fc1f90ae7",
     priority: "HIGH"
   )
   → returns { slug: "PRO-26", ... }

   // Don't know the team id? Call list-teams, or call without it and
   // read the 400: "At least one team is required. Teams in this
   // organization: Platform (7c9e6679-...), Growth (2b1f...)." Then retry.

2. create-document(
     title: "Onboarding Revamp",
     type: "FEATURE",
     projectId: "PRO-26",
     content: "..."
   )

Updating a Project

Use update-project to change a project's metadata or status by UUID or slug. Only the fields you pass are modified.

Tool: update-project Underlying API: PUT /projects/:projectId

update-project(
  projectId: string,   // PRO-* slug or UUID
  name?: string,
  description?: string,
  priority?: "LOW" | "MEDIUM" | "HIGH" | "URGENT",
  status?: "NOT_STARTED" | "IN_PROGRESS" | "COMPLETED" | "ARCHIVED"
)

Reordering Project Artifacts

Use move-artifact to reorder a root artifact within its project's stack rank — the human-curated priority order shown on the project page. This is a write-scope operation.

Tool: move-artifact Underlying API: POST /projects/:projectId/artifacts/move

move-artifact(
  projectId: string,            // PRO-* slug or UUID
  artifactId: string,           // Artifact to move (PRD-*, PLN-*, FEA-*, or UUID)
  position: "top" | "bottom" | "before" | "after",
  referenceArtifactId?: string  // Required for "before"/"after"; omit for "top"/"bottom"
)

Stack rank is a project-wide, root-level ordering: only top-level documents and features participate, not nested children. Use top / bottom to move to the ends, or before / after with referenceArtifactId to position relative to another artifact. Read sortOrder from list-documents / get-document to see the current order (lower sorts first).

The response echoes the move and reports the new sort order:

{
  "moved": true,
  "artifactId": "FEA-42",
  "position": "before",
  "referenceArtifactId": "FEA-40",
  "newSortOrder": 3
}

On this page