Projects API
Projects organize tasks, workflows, documents, and tables into workspaces. Each project can optionally point to a filesystem working directory, which agents use as their execution context.
Quick Start
Create a project, attach documents as default context, and list tasks within it — the typical setup flow:
// 1. Create a project with a working directory
interface Project {
id: string;
name: string;
description?: string;
workingDirectory?: string;
status: string;
taskCount: number;
}
const projectRes: Response = await fetch("http://localhost:3000/api/projects", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Marketing Site Redesign",
description: "Q2 redesign of the company marketing site",
workingDirectory: "/Users/team/projects/marketing-site",
}),
});
const project: Project = await projectRes.json();
// → { id: "proj-8f3a-4b2c", name: "Marketing Site Redesign", status: "active", ... }
// 2. Upload documents, then bind them as project defaults
// (any task in this project will receive these files as context)
await fetch(`http://localhost:3000/api/projects/${project.id}/documents`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
documentIds: ["doc-brand-guidelines-v3", "doc-sitemap-current"],
}),
});
// → { updated: 2, projectId: "proj-8f3a-4b2c" }
// 3. Create a task inside this project
interface Task {
id: string;
title: string;
status: string;
}
const taskRes: Response = await fetch("http://localhost:3000/api/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: "Audit current homepage for accessibility",
projectId: project.id,
priority: 1,
assignedAgent: "claude-code",
}),
});
const task: Task = await taskRes.json();
// 4. List all tasks in this project to see progress
const tasksRes: Response = await fetch(`http://localhost:3000/api/tasks?projectId=${project.id}`);
const tasks: Task[] = await tasksRes.json();
console.log(`${tasks.length} tasks in ${project.name}`);
tasks.forEach((t: Task) => console.log(` [${t.status}] ${t.title}`)); Base URL
/api/projects
Endpoints
List Projects
/api/projects Retrieve all projects with task count aggregation.
Response Body (Array)
| Field | Type | Req | Description |
|---|---|---|---|
| id | string (UUID) | * | Project identifier |
| name | string | * | Project name |
| description | string | — | Project description |
| workingDirectory | string | — | Filesystem path for agent execution |
| status | enum | * | active, paused, or completed |
| taskCount | number | * | Total tasks in this project |
| createdAt | ISO 8601 | * | Creation timestamp |
| updatedAt | ISO 8601 | * | Last modification |
Fetch all projects to build a workspace selector or dashboard overview:
// List all projects with their task counts
const response: Response = await fetch("http://localhost:3000/api/projects");
const projects: Project[] = await response.json();
// Show active projects with pending work
const active: Project[] = projects.filter((p) => p.status === "active" && p.taskCount > 0);
active.forEach((p) => console.log(`${p.name}: ${p.taskCount} tasks`)); Example response:
[
{
"id": "proj-8f3a-4b2c",
"name": "Marketing Site Redesign",
"description": "Q2 redesign of the company marketing site",
"workingDirectory": "/Users/team/projects/marketing-site",
"status": "active",
"taskCount": 12,
"createdAt": "2026-03-15T09:00:00.000Z",
"updatedAt": "2026-04-02T14:22:00.000Z"
},
{
"id": "proj-c7d1-9e4f",
"name": "API Integration Tests",
"description": "Automated test suite for third-party API integrations",
"workingDirectory": "/Users/team/projects/api-tests",
"status": "active",
"taskCount": 5,
"createdAt": "2026-03-20T11:30:00.000Z",
"updatedAt": "2026-04-01T16:45:00.000Z"
}
] Create Project
/api/projects Create a new project. If a working directory is provided, an environment scan runs automatically in the background.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| name | string | * | Project name (1–100 characters) |
| description | string | — | Project description (max 500 characters) |
| workingDirectory | string | — | Filesystem path (max 500 characters) |
Response 201 Created — New project with status: "active"
Errors: 400 — Zod validation failure
Create a project pointing to a local codebase — Stagent automatically scans the directory for environment details (language, framework, dependencies):
// Create a project with a working directory
// The environment scan starts automatically in the background
const response: Response = await fetch("http://localhost:3000/api/projects", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Marketing Site Redesign",
description: "Q2 redesign initiative",
workingDirectory: "/Users/team/projects/marketing-site",
}),
});
const project: Project = await response.json();
console.log(project.id); // "proj-8f3a-4b2c"
console.log(project.status); // "active" Example response:
{
"id": "proj-8f3a-4b2c",
"name": "Marketing Site Redesign",
"description": "Q2 redesign initiative",
"workingDirectory": "/Users/team/projects/marketing-site",
"status": "active",
"taskCount": 0,
"createdAt": "2026-04-03T10:00:00.000Z",
"updatedAt": "2026-04-03T10:00:00.000Z"
} Get Project
/api/projects/{id} Retrieve a single project by ID.
Response 200 — Project object
Errors: 404 — { "error": "Not found" }
Fetch a specific project to display its details or check status before creating tasks:
// Fetch a project and check if it's ready for work
const response: Response = await fetch("http://localhost:3000/api/projects/proj-8f3a-4b2c");
const project: Project = await response.json();
if (project.status === "active") {
console.log(`${project.name} is active with ${project.taskCount} tasks`);
} Update Project
/api/projects/{id} Update project fields and optionally replace document bindings. Documents are replaced atomically — the old set is removed and the new set is linked.
Request Body (all fields optional)
| Field | Type | Req | Description |
|---|---|---|---|
| name | string | — | Updated name (1–100 chars) |
| description | string | — | Updated description (max 500 chars) |
| workingDirectory | string | — | Updated path (max 500 chars) |
| status | enum | — | active, paused, or completed |
| documentIds | string[] | — | Replace all default document bindings |
Response 200 — Updated project object
Errors: 400 — Validation failure, 404 — Not found
Pause a project to prevent task auto-execution while keeping all resources intact:
// Pause a project — tasks remain but won't auto-execute
await fetch("http://localhost:3000/api/projects/proj-8f3a-4b2c", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: "paused" }),
}); Delete Project
/api/projects/{id} Permanently delete a project and all related resources. Cascades through environment scans, chat data, usage records, tasks, workflows, schedules, documents, and tables.
Response 200 — { "success": true }
Errors: 404 — Not found, 500 — Cascade delete failure
The cascade deletion order ensures foreign key safety:
- Environment data (scans, checkpoints, artifacts, sync ops)
- Chat data (messages, conversations)
- Usage ledger entries
- Task children (logs, notifications, documents, context)
- Document defaults, user tables (with rows, columns, triggers, charts)
- Direct children (documents, tasks, workflows, schedules)
- Project record
Delete a project and everything inside it — this is irreversible:
// WARNING: Cascade deletes all tasks, workflows, schedules, and documents
const res: Response = await fetch("http://localhost:3000/api/projects/proj-8f3a-4b2c", {
method: "DELETE",
});
const { success }: { success: boolean } = await res.json();
console.log(success ? "Project deleted" : "Delete failed"); List Project Documents
/api/projects/{id}/documents List all default document bindings for a project with full document metadata.
Response Body (Array)
| Field | Type | Req | Description |
|---|---|---|---|
| id | string (UUID) | * | Document ID |
| originalName | string | * | Original filename |
| filename | string | * | Stored filename |
| mimeType | string | * | MIME type |
| size | number | * | File size in bytes |
| direction | string | * | input or output |
| status | string | * | Processing status |
| category | string | — | Document category |
Retrieve all documents bound to a project — these are automatically available as context for every task in the project:
// List project documents to verify context is configured
const response: Response = await fetch("http://localhost:3000/api/projects/proj-8f3a-4b2c/documents");
const docs: { direction: string; originalName: string; size: number }[] = await response.json();
docs.forEach((d) => {
const sizeKB: string = (d.size / 1024).toFixed(1);
console.log(`[${d.direction}] ${d.originalName} (${sizeKB} KB)`);
}); Example response:
[
{
"id": "doc-brand-guidelines-v3",
"originalName": "brand-guidelines-v3.pdf",
"filename": "brand-guidelines-v3-1712145600.pdf",
"mimeType": "application/pdf",
"size": 245760,
"direction": "input",
"status": "processed",
"category": "reference"
}
] Replace Project Documents
/api/projects/{id}/documents Replace all default document bindings for a project. Previous bindings are removed and new ones are created atomically.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| documentIds | string[] | * | Array of document UUIDs to bind |
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| updated | number | * | Count of new bindings created |
| projectId | string (UUID) | * | Project ID |
Errors: 400 — documentIds not an array, 404 — Project not found
Replace the entire set of default documents — previous bindings are removed first, then new ones are created:
// Atomically replace project document bindings
const response: Response = await fetch("http://localhost:3000/api/projects/proj-8f3a-4b2c/documents", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
documentIds: ["doc-brand-guidelines-v3", "doc-sitemap-current"],
}),
});
const { updated }: { updated: number } = await response.json();
console.log(`Bound ${updated} documents to project`); Project Statuses
| Status | Description |
|---|---|
| active | Default state. Tasks can be executed. |
| paused | Work suspended. Tasks remain but won’t auto-execute. |
| completed | Work finished. Project archived. |