API Specification
Two surfaces:
- REST endpoints — for the SvelteKit app and external clients (curl, Postman, agents calling REST)
- MCP tools — for AI agents using Model Context Protocol
Both wrap the same underlying operations. MCP is just a translation layer over REST.
REST Endpoints
All under /api/*. Hosted by the SvelteKit app or a dedicated Worker (TBD by rewrite).
Workspaces
POST /api/workspaces
Create a new workspace.
Request: { name?: string }
Response: { id, slug, name, created_at }
GET /api/workspaces/:id
Get current workspace state (snapshot from Y.Doc).
Response includes:
- workspace metadata (id, slug, name, created_at, version)
- settings (Y.Map serialized) — keys masked
- layout, order_state, cv_profile, cl_profile, cloud_keys (with masked keys)
Used for fresh client load before WebSocket sync establishes.
PATCH /api/workspaces/:id
Direct workspace PATCH applies the provided patch through the broker. Prefer
resource-specific endpoints or /ops for new writes.
Behavior: applies provided patch to Y.Doc via the broker.
Jobs
GET /api/workspaces/:id/jobs
List all jobs in the workspace.
Response: Job[]
POST /api/workspaces/:id/jobs
Create a new job.
Request: partial Job (at minimum: { url? | title? })
Response: created Job. Pipeline auto-advances if URL provided.
PATCH /api/workspaces/:id/jobs/:jobId
Update job fields.
Request: partial Job. Special flags:
_statusOnly— fast path for status changes (steward auto-advance)_salaryOnly— fast path for salary + origin (enrichment stage)_tailoredClOnly— fast path for CL section edits_formatOnly— format_overrides only
Response: updated Job.
DELETE /api/workspaces/:id/jobs/:jobId
Delete a workspace job by committing job.delete to the jobs sub-doc.
Workspace Intelligence
Workspace Intelligence is the process-state surface. Browser UI, MCP, and future schedulers should read and command pipeline state here instead of building parallel job/activity interpretations.
GET /api/workspaces/:id/activity
List durable process ledger events.
Query filters: limit, jobId, stage, status, severity, actorClass,
actorId.
Response: { activity, filters, nowMs }.
GET /api/workspaces/:id/intelligence
Return the workspace process projection.
Query filters: activityLimit, jobLimit, jobId.
Response includes:
summary— job count, stage quality, queue pressure, warning countstageSummaries— RADAR / EXTRACT / ENRICH / EVALUATE / TAILOR countsjobStates— per-job stage state, warnings, latest activity, available commandsjobs— resolved workspace job projections for the dashboard intelligence panelactivity— recent process ledger rows
POST /api/workspaces/:id/intelligence/commands/rerun-extract
Queue extraction repair for a job. Clears AI-owned extracted fields, preserves
human-origin fields by default, stamps a process command marker on the job, and
commits a job.update op so open browser tabs can re-run EXTRACT through the
same pipeline actor model.
Request: { jobId, reason?, actorClass?, actorId?, clearHumanFields? }
Response: { command, workspaceId, jobId, requestId, clearedFields, preservedHumanFields }
GET /api/workspaces/:id/process-requests
List durable Workspace Intelligence process requests.
Query filters: limit, jobId, stage, status.
Response: { requests, nowMs }.
POST /api/workspaces/:id/process-requests/claim
Claim queued process requests for an executor. Browser tabs are the preferred worker class; future local/server runners use the same contract.
Request: { workerId, workerClass, stages?, jobIds?, max?, leaseMs? }
Response: { requests, nowMs, unavailable? }, where each claimed request
includes claimToken. Missing queue migrations return an empty unavailable
response rather than a failing response so browser workers stay quiet during
staged deploys.
PATCH /api/workspaces/:id/process-requests/:requestId
Report lifecycle status for a claimed process request. Terminal statuses clear
the process marker in jobs.chain_overrides.__process so stale browser commands
do not re-run after reload.
Request: { status, workerId?, claimToken?, summary?, error?, result? }
Response: { request, nowMs }.
CV / CL operations
POST /api/cv/generate?workspace=:wsid
Persist a tailored CV. The LLM call runs on the client; this endpoint just writes the result.
Request: { job_id, profile: Node, providerId, model, usage, wasFallback } — profile is a full Node-tree snapshot.
Response: { success: true, jobId }. Broadcasts job_update via realtime.
POST /api/cl/generate?workspace=:wsid
Same shape, for cover letter.
Settings (via Yjs ops)
Settings updates flow through the typed op catalog (lib/mutations/src/opsCatalog.ts): settings.update, layout.update, order_state.update. Clients dispatch through the workspace SDK; the REST endpoints accept ops and forward them to the broker.
Chain / cascade
GET /api/chain?workspace=:wsid
Returns ChainConfig: { providerKeys, chains }. This is the execution path — keys are real (unmasked). Mode-gated:
- dev mode: env vars merged in
- production mode: only workspace BYOK keys
Files (R2)
GET /api/files?id=:fileId&workspace=:wsid
Stream a file from R2. Workspace ownership check.
POST /api/files?workspace=:wsid&job_id=:jobId&type=cv|cl|misc
Multipart upload. Stores in R2, updates jobs.files in Y.Doc.
DELETE /api/files?id=:fileId&workspace=:wsid
Delete from R2 + Y.Doc reference.
Health / telemetry
GET /api/health
Returns: { ok: true, ts }.
POST /api/telemetry
Append-only telemetry event log (D1 table). Rate-limited.
MCP Tools
Each REST endpoint becomes an MCP tool. Tool definitions follow the Model Context Protocol Tool Spec.
The MCP server is a separate Cloudflare Worker. It connects to the same D1 + DO + R2 as the SvelteKit app.
Connection
Clients (ChatGPT, Claude, Claude Code, Cursor, etc.) configure the remote MCP server URL:
{
"mcpServers": {
"careervector": {
"url": "https://mcp.careervector.corbet.ch/mcp"
}
}
}
Tool calls still include wsId; workspace ID remains the access credential.
See wiki/content/architecture/MCP-CONNECTORS.md for current ChatGPT/Claude
setup notes and CVL editing workflow guidance.
Tools available
| Tool | Wraps | Description |
|---|---|---|
add_job |
POST /jobs | Add a job by URL or manual fields. Pipeline auto-advances. |
list_jobs |
GET /jobs | Returns all jobs in the workspace |
get_job |
GET /jobs/:id | Returns a single job |
update_job |
PATCH /jobs/:id | Update fields (idempotent for same id+fields) |
delete_job |
DELETE /jobs/:id | Delete |
tailor |
(Yjs op) | Persist a tailored CV/CL snapshot for a job |
get_cv_typst |
Typst render source | Return CV Typst source for agents |
compile_cv_pdf |
Koyeb Typst service | Compile CV Typst source to PDF |
get_cvl_tree |
workspace snapshot | Return exact CVL node paths and editable node data |
patch_node_data |
(Yjs op) | Shallow-merge node data for safe chatbot edits |
update_node |
(Yjs op) | Update a CV/CL quarry node |
add_node |
(Yjs op) | Add a node to the quarry |
move_node |
(Yjs op) | Reorder or reparent nodes |
delete_node |
(Yjs op) | Delete a node |
set_selection |
(Yjs op) | Choose active child variants for rendering |
set_score_criterion |
(settings update) | Update a scoring criterion config |
evaluate_job |
POST /jobs/:id/evaluate (action) | Run scoring evaluation |
list_views |
(settings read) | Returns view definitions |
set_active_view |
(Yjs op on settings) | Switch dashboard view |
get_workspace_summary |
GET /workspaces/:id | Concise summary for context-loading |
list_activity |
GET /activity | Read filtered Workspace Intelligence activity |
get_workspace_intelligence |
GET /intelligence | Read process quality, job states, and queue pressure |
get_job_process_state |
GET /intelligence?jobId=... | Read one job's pipeline state and warnings |
rerun_extract |
POST /intelligence/commands/rerun-extract | Queue extraction repair for a job |
Note: where MCP tools translate to Yjs ops (not REST), the MCP server applies the op via the realtime broker on the client's behalf.
Tool semantics
Per principle 7 (agent API parity):
- Every tool is idempotent (retries don't double-apply)
- Every tool returns a clear success/failure result with explanation
- Every tool emits realtime ops so connected GUI clients see the change
Streaming responses
For long-running operations (tailor, evaluate), MCP supports streaming. The agent sees progress (e.g., "evaluating criterion 3 of 7") rather than waiting for completion.
Error handling
Standard errors:
WorkspaceNotFound— invalid workspace IDJobNotFound— job doesn't exist in this workspaceChainExhaustion— all LLM providers in cascade failedLocked— singleflight lock active (retry after notification)RateLimit— provider 429, retry after delayInvalidShape— Zod validation failed (with detail)
Schema source of truth
All request/response shapes derive from Zod schemas in lib/schemas/:
JobSchema,NodeSchema/LangTreeSchema(CV/CL document trees),WorkspaceSettingsSchema,CloudKeysSchema, etc.
Zod schemas → OpenAPI spec (auto-generated via hono-openapi or similar) → MCP tool definitions.
This means: change a schema, the API spec updates everywhere automatically. No drift.