Project config
Three optional files in a workspace’s .serin folder tell Serin what detection can’t. Commit them with the project. Values of environment variables never go in them.
.serin/run.json
How the workspace runs. Targets listed here come first and replace detected ones with the same id.
{
"default": "api",
"targets": [
{ "id": "api", "command": "uv run api", "cwd": "backend", "port": 9000 }
]
}
| Field | Meaning |
|---|---|
default | The target Run starts. The one you ran last wins over it. |
detect | false uses only the targets listed here. Default true. |
targets[].command | Required. The shell command that starts it. |
targets[].id | Stable name for the target. |
targets[].name | What the Run chip shows. Defaults to the id. |
targets[].cwd | Folder to run in, inside the workspace. Default . |
targets[].port | The port it would like. Serin may pick another. |
targets[].install | A command to run first, like installing packages. |
targets[].web | false for a worker with nothing to preview. Default true. |
targets[].env | Extra environment variables, name to value. |
targets[].framework | A label, like fastapi. |
Every target gets PORT and HOST (127.0.0.1). Use them in your command, as the FastAPI starter does:
{
"default": "api",
"detect": false,
"targets": [{
"id": "api",
"install": "(test -d .venv || python3 -m venv .venv) && .venv/bin/pip install -q -r requirements.txt",
"command": ".venv/bin/uvicorn main:app --reload --host 127.0.0.1 --port $PORT",
"port": 8000
}]
}
.serin/serin.json
What the project needs: how to publish it, which environment variables it expects, and its ports.
{
"publish": { "dir": "dist", "command": "npm run build", "spa": true, "site": "my-site" },
"env": {
"DATABASE_URL": "Postgres connection string",
"SENTRY_DSN": { "description": "Error reporting", "optional": true }
},
"ports": [3000]
}
publish
| Field | Meaning |
|---|---|
dir | The folder whose files become the site, inside the workspace. Default: found from the framework. |
command | The build. Default: the build script in package.json. false publishes dir as it is. |
cwd | Where the build runs and package.json is read. Default . |
spa | true answers unknown paths with /index.html. Default: on when the build has exactly one HTML page. |
site | The site name to publish to when none is given. |
More on how builds are found in Publish.
env and ports
env names the variables the project needs, each with a description. It can also be a list of names. "optional": true means the project runs without it. The app lists any that have no value yet under Needed by This Project. ports lists the ports the project uses.
.serin/agent.json
What proves an agent’s edit didn’t break anything.
{ "verify": ["npx tsc --noEmit"] }
Each verify command runs in the workspace. An agent’s edit, write_file and approved propose_edit apply only when they all pass. Check Project in the Problems panel runs the same list, and reads file:line:col errors from their output.
Without the file, Serin runs tsc --noEmit when there’s a tsconfig.json, plus Vitest or Jest on tests related to the changed files. Check Project also runs pyright for Python when it’s installed.
| Starter | verify |
|---|---|
| Next.js, Vite + React | npx tsc --noEmit |
| Astro blog | npx astro build |
| Express API | node --test |
| FastAPI | .venv/bin/python -m py_compile main.py |
| Website | node --check script.js |
Environment variables
Set them in the app under Environment Variables. The values stay on the server, outside the workspace, so they never show up in the file list, git status, a checkpoint or a copy of the workspace.
- New terminals and run targets get them. Restart a running target to pick up a change.
- Import copies the values from a
.envfile in the workspace. Nothing reads.envfiles on its own. The app warns when Git doesn’t ignore one. - Names use letters, digits and
_, and don’t start with a digit. - Hide from Agents keeps a variable out of terminals an agent opens for itself. An agent you start in your own terminal still sees it, like any program there.