API reference

Policy

The organization's dev policy: lifecycle limits, budgets, egress ceilings, templates and extras.

GET/v1/dev/policy

Get the policy

The organisation's current dev policy.

Permission: dev:policy.read

Response200 OK

budgetobject
Usage budgets in ci's cost unit, one vCPU-second. Both null by default: no budget. A session reserves 15 minutes ahead; one the budget cannot pay for 5 minutes is refused (403 budget_exceeded), and a running one whose paid time ends with nothing more to reserve stops with state_reason budget and session.stop_requested, announced at least 5 minutes before by session.budget_warning {stops_at, scope, limit_units, resets_at, next} and one need of kind budget from Ciresk dev to the session's owner, which ciresk dev status, watch and needs and dev_session_needs show and which clears when the session ends. Changed only through dev.policy.set, audited per field.
budget.org_month_unitsinteger or null
what the organisation's sessions use in a UTC calendar month
budget.person_day_unitsinteger or null
what one person's sessions, their agents' included, use in a UTC day
clipboardstring
OSC 52 over the terminal streams (ssh channels with a pty or a login shell, dev exec): allow mints the ticket capability clipboard, under which set sequences pass and are audited dev.clipboard.copied, and queries pass only with transfer_up too (a query's answer is an upload); deny strips both, audited dev.clipboard.denied with the byte count, never the contentOne of allow, deny
dotfilesobject
Whether a person's dotfiles repository is applied in the sessions they own. Left out it reads as allow with any host: nothing runs until a person sets a repository. deny skips them at every new session and refuses dev.dotfiles.set (403 dotfiles_off).
dotfiles.accessstring
One of allow, deny
dotfiles.hostsarray of strings
when not empty, the repository's host must be one of these: an exact host or *.suffix, as in egress.yaml (403 dotfiles_host_not_allowed)
downloadstring
One of allow, deny
egressobject
The organisation's ceilings over every template's egress rows, applied at dev up: a row they do not cover is dropped, a required one is 422 egress_denied. Validated at dev.policy.set: every host is one egress.yaml takes, no port is 0. A changed ceiling reaches a running session at its next renewal, never wider than the rows it was compiled with.
egress.agentarray of objects or null
the ceiling on top of session for a session an agent principal starts (reason agent_policy); unset is empty, so such a session reaches only the registry cache
egress.agent[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.agent[].portsarray of integers
443 when empty
egress.agent_exitboolean
an agent's exec or ssh in a person's session goes out through its own exit (127.0.0.1:3131) under agent, enforced by Landlock; on by default, so an agent reaches the read-only registry cache and the session's MCP gateway until agent lists rows; false shares the person's set
egress.sessionarray of objects or null
when set, the ceiling for every session (reason org_policy); unset changes nothing
egress.session[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.session[].portsarray of integers
443 when empty
lifecycleobject
How long and how many dev sessions the organisation runs. A field left out takes its default, so every organisation is limited without writing a policy; null switches an optional limit off. A session past max_lifetime_secs stops with state_reason max_lifetime and session.stop_requested; lifetime_warning_secs before, its owner gets one need of kind expiring (dev.sessions.needs.raise), which ciresk dev status, watch and needs and dev_session_needs show. Changed only through dev.policy.set, audited per field.
lifecycle.auto_stopstring
what an idle stop, the budget's hard stop and max_lifetime_secs do to a cloud-writer session: pause keeps it with its checkpoint for dev.sessions.start, end ends it; a local writer always endsOne of pause, end
lifecycle.idle_max_secsinteger
at least idle_min_secs; idle_secs and a person's idle_secs lie between; a template that names an idle over it is refused at dev.sessions.up (422 template_invalid, finding idle_over_policy with its next), the 60 min default is pulled down
lifecycle.idle_min_secsinteger
lifecycle.idle_secsinteger or null
the idle stop when the person names none; null is the template's (60 min unless it says)
lifecycle.lifetime_warning_secsinteger
shorter than max_lifetime_secs
lifecycle.max_lifetime_secsinteger or null
from create to stop, whatever the activity; null, the default, is no limit; ciresk dev policy preset no-local-checkout suggests 86400
lifecycle.max_session_cpus_milliinteger or null
the largest cpu reservation, in thousandths of a cpu; null is the worker's own limit (422 session_too_large)
lifecycle.max_session_memory_bytesinteger or null
the largest memory reservation one template may declare; null is the worker's own limit (422 session_too_large)
lifecycle.sessions_per_orginteger
live sessions of the organisation, never above the installation's own ceiling (409 org_session_limit)
lifecycle.sessions_per_personinteger
live sessions one person and their agents hold; at most sessions_per_org (409 person_session_limit)
local_syncstring
One of allow, deny
lockedobject
The organisation's overlay over every repository's dev file, applied at compile; a field left out changes nothing. Validated at dev.policy.set (422 policy_invalid).
locked.container_cpus_milliinteger or null
a cap on every container's cpus, in thousandths of a cpu
locked.container_memory_bytesinteger or null
a cap on every service's, prepare step's and the shell's memory, memory_ceiling and memory_max
locked.egressarray of objects or null
when set, the session's egress rows exactly (the template's dropped); egress.yaml stays the ceiling
locked.egress[].hoststringRequired
locked.egress[].portsarray of integersRequired
locked.egress[].purposestringRequired
locked.egress[].requiredbooleanRequired
locked.imagesarray of strings
pinned references, host/path[:tag]@sha256:<64 hex>, each repository once; a service's or the browser's image of that repository gets this reference
modelsobject
The model proxy in a session: with allow, dev up sets the session's models to {default_model}, so the worker points every container's agents at its front on https://127.0.0.1:3130 with a placeholder key and the installation CA. Off by default, an extra; a policy written before it reads as off.
models.allowboolean
models.default_modelstring or null
the model an agent gets when it names none; null leaves it to the gateway's default
pathsarray of objects
paths[].prefixstringRequired
a directory prefix ending in /, relative, no..; the longest match decides
paths[].readarray of stringsRequired
groups that may read; write implies read
paths[].writearray of stringsRequired
port_forwardstring
One of allow, deny
retentionobject
How long dev keeps what it records, in days from 1 to 3650; a policy written before it reads the defaults. A session in stopped or failed goes with its journal, grants, members, needs, ledger rows and ci records once its end is older than ended_sessions_days; a connection window or egress decision once its window_to is older than its own field. Audit records keep core/audit's retention (12 months by default); checkpoints the bucket's 30 days. Changed only through dev.policy.set, audited per field.
retention.connections_daysinteger
retention.egress_decisions_daysinteger
retention.ended_sessions_daysinteger
sharingstring
One of false, view, use
sshstring
One of allow, deny
ssh_execstring
ssh exec channels with no pty before them (VS Code's, Cursor's and Zed's Remote-SSH servers, JetBrains' backend, ssh host <cmd> without -t, legacy scp and rsync): deny adds the restriction no_ssh_exec to every ticket, under which the worker refuses such a channel, audited dev.session.transfer {channel: exec, allowed: false}; an exec with a pty, a shell, sftp and forwards are unchanged. A field left out reads as allowOne of allow, deny
templatesstring
published: dev up admits only a promoted template version (403 template_not_published)One of any, published
uploadstring
One of allow, deny
versionintegerRequired
webstring
the ceiling for the session view in the browser: off refuses dev.sessions.web_handoff and every gateway renewal, so an open preview stops within 20 s; owners and members only, never the whole organisation or the publicOne of false, view, use
web_idestring
VS Code Web in the session: on mints ide_ro for every role and ide for use and the owner; code-server runs with downloads and uploads disabled unless the ticket holds transfer_down and transfer_up. Off by default, an extraOne of off, on
workersstring
Where the organisation's sessions run: cell, on hosts ci's factory starts for it or its admin enrolled; customer, only on hosts its admin enrolled with dev.workers.enrol, in its own network, so the factory never sees it in dev.workers.demand, dev.workers.provision refuses it (409 customer_workers) and a pending session with no online worker says no_worker. A policy written before it reads as cell.One of cell, customer
curl "$CIRESK_API/v1/dev/policy" \
  -H "Authorization: Bearer $CIRESK_KEY"
PUT/v1/dev/policy

Set the policy

Write a new version of the organisation's dev policy.

A person with dev:policy.write. The version must be the current one plus one (409 policy_version_conflict). A narrowing reaches running sessions through their tickets at the next renewal (20 s); a widening applies to new sessions. The lifecycle limits apply to sessions created after the version, except the warning window and the session counts, which read the current version. Every version is kept and audited with its diff, a nested field named by its path (lifecycle.idle_max_secs).

Permission: dev:policy.write

Request body

budgetobject
Usage budgets in ci's cost unit, one vCPU-second. Both null by default: no budget. A session reserves 15 minutes ahead; one the budget cannot pay for 5 minutes is refused (403 budget_exceeded), and a running one whose paid time ends with nothing more to reserve stops with state_reason budget and session.stop_requested, announced at least 5 minutes before by session.budget_warning {stops_at, scope, limit_units, resets_at, next} and one need of kind budget from Ciresk dev to the session's owner, which ciresk dev status, watch and needs and dev_session_needs show and which clears when the session ends. Changed only through dev.policy.set, audited per field.
budget.org_month_unitsinteger or null
what the organisation's sessions use in a UTC calendar month
budget.person_day_unitsinteger or null
what one person's sessions, their agents' included, use in a UTC day
clipboardstring
OSC 52 over the terminal streams (ssh channels with a pty or a login shell, dev exec): allow mints the ticket capability clipboard, under which set sequences pass and are audited dev.clipboard.copied, and queries pass only with transfer_up too (a query's answer is an upload); deny strips both, audited dev.clipboard.denied with the byte count, never the contentOne of allow, deny
dotfilesobject
Whether a person's dotfiles repository is applied in the sessions they own. Left out it reads as allow with any host: nothing runs until a person sets a repository. deny skips them at every new session and refuses dev.dotfiles.set (403 dotfiles_off).
dotfiles.accessstring
One of allow, deny
dotfiles.hostsarray of strings
when not empty, the repository's host must be one of these: an exact host or *.suffix, as in egress.yaml (403 dotfiles_host_not_allowed)
downloadstring
One of allow, deny
egressobject
The organisation's ceilings over every template's egress rows, applied at dev up: a row they do not cover is dropped, a required one is 422 egress_denied. Validated at dev.policy.set: every host is one egress.yaml takes, no port is 0. A changed ceiling reaches a running session at its next renewal, never wider than the rows it was compiled with.
egress.agentarray of objects or null
the ceiling on top of session for a session an agent principal starts (reason agent_policy); unset is empty, so such a session reaches only the registry cache
egress.agent[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.agent[].portsarray of integers
443 when empty
egress.agent_exitboolean
an agent's exec or ssh in a person's session goes out through its own exit (127.0.0.1:3131) under agent, enforced by Landlock; on by default, so an agent reaches the read-only registry cache and the session's MCP gateway until agent lists rows; false shares the person's set
egress.sessionarray of objects or null
when set, the ceiling for every session (reason org_policy); unset changes nothing
egress.session[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.session[].portsarray of integers
443 when empty
lifecycleobject
How long and how many dev sessions the organisation runs. A field left out takes its default, so every organisation is limited without writing a policy; null switches an optional limit off. A session past max_lifetime_secs stops with state_reason max_lifetime and session.stop_requested; lifetime_warning_secs before, its owner gets one need of kind expiring (dev.sessions.needs.raise), which ciresk dev status, watch and needs and dev_session_needs show. Changed only through dev.policy.set, audited per field.
lifecycle.auto_stopstring
what an idle stop, the budget's hard stop and max_lifetime_secs do to a cloud-writer session: pause keeps it with its checkpoint for dev.sessions.start, end ends it; a local writer always endsOne of pause, end
lifecycle.idle_max_secsinteger
at least idle_min_secs; idle_secs and a person's idle_secs lie between; a template that names an idle over it is refused at dev.sessions.up (422 template_invalid, finding idle_over_policy with its next), the 60 min default is pulled down
lifecycle.idle_min_secsinteger
lifecycle.idle_secsinteger or null
the idle stop when the person names none; null is the template's (60 min unless it says)
lifecycle.lifetime_warning_secsinteger
shorter than max_lifetime_secs
lifecycle.max_lifetime_secsinteger or null
from create to stop, whatever the activity; null, the default, is no limit; ciresk dev policy preset no-local-checkout suggests 86400
lifecycle.max_session_cpus_milliinteger or null
the largest cpu reservation, in thousandths of a cpu; null is the worker's own limit (422 session_too_large)
lifecycle.max_session_memory_bytesinteger or null
the largest memory reservation one template may declare; null is the worker's own limit (422 session_too_large)
lifecycle.sessions_per_orginteger
live sessions of the organisation, never above the installation's own ceiling (409 org_session_limit)
lifecycle.sessions_per_personinteger
live sessions one person and their agents hold; at most sessions_per_org (409 person_session_limit)
local_syncstring
One of allow, deny
lockedobject
The organisation's overlay over every repository's dev file, applied at compile; a field left out changes nothing. Validated at dev.policy.set (422 policy_invalid).
locked.container_cpus_milliinteger or null
a cap on every container's cpus, in thousandths of a cpu
locked.container_memory_bytesinteger or null
a cap on every service's, prepare step's and the shell's memory, memory_ceiling and memory_max
locked.egressarray of objects or null
when set, the session's egress rows exactly (the template's dropped); egress.yaml stays the ceiling
locked.egress[].hoststringRequired
locked.egress[].portsarray of integersRequired
locked.egress[].purposestringRequired
locked.egress[].requiredbooleanRequired
locked.imagesarray of strings
pinned references, host/path[:tag]@sha256:<64 hex>, each repository once; a service's or the browser's image of that repository gets this reference
modelsobject
The model proxy in a session: with allow, dev up sets the session's models to {default_model}, so the worker points every container's agents at its front on https://127.0.0.1:3130 with a placeholder key and the installation CA. Off by default, an extra; a policy written before it reads as off.
models.allowboolean
models.default_modelstring or null
the model an agent gets when it names none; null leaves it to the gateway's default
pathsarray of objects
paths[].prefixstringRequired
a directory prefix ending in /, relative, no..; the longest match decides
paths[].readarray of stringsRequired
groups that may read; write implies read
paths[].writearray of stringsRequired
port_forwardstring
One of allow, deny
retentionobject
How long dev keeps what it records, in days from 1 to 3650; a policy written before it reads the defaults. A session in stopped or failed goes with its journal, grants, members, needs, ledger rows and ci records once its end is older than ended_sessions_days; a connection window or egress decision once its window_to is older than its own field. Audit records keep core/audit's retention (12 months by default); checkpoints the bucket's 30 days. Changed only through dev.policy.set, audited per field.
retention.connections_daysinteger
retention.egress_decisions_daysinteger
retention.ended_sessions_daysinteger
sharingstring
One of false, view, use
sshstring
One of allow, deny
ssh_execstring
ssh exec channels with no pty before them (VS Code's, Cursor's and Zed's Remote-SSH servers, JetBrains' backend, ssh host <cmd> without -t, legacy scp and rsync): deny adds the restriction no_ssh_exec to every ticket, under which the worker refuses such a channel, audited dev.session.transfer {channel: exec, allowed: false}; an exec with a pty, a shell, sftp and forwards are unchanged. A field left out reads as allowOne of allow, deny
templatesstring
published: dev up admits only a promoted template version (403 template_not_published)One of any, published
uploadstring
One of allow, deny
versionintegerRequired
webstring
the ceiling for the session view in the browser: off refuses dev.sessions.web_handoff and every gateway renewal, so an open preview stops within 20 s; owners and members only, never the whole organisation or the publicOne of false, view, use
web_idestring
VS Code Web in the session: on mints ide_ro for every role and ide for use and the owner; code-server runs with downloads and uploads disabled unless the ticket holds transfer_down and transfer_up. Off by default, an extraOne of off, on
workersstring
Where the organisation's sessions run: cell, on hosts ci's factory starts for it or its admin enrolled; customer, only on hosts its admin enrolled with dev.workers.enrol, in its own network, so the factory never sees it in dev.workers.demand, dev.workers.provision refuses it (409 customer_workers) and a pending session with no online worker says no_worker. A policy written before it reads as cell.One of cell, customer

Response200 OK

budgetobject
Usage budgets in ci's cost unit, one vCPU-second. Both null by default: no budget. A session reserves 15 minutes ahead; one the budget cannot pay for 5 minutes is refused (403 budget_exceeded), and a running one whose paid time ends with nothing more to reserve stops with state_reason budget and session.stop_requested, announced at least 5 minutes before by session.budget_warning {stops_at, scope, limit_units, resets_at, next} and one need of kind budget from Ciresk dev to the session's owner, which ciresk dev status, watch and needs and dev_session_needs show and which clears when the session ends. Changed only through dev.policy.set, audited per field.
budget.org_month_unitsinteger or null
what the organisation's sessions use in a UTC calendar month
budget.person_day_unitsinteger or null
what one person's sessions, their agents' included, use in a UTC day
clipboardstring
OSC 52 over the terminal streams (ssh channels with a pty or a login shell, dev exec): allow mints the ticket capability clipboard, under which set sequences pass and are audited dev.clipboard.copied, and queries pass only with transfer_up too (a query's answer is an upload); deny strips both, audited dev.clipboard.denied with the byte count, never the contentOne of allow, deny
dotfilesobject
Whether a person's dotfiles repository is applied in the sessions they own. Left out it reads as allow with any host: nothing runs until a person sets a repository. deny skips them at every new session and refuses dev.dotfiles.set (403 dotfiles_off).
dotfiles.accessstring
One of allow, deny
dotfiles.hostsarray of strings
when not empty, the repository's host must be one of these: an exact host or *.suffix, as in egress.yaml (403 dotfiles_host_not_allowed)
downloadstring
One of allow, deny
egressobject
The organisation's ceilings over every template's egress rows, applied at dev up: a row they do not cover is dropped, a required one is 422 egress_denied. Validated at dev.policy.set: every host is one egress.yaml takes, no port is 0. A changed ceiling reaches a running session at its next renewal, never wider than the rows it was compiled with.
egress.agentarray of objects or null
the ceiling on top of session for a session an agent principal starts (reason agent_policy); unset is empty, so such a session reaches only the registry cache
egress.agent[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.agent[].portsarray of integers
443 when empty
egress.agent_exitboolean
an agent's exec or ssh in a person's session goes out through its own exit (127.0.0.1:3131) under agent, enforced by Landlock; on by default, so an agent reaches the read-only registry cache and the session's MCP gateway until agent lists rows; false shares the person's set
egress.sessionarray of objects or null
when set, the ceiling for every session (reason org_policy); unset changes nothing
egress.session[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
egress.session[].portsarray of integers
443 when empty
lifecycleobject
How long and how many dev sessions the organisation runs. A field left out takes its default, so every organisation is limited without writing a policy; null switches an optional limit off. A session past max_lifetime_secs stops with state_reason max_lifetime and session.stop_requested; lifetime_warning_secs before, its owner gets one need of kind expiring (dev.sessions.needs.raise), which ciresk dev status, watch and needs and dev_session_needs show. Changed only through dev.policy.set, audited per field.
lifecycle.auto_stopstring
what an idle stop, the budget's hard stop and max_lifetime_secs do to a cloud-writer session: pause keeps it with its checkpoint for dev.sessions.start, end ends it; a local writer always endsOne of pause, end
lifecycle.idle_max_secsinteger
at least idle_min_secs; idle_secs and a person's idle_secs lie between; a template that names an idle over it is refused at dev.sessions.up (422 template_invalid, finding idle_over_policy with its next), the 60 min default is pulled down
lifecycle.idle_min_secsinteger
lifecycle.idle_secsinteger or null
the idle stop when the person names none; null is the template's (60 min unless it says)
lifecycle.lifetime_warning_secsinteger
shorter than max_lifetime_secs
lifecycle.max_lifetime_secsinteger or null
from create to stop, whatever the activity; null, the default, is no limit; ciresk dev policy preset no-local-checkout suggests 86400
lifecycle.max_session_cpus_milliinteger or null
the largest cpu reservation, in thousandths of a cpu; null is the worker's own limit (422 session_too_large)
lifecycle.max_session_memory_bytesinteger or null
the largest memory reservation one template may declare; null is the worker's own limit (422 session_too_large)
lifecycle.sessions_per_orginteger
live sessions of the organisation, never above the installation's own ceiling (409 org_session_limit)
lifecycle.sessions_per_personinteger
live sessions one person and their agents hold; at most sessions_per_org (409 person_session_limit)
local_syncstring
One of allow, deny
lockedobject
The organisation's overlay over every repository's dev file, applied at compile; a field left out changes nothing. Validated at dev.policy.set (422 policy_invalid).
locked.container_cpus_milliinteger or null
a cap on every container's cpus, in thousandths of a cpu
locked.container_memory_bytesinteger or null
a cap on every service's, prepare step's and the shell's memory, memory_ceiling and memory_max
locked.egressarray of objects or null
when set, the session's egress rows exactly (the template's dropped); egress.yaml stays the ceiling
locked.egress[].hoststringRequired
locked.egress[].portsarray of integersRequired
locked.egress[].purposestringRequired
locked.egress[].requiredbooleanRequired
locked.imagesarray of strings
pinned references, host/path[:tag]@sha256:<64 hex>, each repository once; a service's or the browser's image of that repository gets this reference
modelsobject
The model proxy in a session: with allow, dev up sets the session's models to {default_model}, so the worker points every container's agents at its front on https://127.0.0.1:3130 with a placeholder key and the installation CA. Off by default, an extra; a policy written before it reads as off.
models.allowboolean
models.default_modelstring or null
the model an agent gets when it names none; null leaves it to the gateway's default
pathsarray of objects
paths[].prefixstringRequired
a directory prefix ending in /, relative, no..; the longest match decides
paths[].readarray of stringsRequired
groups that may read; write implies read
paths[].writearray of stringsRequired
port_forwardstring
One of allow, deny
retentionobject
How long dev keeps what it records, in days from 1 to 3650; a policy written before it reads the defaults. A session in stopped or failed goes with its journal, grants, members, needs, ledger rows and ci records once its end is older than ended_sessions_days; a connection window or egress decision once its window_to is older than its own field. Audit records keep core/audit's retention (12 months by default); checkpoints the bucket's 30 days. Changed only through dev.policy.set, audited per field.
retention.connections_daysinteger
retention.egress_decisions_daysinteger
retention.ended_sessions_daysinteger
sharingstring
One of false, view, use
sshstring
One of allow, deny
ssh_execstring
ssh exec channels with no pty before them (VS Code's, Cursor's and Zed's Remote-SSH servers, JetBrains' backend, ssh host <cmd> without -t, legacy scp and rsync): deny adds the restriction no_ssh_exec to every ticket, under which the worker refuses such a channel, audited dev.session.transfer {channel: exec, allowed: false}; an exec with a pty, a shell, sftp and forwards are unchanged. A field left out reads as allowOne of allow, deny
templatesstring
published: dev up admits only a promoted template version (403 template_not_published)One of any, published
uploadstring
One of allow, deny
versionintegerRequired
webstring
the ceiling for the session view in the browser: off refuses dev.sessions.web_handoff and every gateway renewal, so an open preview stops within 20 s; owners and members only, never the whole organisation or the publicOne of false, view, use
web_idestring
VS Code Web in the session: on mints ide_ro for every role and ide for use and the owner; code-server runs with downloads and uploads disabled unless the ticket holds transfer_down and transfer_up. Off by default, an extraOne of off, on
workersstring
Where the organisation's sessions run: cell, on hosts ci's factory starts for it or its admin enrolled; customer, only on hosts its admin enrolled with dev.workers.enrol, in its own network, so the factory never sees it in dev.workers.demand, dev.workers.provision refuses it (409 customer_workers) and a pending session with no online worker says no_worker. A policy written before it reads as cell.One of cell, customer

Errors

  • 409policy_version_conflict
  • 422policy_invalid (a prefix off the rule, an unknown group, lifecycle limits that do not hold together)
curl -X PUT "$CIRESK_API/v1/dev/policy" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "budget": {
      "org_month_units": 1,
      "person_day_units": 1
    },
    "clipboard": "allow",
    "dotfiles": {
      "access": "allow",
      "hosts": [
        "registry.npmjs.org"
      ]
    },
    "download": "allow",
    "egress": {
      "agent": [
        {
          "host": "registry.npmjs.org",
          "ports": [
            1
          ]
        }
      ],
      "agent_exit": true,
      "session": [
        {
          "host": "registry.npmjs.org",
          "ports": [
            1
          ]
        }
      ]
    },
    "lifecycle": {
      "auto_stop": "pause",
      "idle_max_secs": 300,
      "idle_min_secs": 300,
      "idle_secs": 300,
      "lifetime_warning_secs": 300,
      "max_lifetime_secs": 3600,
      "max_session_cpus_milli": 1,
      "max_session_memory_bytes": 18432000,
      "sessions_per_org": 1,
      "sessions_per_person": 1
    },
    "local_sync": "allow",
    "locked": {
      "container_cpus_milli": 1,
      "container_memory_bytes": 18432000,
      "egress": [
        {
          "host": "registry.npmjs.org",
          "ports": [
            1
          ],
          "purpose": "npm packages",
          "required": true
        }
      ],
      "images": [
        "postgres:17@sha256:4c8a1f2e9b7d3c6a5e0f8b2d1c4a7e9f3b6d0c2a5e8f1b4d7c0a3e6f9b2d5c8a"
      ]
    },
    "models": {
      "allow": true,
      "default_model": "sonnet"
    },
    "paths": [
      {
        "prefix": "crates/payments/",
        "read": [
          "acme/platform"
        ],
        "write": [
          "acme/platform"
        ]
      }
    ],
    "port_forward": "allow",
    "retention": {
      "connections_days": 1,
      "egress_decisions_days": 1,
      "ended_sessions_days": 1
    },
    "sharing": false,
    "ssh": "allow",
    "ssh_exec": "allow",
    "templates": "any",
    "upload": "allow",
    "version": 1,
    "web": false,
    "web_ide": "off",
    "workers": "cell"
  }'
GET/v1/dev/policy/effective

Get the effective policy

The policy and the path view that apply to the caller, or to a named principal for a service (ci).

Read by ciresk dev policy show and by ciresk dev doctor's policy check; policy preset reads dev.policy.get, the version it writes over.

Permission: dev:policy.read

Parameters

NameTypeRequiredDescription
principalquerystringOptionalOnly for a service principal with dev:policy.read (ci evaluating a job's requester). user:<id> reads with the person's directory groups, agent:<id> with its owner's, service:<name> with the groups the installation configures for it (trunk jobs are requested as service:ci), key:<id> with none: fail-closed until core/identity exposes a key's owner, so a key reads only what everyone reads and the answer carries next (run as a user login or a configured service:<name>) for ci's refusal to quote.

Response200 OK

nextstring
only for a principal that resolves to no groups by design (key:<id>); what to run as instead
policyobjectRequired
and; a field left out reads as allow (and sharing as view)
policy.budgetobject
Usage budgets in ci's cost unit, one vCPU-second. Both null by default: no budget. A session reserves 15 minutes ahead; one the budget cannot pay for 5 minutes is refused (403 budget_exceeded), and a running one whose paid time ends with nothing more to reserve stops with state_reason budget and session.stop_requested, announced at least 5 minutes before by session.budget_warning {stops_at, scope, limit_units, resets_at, next} and one need of kind budget from Ciresk dev to the session's owner, which ciresk dev status, watch and needs and dev_session_needs show and which clears when the session ends. Changed only through dev.policy.set, audited per field.
policy.budget.org_month_unitsinteger or null
what the organisation's sessions use in a UTC calendar month
policy.budget.person_day_unitsinteger or null
what one person's sessions, their agents' included, use in a UTC day
policy.clipboardstring
OSC 52 over the terminal streams (ssh channels with a pty or a login shell, dev exec): allow mints the ticket capability clipboard, under which set sequences pass and are audited dev.clipboard.copied, and queries pass only with transfer_up too (a query's answer is an upload); deny strips both, audited dev.clipboard.denied with the byte count, never the contentOne of allow, deny
policy.dotfilesobject
Whether a person's dotfiles repository is applied in the sessions they own. Left out it reads as allow with any host: nothing runs until a person sets a repository. deny skips them at every new session and refuses dev.dotfiles.set (403 dotfiles_off).
policy.dotfiles.accessstring
One of allow, deny
policy.dotfiles.hostsarray of strings
when not empty, the repository's host must be one of these: an exact host or *.suffix, as in egress.yaml (403 dotfiles_host_not_allowed)
policy.downloadstring
One of allow, deny
policy.egressobject
The organisation's ceilings over every template's egress rows, applied at dev up: a row they do not cover is dropped, a required one is 422 egress_denied. Validated at dev.policy.set: every host is one egress.yaml takes, no port is 0. A changed ceiling reaches a running session at its next renewal, never wider than the rows it was compiled with.
policy.egress.agentarray of objects or null
the ceiling on top of session for a session an agent principal starts (reason agent_policy); unset is empty, so such a session reaches only the registry cache
policy.egress.agent[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
policy.egress.agent[].portsarray of integers
443 when empty
policy.egress.agent_exitboolean
an agent's exec or ssh in a person's session goes out through its own exit (127.0.0.1:3131) under agent, enforced by Landlock; on by default, so an agent reaches the read-only registry cache and the session's MCP gateway until agent lists rows; false shares the person's set
policy.egress.sessionarray of objects or null
when set, the ceiling for every session (reason org_policy); unset changes nothing
policy.egress.session[].hoststringRequired
as egress.yaml writes it: a name, *.<suffix> or an ip
policy.egress.session[].portsarray of integers
443 when empty
policy.lifecycleobject
How long and how many dev sessions the organisation runs. A field left out takes its default, so every organisation is limited without writing a policy; null switches an optional limit off. A session past max_lifetime_secs stops with state_reason max_lifetime and session.stop_requested; lifetime_warning_secs before, its owner gets one need of kind expiring (dev.sessions.needs.raise), which ciresk dev status, watch and needs and dev_session_needs show. Changed only through dev.policy.set, audited per field.
policy.lifecycle.auto_stopstring
what an idle stop, the budget's hard stop and max_lifetime_secs do to a cloud-writer session: pause keeps it with its checkpoint for dev.sessions.start, end ends it; a local writer always endsOne of pause, end
policy.lifecycle.idle_max_secsinteger
at least idle_min_secs; idle_secs and a person's idle_secs lie between; a template that names an idle over it is refused at dev.sessions.up (422 template_invalid, finding idle_over_policy with its next), the 60 min default is pulled down
policy.lifecycle.idle_min_secsinteger
policy.lifecycle.idle_secsinteger or null
the idle stop when the person names none; null is the template's (60 min unless it says)
policy.lifecycle.lifetime_warning_secsinteger
shorter than max_lifetime_secs
policy.lifecycle.max_lifetime_secsinteger or null
from create to stop, whatever the activity; null, the default, is no limit; ciresk dev policy preset no-local-checkout suggests 86400
policy.lifecycle.max_session_cpus_milliinteger or null
the largest cpu reservation, in thousandths of a cpu; null is the worker's own limit (422 session_too_large)
policy.lifecycle.max_session_memory_bytesinteger or null
the largest memory reservation one template may declare; null is the worker's own limit (422 session_too_large)
policy.lifecycle.sessions_per_orginteger
live sessions of the organisation, never above the installation's own ceiling (409 org_session_limit)
policy.lifecycle.sessions_per_personinteger
live sessions one person and their agents hold; at most sessions_per_org (409 person_session_limit)
policy.local_syncstring
One of allow, deny
policy.lockedobject
The organisation's overlay over every repository's dev file, applied at compile; a field left out changes nothing. Validated at dev.policy.set (422 policy_invalid).
policy.locked.container_cpus_milliinteger or null
a cap on every container's cpus, in thousandths of a cpu
policy.locked.container_memory_bytesinteger or null
a cap on every service's, prepare step's and the shell's memory, memory_ceiling and memory_max
policy.locked.egressarray of objects or null
when set, the session's egress rows exactly (the template's dropped); egress.yaml stays the ceiling
policy.locked.egress[].hoststringRequired
policy.locked.egress[].portsarray of integersRequired
policy.locked.egress[].purposestringRequired
policy.locked.egress[].requiredbooleanRequired
policy.locked.imagesarray of strings
pinned references, host/path[:tag]@sha256:<64 hex>, each repository once; a service's or the browser's image of that repository gets this reference
policy.modelsobject
The model proxy in a session: with allow, dev up sets the session's models to {default_model}, so the worker points every container's agents at its front on https://127.0.0.1:3130 with a placeholder key and the installation CA. Off by default, an extra; a policy written before it reads as off.
policy.models.allowboolean
policy.models.default_modelstring or null
the model an agent gets when it names none; null leaves it to the gateway's default
policy.pathsarray of objects
policy.paths[].prefixstringRequired
a directory prefix ending in /, relative, no..; the longest match decides
policy.paths[].readarray of stringsRequired
groups that may read; write implies read
policy.paths[].writearray of stringsRequired
policy.port_forwardstring
One of allow, deny
policy.retentionobject
How long dev keeps what it records, in days from 1 to 3650; a policy written before it reads the defaults. A session in stopped or failed goes with its journal, grants, members, needs, ledger rows and ci records once its end is older than ended_sessions_days; a connection window or egress decision once its window_to is older than its own field. Audit records keep core/audit's retention (12 months by default); checkpoints the bucket's 30 days. Changed only through dev.policy.set, audited per field.
policy.retention.connections_daysinteger
policy.retention.egress_decisions_daysinteger
policy.retention.ended_sessions_daysinteger
policy.sharingstring
One of false, view, use
policy.sshstring
One of allow, deny
policy.ssh_execstring
ssh exec channels with no pty before them (VS Code's, Cursor's and Zed's Remote-SSH servers, JetBrains' backend, ssh host <cmd> without -t, legacy scp and rsync): deny adds the restriction no_ssh_exec to every ticket, under which the worker refuses such a channel, audited dev.session.transfer {channel: exec, allowed: false}; an exec with a pty, a shell, sftp and forwards are unchanged. A field left out reads as allowOne of allow, deny
policy.templatesstring
published: dev up admits only a promoted template version (403 template_not_published)One of any, published
policy.uploadstring
One of allow, deny
policy.versionintegerRequired
policy.webstring
the ceiling for the session view in the browser: off refuses dev.sessions.web_handoff and every gateway renewal, so an open preview stops within 20 s; owners and members only, never the whole organisation or the publicOne of false, view, use
policy.web_idestring
VS Code Web in the session: on mints ide_ro for every role and ide for use and the owner; code-server runs with downloads and uploads disabled unless the ticket holds transfer_down and transfer_up. Off by default, an extraOne of off, on
policy.workersstring
Where the organisation's sessions run: cell, on hosts ci's factory starts for it or its admin enrolled; customer, only on hosts its admin enrolled with dev.workers.enrol, in its own network, so the factory never sees it in dev.workers.demand, dev.workers.provision refuses it (409 customer_workers) and a pending session with no online worker says no_worker. A policy written before it reads as cell.One of cell, customer
viewobjectRequired
one principal's evaluated path view; carries no group names
view.entriesarray of objectsRequired
view.entries[].accessobjectRequired
view.entries[].access.readbooleanRequired
view.entries[].access.writebooleanRequired
view.entries[].prefixstringRequired
view.policy_versionintegerRequired
curl "$CIRESK_API/v1/dev/policy/effective" \
  -H "Authorization: Bearer $CIRESK_KEY"