Projects
The projects namespace wraps the Projects REST resource — pipeline-driven workflows expanded from a versioned template into phases (tasks), steps (subtasks), and per-execution attempts, with versioned artifacts per phase.
For the object shapes, error codes, and the endpoints the SDK doesn't wrap yet (gate resolution, phase retrigger, artifact revert, edit sessions — all REST-only), see the wire-level reference. For the model, see Concepts → Project.
Auth. Every route in this namespace requires the control plane's
x-catentio-sessionheader, which this SDK never sends. NeitherapiKeymode nor Bearer-session mode authenticates here. See SDKs → Auth: what actually works.
Namespace
catentio.projects — the surface, grouped by intent:
// Basics
catentio.projects.list()
catentio.projects.get(id)
catentio.projects.create(input)
// Attachments
catentio.projects.listAttachments(id)
catentio.projects.addAttachment(id, input)
// Drill-down
catentio.projects.listTasks(id)
catentio.projects.getTask(id, taskId)
catentio.projects.listSubtasks(id, taskId)
catentio.projects.getSubtask(id, taskId, subtaskId)
catentio.projects.listAttempts(id, subtaskId)
catentio.projects.listArtifacts(id)
catentio.projects.listEvents(id)
// Cost
catentio.projects.cost(id)
// Lifecycle
catentio.projects.pause(id)
catentio.projects.resume(id)
catentio.projects.abandon(id)
catentio.projects.runStep(id, input?)
catentio.projects.retrySubtask(id, subtaskId)
Method names are camelCase, but the payloads are the raw wire shapes with snake_case keys — list calls return { data: [...], meta: {...} }, single-object calls return the bare object.
Core methods
projects.list / projects.get
const page = await catentio.projects.list();
for (const p of page.data) {
console.log(p.id, p.status, p.cost_total_usd);
}
const p = await catentio.projects.get('sustainable-urban-farming-explainer-3f9a1c2b');
Project ids are <title-slug>-<8 hex chars> — the title lowercased with non-alphanumerics collapsed to dashes (truncated to 48 chars), plus a random 8-character hex suffix (app/runtime/api.py, POST /v1/projects). status is one of planning, active, paused, completed, abandoned.
projects.create
Signature. catentio.projects.create(input, token?): Promise<Project>
Spawns a project and expands its template atomically — the response is a fully planned project.
const project = await catentio.projects.create({
title: 'Sustainable urban farming explainer',
workflow_slug: 'content',
brief: 'A practical explainer on sustainable urban farming. Tone: hands-on.',
cost_budget_usd: '5.00', // optional, USD
// workflow_version: 2, // optional; omitted = latest active
});
title, workflow_slug, and brief (a plain string — not an object) are required. Ownership is forced from your credential server-side. An archived template or an unresolvable step binding fails with 400 before any row is created.
Drill-down
Project → tasks (phases) → subtasks (steps) → attempts:
const tasks = (await catentio.projects.listTasks(project.id)).data;
const research = tasks.find((t) => t.phase_slug === 'research');
const subtasks = (await catentio.projects.listSubtasks(project.id, research.id)).data;
const attempts = (await catentio.projects.listAttempts(project.id, subtasks[0].id)).data;
Task and subtask ids are UUIDs. Each attempt carries attempt_number, attempt_reason, status (pending / running / succeeded / failed), output, cost_usd, duration_ms, and — for agent steps — the child_run_id of the run it spawned.
Artifacts and events
const artifacts = (await catentio.projects.listArtifacts(project.id)).data;
const events = (await catentio.projects.listEvents(project.id)).data;
listArtifacts returns each phase's current pipeline-artifact version (the wire default current_only=true; the SDK doesn't expose the full-history flag — use the REST endpoint with ?current_only=false). Events are the project's full pipeline timeline.
Cost
const breakdown = await catentio.projects.cost(project.id);
console.log(breakdown.total_usd, breakdown.budget_usd, breakdown.budget_burn);
Amounts are USD decimal strings. See Cost & budgets.
Lifecycle
await catentio.projects.pause(pid); // park at status=paused; autodrive skips it
await catentio.projects.resume(pid); // crash-recover + back to active
await catentio.projects.abandon(pid); // terminal
await catentio.projects.runStep(pid); // advance exactly one eligible step
await catentio.projects.retrySubtask(pid, subtaskId); // queue a manual_retry attempt
retrySubtask rejects with a 409 when an attempt is already queued for the subtask. The SDK method doesn't take an addendum brief — pass ?addendum_brief= on the REST endpoint if you need one.
Not in the SDK (REST-only)
PATCH /v1/projects/{id}— edittitle/cost_budget_usd.POST …/subtasks/{sid}/resolve-gate— gate approval.POST …/phases/{slug}/retrigger,POST …/phases/{slug}/revert-artifact,POST …/edit-sessions(+/approve) — the backtrack surface.
Errors
FastAPI-shaped errors ({ detail: … }) surface with the HTTP status: 400 validation (missing fields, unknown/archived template, bad bindings), 404 unknown ids, 409 conflicts (queued retry, in-flight phase), 502 runtime unreachable.
Next
- API → Projects — full wire-level reference including the REST-only actions.
- Workflows — what projects expand from.
- Runs — the sessions agent steps spawn.