Files API
Read, write, and delete lab files. Backs the local-agents and CLI workflows.
Files
Read and write any file in a lab — notes, papers, scripts, datasets. Authenticated callers see the same tree the orchestrator and Files panel see. When the lab has a linked GitHub repo with auto-push enabled, write/delete operations also commit to the repo.
Base URL: https://hubify.com/api/v1
Required scope:
lab:<slug>:rforGETlab:<slug>:rwforPOST/PATCH/DELETE
The wildcard lab:*:r / lab:*:rw / lab:*:admin also works.
List files in a lab
GET /api/v1/files?labId=<id>
Returns the full file tree:
{
"files": [
{
"_id": "k57...",
"labId": "k88...",
"name": "today.md",
"path": "/notes/today.md",
"type": "file",
"parentPath": "/notes",
"mimeType": "text/markdown",
"size": 4123,
"content": "...",
"createdAt": 1714368000000,
"updatedAt": 1714368042000
}
],
"total": 1
}
Read a single file
GET /api/v1/files?labId=<id>&path=/notes/today.md
Returns just that file's record. 404 if the path does not exist.
Create or overwrite a file
POST /api/v1/files
Content-Type: application/json
{
"labId": "<id>",
"path": "/notes/today.md",
"content": "# Today\n\nMeeting notes...",
"mimeType": "text/markdown"
}
If a file already exists at path, this updates its content. Otherwise it creates the file (and the implied parent folder structure). MIME type is inferred from the extension if omitted.
Response:
{ "created": true, "path": "/notes/today.md", "fileId": "k7...", "bytes": 28 }
Update content only
PATCH /api/v1/files
Content-Type: application/json
{ "labId": "<id>", "path": "/notes/today.md", "content": "..." }
Same shape as POST, but returns 404 if no file exists at path. Use this when you specifically don't want to create new files by accident.
Delete a file
DELETE /api/v1/files?labId=<id>&path=/notes/today.md
Response:
{ "deleted": true, "path": "/notes/today.md" }
GitHub round-trip
When a lab has a GitHub repo linked and gitAutoPushOnEdit is true (toggle in Lab Settings):
POST/PATCHwrites alsoPUT /repos/.../contents/{path}on GitHubDELETEalsoDELETE /repos/.../contents/{path}on GitHub
The Hubify request returns success as long as the Convex write succeeded — GitHub push errors are logged on the lab's activity feed but don't fail the API call. Use GET /api/v1/sync to confirm the latest sync SHA.
See Local Agents guide for the full bidirectional flow.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing labId / path / content |
| 401 | Invalid or missing API key |
| 403 | Key lacks lab:<slug>:r (GET) or lab:<slug>:rw (write) |
| 404 | No file at the given path (GET / PATCH / DELETE) |
| 429 | Rate limit (120/min read, 30/min write) |
| 500 | Convex error — check response body |