Sessions
A session is one running copy of your stack in the cloud: the template's services, a shell, a browser and your code. This page follows a session through its life: starting it, checking on it, stopping and starting it again, starting it on a schedule, the automatic stops, ending it, resetting its data, switching branches, leaving a cloud session and sharing it with a teammate.
Error codes on this page link to their entry in troubleshooting.md.
Start a session
ciresk dev up # the template for the directory you are in
ciresk dev up app # a named template
ciresk dev up app --preset light --param api-workers=4
ciresk dev up app --remote # a cloud session with no local worktree behind itEach worktree gets its own session. ciresk dev up creates it, or returns the one that is already running for this worktree on this machine, so running it twice gives you the same session back. templates.md says which template a bare ciresk dev up picks.
up waits until every service is ready and prints the session:
- the label and state, with the primary URL (
http://<label>.localhost:<port>) - one URL per
httpport, and127.0.0.1:<local> -> <port>for eachtcpport - the session id, the generation (the number of the last sync of your worktree) and whether it is in sync
- the parameter values and preset, when the template declares parameters
- each service and its state
While it waits, up prints a progress line on stderr every 10 seconds. When no worker is free, the session is pending and the line says what it waits for (a worker starting, for example). --timeout counts from the last time a starting service moved, so a long install is waited through. A service that fails or stalls ends the wait with service_not_ready (exit 1) and names the service; ciresk dev logs <service> shows why.
| Flag | Default | What it does |
|---|---|---|
<template> | picked from the directory | The template in .ciresk/dev.yaml to start. |
--recreate | off | Ends the running session and starts a new one in its place, with the same label. |
--remote | off | A cloud session: it starts from the repository's trunk, not from your worktree, and holds its own edits. See Cloud sessions. |
--lazy | off | Fetches file content on first read instead of before the start. Takes effect only when the template's workspace.materialise is lazy. |
--idle <duration> | the template's or your organization's | This session's idle stop, such as 30m or 2h, within your organization's bounds. See Idle stop. |
--param <name>=<value> | the parameter's default | A template parameter's value. Repeatable. |
--preset <name> | none | One of the template's presets. Its values apply before --param. |
--timeout <duration> | 120s | How long to wait with nothing moving before up gives up with not_ready (exit 7). The session keeps starting. |
--no-wait | off | Returns once the session is created. |
Durations are a whole number with ms, s, m or h; a bare number is seconds. Every command also takes --json for one JSON answer on stdout and --quiet for no progress lines.
Parameters and presets
A template may declare typed parameters and named presets (templates.md). A session's value of each parameter is its default, then the preset's value, then the value you pass with --param. A value the template does not allow is refused with parameter_invalid (exit 2), and each finding says what the parameter takes. The session records the values it runs with; ciresk dev status shows them as parameters: seed=none, api-workers=4 (preset light).
With a session running, ciresk dev up compares only the parameters you name, directly or through --preset:
| You run | Result |
|---|---|
ciresk dev up with no --param or --preset | The running session, as it is. |
A different value of a parameter marked mutable | up ends the session and starts a new one with the new values, and says so. |
| A different value of an immutable parameter | Refused with parameter_immutable (exit 4), naming the parameters. Run the same command with --recreate. |
An agent that calls the dev_session_up MCP tool gets parameters_changed or parameter_immutable instead, and passes recreate: true to apply the change; nothing restarts a session behind your back.
When the template changes
A running session keeps the template it started with. When you edit .ciresk/dev.yaml, ciresk dev status says the file changed, and the next ciresk dev up starts the session again on the new file. Asking a running session for another template (ciresk dev up other) is refused with template_mismatch (exit 4); add --recreate to replace it.
Refusals at up
| Code | Exit | Meaning |
|---|---|---|
no_template | 2 | No .ciresk/dev.yaml, no template of that name, or no way to pick one. |
template_invalid | 2 | The template fails validation; the answer lists every finding (templates.md). |
parameter_invalid | 2 | --param or --preset names something the template does not declare, or a value its type refuses. |
parameter_immutable, template_mismatch | 4 | See above. |
person_session_limit, org_session_limit | 4 | You, or your organization, already hold the most live sessions allowed (10 per person and 100 per organization unless an admin changed them). ciresk dev status --all lists yours; end one you are done with. |
idle_out_of_bounds | 4 | --idle is outside your organization's range; the answer names both bounds. |
session_too_large | 4 | The template reserves more memory or CPUs than your organization allows one session. |
egress_denied | 4 | A required egress row is not allowed (egress.md). |
template_not_published | 4 | Your organization runs only published template versions, and this file is not the promoted one. |
policy_local_sync_denied | 4 | Your organization does not allow syncing a local worktree. Use ciresk dev up --remote. |
budget_exceeded | 5 | Your budget or your organization's is spent (budgets.md). |
cell_session_limit | 8 | The region is full. Try again later. |
Check on a session
ciresk dev status # this worktree's session
ciresk dev status --wait # wait up to 55 s until it is ready
ciresk dev status --all # every live session you own or that is shared with you
ciresk dev open # the primary URL in your browser (--print only prints it)status shows the same lines as up, plus what needs you first (questions and approvals from your agents, and a lifetime warning), the session's health and its next step. It also shows your role on a session shared with you, the organization policy the session runs under and, when you have dotfiles, whether they were applied.
status --all is the list of your sessions: one line each with the session id, label, state and primary URL. It shows live sessions (everything but stopped and failed, so paused and lost sessions are included), yours and those shared with you. The API lists ended ones too, GET /v1/dev/sessions?state=stopped, and started_by=agent or started_by=person keeps only the sessions an agent or a person opened. A person or service key with dev:audit.read lists every session of the organization with scope=org (see /api/dev).
Session states
| State | What it means |
|---|---|
pending | Waiting for a worker. state_reason says why, such as no_capacity, worker_starting or no_worker. |
starting | A worker holds it: it receives your first sync, runs the prepare steps and starts the services. |
ready | Every service is ready. |
degraded | Running, but a service is not well; status names it and its next step. |
disconnected | The worker stopped reporting. Nothing is stopped; it comes back when the worker does. After 15 minutes it becomes lost. |
lost | The worker is gone. The next ciresk dev up in the worktree places the session again on another worker. |
stopping | A stop was asked for and the worker is stopping it. |
paused | A cloud session stopped and kept with its checkpoint, using no compute. ciresk dev start brings it back. |
stopped | Ended. state_reason says why: requested, idle, max_lifetime, budget, kill, access_changed, recreated, checkpoint_expired and others. |
failed | Ended by a failure; state_reason holds its code, such as start_failed or disk_full. |
While a session starts, phase narrows its state down for a client: placing, syncing, starting or ready.
Idle stop
A session is active while your worktree syncs to it, a stream to it (a URL, a port, SSH) is open, or a command names it. After its idle time without activity it stops. A session that gets no first sync within 60 seconds of starting stops too.
The idle time is the template's idle (60 minutes unless the template says otherwise), or your organization's default when it sets one, moved into your organization's range (5 minutes to 8 hours unless an admin narrowed it). ciresk dev up --idle 2h chooses your own for one session; outside the range it is refused with idle_out_of_bounds.
What an idle stop does depends on where the session's code lives:
- A session on your worktree ends: its containers and volumes are deleted, and your code is safe in your worktree. The next
ciresk dev upstarts a fresh one. - A cloud session is paused with its checkpoint (see Stop and start a cloud session), unless your organization set automatic stops to end sessions. In that case a cloud session started without
--idlegets your organization's maximum idle time instead, since it holds the only copy of its edits.
Maximum lifetime
Your organization can cap how long any session runs, whatever its activity (between 1 hour and 7 days; no cap by default). Before the end, by default one hour before, the session raises a need of kind expiring to you, which ciresk dev status, ciresk dev watch and ciresk dev needs show. At the end the session stops like an idle stop: a session on your worktree ends, and a cloud session is paused. ciresk dev up --recreate starts a fresh one with a new lifetime. A budget's hard stop works the same way (budgets.md).
Stop and start a cloud session
ciresk dev stop # checkpoint the workspace, release the compute, keep the session
ciresk dev start # place it again from that checkpointstop and start are for cloud sessions (--remote, or a session started from the console). A session on your worktree has nothing to keep, since its code is on your machine: stop refuses it with not_cloud_writer (exit 1), and ciresk dev down ends it instead.
ciresk dev stop freezes the session, stores a checkpoint of its workspace, and answers once the session is paused, with the time of its checkpoint and the data volumes it did not keep. It waits up to 90 seconds; after that it answers stopping and the session is paused in the background. If the final checkpoint fails, the session pauses on the previous one, at most about a minute older. Stopping a session that already ended answers session_ended.
A paused session keeps:
- its id, so links to it keep working
- its workspace files, as of the checkpoint
- its members and their roles, its device grants, open needs and journal
- its parameter values
- its branch: nothing else writes the session's branch while it is paused
It does not keep running processes, memory, or the data in service volumes such as a database: the checkpoint holds the workspace only, so the template's data volumes start empty and their seed jobs run again. ciresk dev stop names those volumes, and the session's journal records them. Web preview links lapse, and the session's SSH host key changes; ciresk dev ssh and your editor pick up the new key by themselves.
A paused session runs nothing, reserves nothing from your budget and does not count toward the live-session limits. It lasts until 30 days after the session was created, when its checkpoint expires. Before that, by default one hour before, you get an expiring need, and at that time the session ends with state_reason: checkpoint_expired.
ciresk dev start [<template>] [--timeout 120s] [--no-wait]ciresk dev start is ciresk dev up --remote for the worktree's paused session: it is admitted like a new session (your session limits and budget), takes your organization's current policy and a fresh maximum lifetime, and is placed again from its checkpoint, on whichever worker takes it. It keeps the parameters it was created with. ciresk dev up --remote in the same worktree starts it the same way, and ciresk dev up --remote --recreate ends it and starts a new session from the trunk. A session that is already running answers as it is. One that is stopping, has ended, or was paused by the kill switch answers not_paused (exit 1): a killed session never starts again. A plain ciresk dev up, without --remote, does not start a paused cloud session: it starts a session on your worktree.
Retrying stop and start safely
The API's stop, pause and start calls (POST /v1/dev/sessions/{id}/stop, /pause and /start) take an Idempotency-Key header. A retry with the same key, method, path and body within 24 hours gets the first answer again instead of acting twice; the same key with another body is refused with idempotency_key_reused (422), and a key that is empty or over 255 characters with invalid_idempotency_key (400). Without the header the calls still act once per state change. ciresk dev stop and ciresk dev down send a fresh key on every run, and --idempotency-key <key> lets you choose it, so a retried command never stops twice. ciresk dev start and ciresk dev up send their own key.
Start on a schedule
ciresk dev schedule set 08:30 --tz Europe/Copenhagen # this worktree's cloud session, weekdays
ciresk dev schedule set 08:30 --days mon,wed,fri --tz Europe/Berlin
ciresk dev schedule set 09:00 --template app --tz America/New_York # every paused session of yours of this template
ciresk dev schedule show # this worktree's session's schedule
ciresk dev schedule show --all # every schedule of yours
ciresk dev schedule clear [--template app]A schedule has a paused cloud session ready by a local time on the days you choose, so a session you stopped in the evening is waiting for you in the morning. It starts the session 5 minutes before the time, from its checkpoint, through the same admission as ciresk dev start: your session limits and budget apply, and a refusal is recorded instead of a start. A session that is not paused at that time (still running, for example) is left as it is. A start more than 15 minutes late (when your organization was suspended at the time, for example) is skipped and recorded as missed.
| Argument or flag | Default | What it does |
|---|---|---|
<HH:MM> | required | The local time the session is ready by, 00:00 to 23:59. |
--days | weekdays | mon,tue,wed,thu,fri,sat,sun in any combination, weekdays or every-day. |
--tz | the TZ environment variable | An IANA time zone, such as Europe/Copenhagen. Without --tz or TZ the command refuses, since it cannot know your zone. |
--template <name> | this worktree's session | Schedules every paused session of yours with this template name instead. |
Without --template, the schedule belongs to this worktree's session, which must be a cloud session (a session on your worktree is never paused, so set refuses it with not_cloud_writer) and must not have ended (session_ended). Setting a schedule again replaces it, so running the same set twice is harmless; clear removes one and leaves the sessions as they are, and clearing twice is harmless too. A session's schedule is removed at its next start time once the session has ended.
schedule show prints when each schedule is ready, its next start (in UTC) and what its last run did: the sessions it started, the ones it could not start with the reason, or that it was missed. An agent manages schedules through the same capability with the MCP tools; the person who owns the session is the one it starts for.
End a session
ciresk dev downdown ends this worktree's session and releases everything it held. Only the session's owner can end it. A paused session ends too. Afterwards ciresk dev up starts a new one. A cloud session stores a last checkpoint as it stops, so ciresk dev up --remote can still continue it (below). --idempotency-key <key> makes a retried down act once.
Reset data to its seed
ciresk dev reset # every data volume
ciresk dev reset --volume postgres # only some; repeatable
ciresk dev reset --rebuild # empty the volumes and run the seed jobs againA template that declares data (templates.md) gets a snapshot of its data volumes once its seed jobs have completed. reset stops the services that use those volumes, puts the volumes back to the snapshot, typically in about a second, and starts the services again. Running commands get 30 seconds to finish before they are interrupted, and new ones wait until the reset is done. reset waits up to 10 minutes and prints which volumes it restored and which services it restarted.
When a file under the template's data.inputs changes (a new migration, often after a branch switch), the snapshot is stale: ciresk dev status says so and names ciresk dev reset --rebuild, and a reset rebuilds instead of restoring. Nothing resets your data by itself. The session's owner and use members can reset.
Switch branches
Switch branches in your worktree as you always do. The session follows:
- While git holds
.git/index.lock(a checkout, a rebase or a commit in progress), nothing is synced, so the session never sees half a switch. - When the branch changed, the switch is synced as one change once git is done and your worktree has been quiet for 200 milliseconds. The session moves to the new branch first.
- A prepare step whose
inputschanged (a lockfile, for example) runs again, and the services that wait for it restart. Other services take the change through their own watchers.ciresk dev wait --gen <n>waits for all of it. - A change under
data.inputsmarks the seed stale (above).
If another session already works on the new branch, the switch is refused with writer_conflict: the session gets nothing of the new branch, sync pauses, and it is tried again every 10 seconds. A detached HEAD leaves the session on its last branch.
In a cloud session, switch branches with git inside the session.
Cloud sessions
ciresk dev up --remote starts a session from the repository's trunk with no local worktree behind it: the session holds its own edits, which you make with ciresk dev exec, ciresk dev ssh or your editor (editors.md). Use it when you want work to go on without your machine, or when your organization does not allow syncing a local worktree.
Its edits leave the session in these ways:
| Command | What it does |
|---|---|
ciresk dev checkpoint | Stores the workspace as a checkpoint now. The session also takes them on its own as you work. |
ciresk dev push [--base <branch>] [--pr] [--title <text>] | Pushes the checkpoint as one commit to the session's own branch, and with --pr opens a pull request into --base. See git.md. |
ciresk dev stop | Keeps the whole session, paused, until ciresk dev start. |
ciresk dev up --remote after the session ended | Continues the newest ended cloud session of this worktree from its last checkpoint, as a new session on the same branch. A session ended by the kill switch is not continued. Add --recreate to start from the trunk instead. |
Share a session
You can give a member of your organization access to one of your sessions, to follow along or to work in it with you:
ciresk dev share [email protected] --role view
ciresk dev share [email protected] --role use
ciresk dev share --list
ciresk dev share --revoke devm_0192...| Role | What the member can do |
|---|---|
view | Status, logs, the journal (ciresk dev watch), code search, the session's http ports, and the read-only shell (ciresk dev ssh --read-only). No exec, no browser, no data operations, no editor. |
use | Everything but sharing, stopping and syncing: exec, restart, reset, test logins (ciresk dev login <identity> --cookies or --revoke), the browser, the read-write shell and editor, and every declared port. |
Only you, the owner, can share, and only as a person: an agent cannot share a session. The member is named by e-mail address or user id. A share is refused when the role is above your organization's sharing ceiling (sharing_ceiling, exit 4; view unless an admin changed it), when the person is not another member of your organization (not_a_member), when the member may not read every path the session holds (member_view_narrower), or with use on a session whose agents act for you in other products (delegated_session). A session that has ended cannot be shared (session_not_running). admin.md covers the ceiling.
--revoke takes the member id that --list prints. It ends the member's access at once: their open connections close.
Join a session shared with you
The member runs, on their own machine:
ciresk dev attach devs_0192... # the session id the owner gives you
ciresk dev status --all # the session, with your role
ciresk dev ssh <label> # use: the read-write shell
ciresk dev ssh <label> --read-only # view or use: the read-only shell
ciresk dev watch --session devs_0192... --followattach grants your device access and has your daemon serve the session, so its URLs work on your machine too. An attached device never syncs files into the session; only the owner's worktree does. ciresk dev watch follows what happens in the session, one line per event: syncs with the paths they changed, commands and their exit codes, restarts, resets and logins. ciresk dev attach <session_id> --revoke <grant_id> takes your device off again.