Projects
A project is a named container for your code and runtime. You push a code tarball, Computalot publishes the revision immediately, and then jobs trigger runtime preparation on demand.
For platform-provided compute primitives that don’t require your own code, use Sealed Recipes instead.
Lifecycle
POST /api/v1/projects → create
POST /api/v1/projects/:name/push → upload code tarball
POST /api/v1/jobs → submit work
POST /api/v1/projects/:name/init → optional: prepare currently available workers
GET /api/v1/projects/:name/status → inspect published vs warm stateGET /api/v1/projects/:name/status is the top-level truth for the active revision. After push publishes the current content hash, you can submit jobs with "project": "my-project" immediately. ready_for_jobs: true just means the active revision is already warm.
Quick Example
# 1. Create
curl -sS "$BASE_URL/api/v1/projects" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "my-project", "remote_dir": "/root/my-project"}'
# 2. Upload (raw binary, NOT multipart)
tar czf code.tar.gz Dockerfile computalot.project.json script.py
curl -sS "$BASE_URL/api/v1/projects/my-project/push" \
-X POST -H "Authorization: Bearer $TOKEN" --data-binary @code.tar.gz
# 3. Submit work immediately if you want
curl -sS "$BASE_URL/api/v1/jobs" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "structured_runner", "runner_command": ["python3", "script.py"], "payload": {"test": true}, "project": "my-project", "timeout_s": 120}'
# 4. Optional: prepare currently available workers ahead of time
curl -sS "$BASE_URL/api/v1/projects/my-project/init" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{}'How It Works
Projects run as sandboxed OCI containers. Push a tarball with your code, a Dockerfile, and a computalot.project.json manifest. Computalot builds a container image and runs tasks in a sandboxed environment.
See Project Manifest for the manifest schema and Setup for the init flow.
If your project runs long ML or evaluation jobs, declare immutable model/dataset inputs in data_sources, declare writable package/model caches in cache_mounts, and enable resumable checkpoints on the jobs themselves. Do not assume runner-side downloads are reused automatically across tasks.
Updating Code
Push a new tarball. The new revision is published immediately; future jobs on that revision may cold-start once while runtime preparation catches up. Use invalidate only if you want to discard old prepared runtimes, and use init only if you want to prepare currently available workers ahead of time:
tar czf code.tar.gz .
curl -sS "$BASE_URL/api/v1/projects/my-project/push" \
-X POST -H "Authorization: Bearer $TOKEN" --data-binary @code.tar.gz
curl -sS "$BASE_URL/api/v1/projects/my-project/invalidate" \
-X POST -H "Authorization: Bearer $TOKEN"
curl -sS "$BASE_URL/api/v1/projects/my-project/init" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{}'Use PUT /api/v1/projects/:name for metadata-only changes. A successful POST /push updates the latest content hash immediately, marks the new revision published but not yet warm, and can include tarball_diff (added_files, removed_files, changed_files) when the previous tarball is available locally. If POST /push returns 409, wait for the current refresh to finish and retry.
Readiness
can_accept_new_jobs: truemeans the latest project revision is published and jobs can be submitted nowready_for_jobs: truemeans the active revision is already warm enough to admit work without waiting for runtime preparation- It does not prove your application-level imports or credentials are valid — use manifest validation checks for that
- After a successful push, expect
can_accept_new_jobs: trueand oftenready_for_jobs: falsewhile the first job or an optional/initprepares runtime - Use
GET /api/v1/projects/:name/status/detailswhenstatus_messageis not enough — it adds sanitized diagnostics, log tails, and recovery guidance - Run one small smoke job after setup changes before submitting a large batch
Recovery
If setup fails or the runtime state becomes stale:
GET /api/v1/projects/:name/statusto confirm the active revision is not readyGET /api/v1/projects/:name/status/detailsfor sanitized diagnostics plus the recommended next step- Fix your project, push a new tarball if needed, then
POST /api/v1/projects/:name/invalidate - Submit a small job normally, or call
POST /api/v1/projects/:name/initif you specifically want to prepare currently available workers ahead of time
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/v1/projects | Create a project |
GET | /api/v1/projects | List your projects |
GET | /api/v1/projects/:name | Project config + readiness |
PUT | /api/v1/projects/:name | Update project metadata (not code) |
DELETE | /api/v1/projects/:name | Delete project (blocked if active jobs) |
POST | /api/v1/projects/:name/push | Upload code tarball |
POST | /api/v1/projects/:name/init | Prepare currently available workers |
PUT | /api/v1/projects/:name/cancel-queued | Cancel queued/planning jobs |
POST | /api/v1/projects/:name/invalidate | Mark for re-init |
GET | /api/v1/projects/:name/status | Check readiness |
GET | /api/v1/projects/:name/status/details | Diagnostics for setup issues |
PUT | /api/v1/projects/:name/kv/:key | Write project-scoped shared state |
GET | /api/v1/projects/:name/kv/:key | Read project-scoped shared state |
DELETE | /api/v1/projects/:name/kv/:key | Delete project-scoped shared state |
GET | /api/v1/projects/:name/stream | SSE stream for all jobs in project |