Synsemadocsv0.6.xENES

Operate

Synsema platform (syn)

synsema.com runs Synsema programs for you: a folder goes up, a URL comes back. It is one way to deploy — the same program runs on your own server with synsema serve (Deploy); nothing in the language depends on the platform.

What the platform adds: containers, a URL with HTTPS, secrets kept out of your repository, logs, the audit of every capability check, schedules for jobs, and the human gates of your program (approve, confirm, ask) answered from a dashboard or an API.

Install syn§

syn is itself a Synsema program, so the engine goes first (Quickstart):

curl -fsSL https://synsema.com/cli/install.sh | sh      # macOS, Linux → ~/.local/bin/syn
irm https://synsema.com/cli/install.ps1 | iex           # Windows → %LOCALAPPDATA%\Synsema\syn

Account and login§

syn signup      # no account yet
syn login       # already have one

Both print a page and a short code. Open the page, create the account there if you need one, and approve the code: the terminal signs in. No password goes through the terminal. The token stays in .synsema/syn.json in the current folder — add .synsema/ to your .gitignore.

In CI, skip the login: set SYN_TOKEN (an API token from Settings on synsema.com) and, if you use another site, SYN_SITE.

Deploy§

From the folder of your project:

syn deploy

The first time it creates the project; after that it sends a new version. It prints the ceiling — each require line of your program, granted or denied by your plan — and any secret the program still needs. A program that asks for more than the plan allows does not deploy: the platform refuses it before it runs, instead of letting it fail later.

What travels: every file of the folder except what .gitignore names, plus .git, .env, .synsema, node_modules and target, which are always left out. A file over 1 MB is skipped with a warning; the whole package must stay under 8 MB. syn files shows the list without uploading.

The entry file is the one syn.toml names; without it, the single top-level .syn with a serve on block, or --entry.

Commands§

CommandWhat it does
syn signup / syn loginSign this folder in from the browser (above)
syn deploy [--name N] [--entry E] [--kind web|worker]Upload the folder and queue a deploy
syn statusState, package, ceiling and deploys of this folder's project
syn logs [--follow]What the platform and the runner wrote
syn secrets [set NAME=value …]List the secrets set and the ones still needed, or set them (write-only)
syn env [set NAME=value … [--secret]] [rm NAME …]The environment: list it as .env, set, remove
syn projectsEvery project of the account
syn openThe URL of this project
syn filesWhat would travel, without uploading
syn stopTake the service down; files, secrets and volume stay
syn delete --yesRemove the project and everything the runner holds for it

What a project is§

A folder of Synsema files with an entry file. Its require block is the manifest: the platform grants what the plan allows and refuses anything above it. A deploy runs the program in a container under that ceiling with the audit on, so every capability check lands in the project's audit.

KindRunsURL
websynsema serve <entry><slug>.synsema.app, extra names <slug>-<label>.synsema.app, your own domain on Pro. The program gets them as SYNSEMA_HOST, SYNSEMA_HOSTS, SYNSEMA_HOST_<LABEL>
workersynsema run <entry>, always onnone (a serve on block is served on a loopback port, so its human gates work)
jobsynsema run <entry> in a fresh container per run, on a schedule or when askednone

syn.toml§

Optional, at the root of the folder. It says what the code cannot say about itself; the require block stays the manifest.

name = "Invoice agent"
slug = "invoices"          # the URL name; free to change later
entry = "app.syn"
kind = "web"               # web | worker | job
memory = "512m"            # optional; the plan has a default and a ceiling

[schedule]                 # jobs only, UTC: five cron fields or @hourly, @daily, …
cron = "0 * * * *"

[secrets]                  # what the program needs set, and a line for whoever sets it
LLM_API_KEY = "the key"

[env]                      # variables with a default, shown in clear, editable
LLM_PROVIDER = "anthropic"

[hosts]                    # web only: extra names; label = what it is for
api = "the JSON API"

[volumes]                  # folders the program writes into, kept between deploys
data = "./data"

[provision]                # a URL the platform asks once, at creation; its env seeds the environment
env_url = "https://example.com/token"

Human gates§

A program that reaches approve "Pay 800 USDC to the vendor?" within 2h (or confirm, or ask … with [...]) stops at that line under serve. The question appears in Approvals on synsema.com and in GET /api/v1/approvals; answer it there or with POST /api/v1/approvals/{id}, and the waiting request continues. Past within with no answer it counts as a no. Only the request that reached the gate waits; the rest of the service keeps answering. In a job, or a worker without serve on, nobody can answer, so approve answers no at once — an unattended program cannot grant itself the threshold.

Jobs, schedules and sleep§

POST /api/v1/projects/{id}/run, or from the dashboard. A run never overlaps the previous one and is given up after two hours; each keeps its exit code and the tail of its output.

(the request waits). Free plans sleep after 10 idle minutes; Pro and Enterprise choose. A worker never sleeps.

The API§

Everything syn and the dashboard do is an HTTPS API with a bearer token: synsema.com/docs and the machine-readable openapi.json.