- Go 64.7%
- TypeScript 34.1%
- CSS 0.7%
- Dockerfile 0.2%
- JavaScript 0.2%
| api | ||
| cmd | ||
| docs | ||
| internal | ||
| migrations | ||
| web | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| Layla TAB Frontend Skeleton.md | ||
| Layla_TAB_Backend_Agent_Prompt_v0.1.md | ||
| Layla_TAB_MVP_Architecture_Spec_v0.1.md | ||
| Makefile | ||
| README.md | ||
Layla TAB backend MVP
Layla TAB is a local-first task platform. This repository implements the protocol-driven Go backend: Task Contracts, generic task routing and leases, Executor enrollment/heartbeat, durable events and SSE, cancellation, recovery watchers, Artifact metadata/S3 presigning, and Feature metadata.
This delivery intentionally does not contain a React frontend, STT/TTS/image-generation implementations, an Executor Manager, GPU scheduling, or plugin upload/runtime code. A missing formal frontend is expected; the root route and JSON APIs remain usable.
Run locally
Requirements: Go 1.26 or newer. SQLite is embedded through a pure-Go driver.
go mod download
$env:LAYLA_DATABASE_PATH = ".\data\layla.db"
go run ./cmd/layla-server
The server listens on :8080 by default. Health and the frozen OpenAPI document are available in the repository:
curl.exe http://localhost:8080/api/v1/health
python -m openapi_spec_validator api/openapi.yaml
SQLite data defaults to ./data/layla.db. Migrations in migrations/*.sql are embedded, applied transactionally in version order, and recorded in schema_migrations at startup.
Configuration
Use .env.example as the complete variable reference. Important groups are:
- HTTP/public URL, database, plugin placeholder directory, request limits, and graceful shutdown.
- Executor heartbeat/offline, task Lease, Claim, watcher, timeout, and SSE settings.
- Optional S3 endpoint/region/bucket/credentials, path style, upload/download URL TTLs, and upload size limit.
Secrets and the database path are never included in /api/v1/config/public. The executable reads actual process environment variables and does not implicitly load .env.
Docker and optional MinIO
docker compose up --build
The default Compose deployment starts with Artifact object storage unconfigured. To use the optional MinIO profile, set the S3 variables so the backend and MinIO agree, then start the profile:
$env:LAYLA_S3_ENDPOINT = "http://minio:9000"
$env:LAYLA_S3_REGION = "us-east-1"
$env:LAYLA_S3_BUCKET = "layla-artifacts"
$env:LAYLA_S3_ACCESS_KEY = "layla"
$env:LAYLA_S3_SECRET_KEY = "layla-development-secret"
docker compose --profile minio up --build
Artifact bytes never pass through the Go server. Clients upload/download through short-lived S3-compatible presigned URLs. Leaving all S3 settings empty is valid; storage-dependent endpoints then return 503.
Minimal API walkthrough
Create a Task Contract before creating tasks. This generic example uses a permissive object result; production contracts should be specific.
curl.exe -X POST http://localhost:8080/api/v1/admin/task-contracts `
-H "Content-Type: application/json" `
-d '{"task_type":"demo.echo","task_version":"1.0","name":"Demo Echo","input_schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object"},"output_schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object"},"artifact_inputs":[],"artifact_outputs":[],"source":"local"}'
Create an Executor enrollment code. Save registration_code from this response; the plaintext code is returned only when the code is created. An identical enroll retry returns the same credentials without consuming another use.
curl.exe -X POST http://localhost:8080/api/v1/admin/executor-enrollment-codes `
-H "Content-Type: application/json" `
-d '{"name":"local-simulator","expires_in_seconds":3600,"max_uses":1}'
Run the protocol simulator with that code. It enrolls, heartbeats, claims, reports indeterminate progress, acknowledges cancellation commands, and completes one compatible task without running any AI workload:
go run ./cmd/layla-executor-simulator `
-enrollment-code "<registration_code>" `
-task-type demo.echo -task-version 1.0 `
-result '{"echo":"simulated"}'
Create a compatible generic task before or after the simulator enrolls. Re-run the simulator with the one-time executor_token it printed:
curl.exe -X POST http://localhost:8080/api/v1/tasks `
-H "Content-Type: application/json" `
-H "Idempotency-Key: demo-001" `
-d '{"protocol_version":"1.0","task_type":"demo.echo","task_version":"1.0","spec":{"message":"hello"},"options":{"max_attempts":2},"routing":{"mode":"capability"}}'
go run ./cmd/layla-executor-simulator `
-token "<executor_token>" `
-task-type demo.echo -task-version 1.0 `
-result '{"echo":"simulated"}'
For manual protocol calls, use Authorization: Bearer <executor_token> with:
POST /api/v1/executor/heartbeatPOST /api/v1/executor/tasks/claimPOST /api/v1/executor/tasks/{id}/eventsPOST /api/v1/executor/tasks/{id}/completeor/failPOST /api/v1/executor/commands/{id}/ack
The exact payloads and every implemented route are defined in api/openapi.yaml. Task streams use GET /api/v1/tasks/{id}/stream; SSE id values are durable task-scoped cursors and can be returned in Last-Event-ID after reconnecting.
Verify
go fmt ./...
go vet ./...
go test ./... -count=1
go test -race ./... -count=1
python -m openapi_spec_validator api/openapi.yaml
See docs/backend-development.md for implementation boundaries and docs/IMPLEMENTATION_STATUS.md for actual phase/test status and known host limitations.