Projects
A project is a named container for your code and runtime. You push a code tarball. Computalot stages and builds it durably. After the revision is published, jobs trigger runtime preparation.
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 a push publishes the current content hash, you can submit jobs with "project": "my-project" immediately. ready_for_jobs: true means that the active revision is already warm.
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.
User-upload projects must use OCI with gVisor. Install dependencies and build assets in the Dockerfile. The API rejects host-style init commands, runtime services, and manifest validation commands. Declarative executable and file checks stay available in the manifest.
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 and dataset inputs in data_sources. Declare writable package and model caches in cache_mounts. Enable resumable checkpoints on the jobs themselves. Do not assume that runner-side downloads are reused automatically across tasks.
Updating code
Push a new tarball. The new revision is published immediately. Jobs on that revision can cold-start once while runtime preparation catches up. Use invalidate only to discard old prepared runtimes. Use init only to prepare currently available workers before a burst:
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. Code always goes through /push. A controller-side OCI build returns 202 with a push_ref and status_url after the tarball and build record are durable. Poll that URL (or GET /api/v1/projects/:name/push) until the status is published or failed. The previous published revision stays active in the meantime. Push status includes bounded build diagnostics, and it can include a tarball_diff (added_files, removed_files, changed_files). A 409 includes the active push when another build or initialization is already in flight.
Readiness
can_accept_new_jobs: truemeans that the latest project revision is published. You can submit jobs nowready_for_jobs: truemeans that the active revision is warm enough to admit work without a wait for runtime preparation- It does not prove that your application-level imports or credentials work. 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 the runtime - When
status_messageis not enough, useGET /api/v1/projects/:name/status/details. It adds sanitized diagnostics, log tails, and recovery guidance - After setup changes, run one small smoke job before you submit a large batch
Recovery
If setup fails or the runtime state becomes stale:
- Read
GET /api/v1/projects/:name/statusto see whether the active revision is ready - Read
GET /api/v1/projects/:name/status/detailsfor sanitized diagnostics plus the recommended next step - Correct your project. If necessary, push a new tarball. Then
POST /api/v1/projects/:name/invalidate - Submit a small job normally, or call
POST /api/v1/projects/:name/initto prepare currently available workers
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/v1/projects | Create a project |
GET | /api/v1/projects | List your projects |
GET | /api/v1/projects/:name | Project configuration + readiness |
PUT | /api/v1/projects/:name | Update project metadata (not code) |
DELETE | /api/v1/projects/:name | Delete project (blocked while jobs are active) |
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 | Read readiness |
GET | /api/v1/projects/:name/status/details | Diagnostics for setup errors |
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 a project |