> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a template

> Save a template: a whole workspace config, checked as a create
checks one, and kept as written. A name already saved is a 409.



## OpenAPI

````yaml /openapi.yaml post /v1/templates
openapi: 3.1.0
info:
  title: Mirage API
  version: '0.1'
servers:
  - url: http://127.0.0.1:8765
    description: A local daemon on its default port
security:
  - bearerAuth: []
paths:
  /v1/templates:
    post:
      tags:
        - Templates
      summary: Create a template
      description: |-
        Save a template: a whole workspace config, checked as a create
        checks one, and kept as written. A name already saved is a 409.
      operationId: create_template_v1_templates_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTemplateRequest'
        required: true
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateResponse'
        '401':
          $ref: '#/components/responses/401'
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
        '429':
          $ref: '#/components/responses/429'
        '501':
          $ref: '#/components/responses/501'
components:
  schemas:
    CreateTemplateRequest:
      properties:
        name:
          type: string
          title: Name
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
        config:
          $ref: '#/components/schemas/WorkspaceConfig'
      additionalProperties: false
      type: object
      required:
        - name
        - config
      title: CreateTemplateRequest
    TemplateResponse:
      properties:
        name:
          type: string
          title: Name
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
        config:
          additionalProperties: true
          type: object
          title: Config
      type: object
      required:
        - name
        - description
        - config
      title: TemplateResponse
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    WorkspaceConfig:
      properties:
        mounts:
          additionalProperties:
            $ref: '#/components/schemas/MountBlock'
          type: object
          title: Mounts
        io:
          $ref: '#/components/schemas/IOConfig'
        command_limits:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/Limit'
              type: object
            - type: 'null'
          title: Command Limits
        max_memory:
          anyOf:
            - type: string
            - type: integer
            - type: 'null'
          title: Max Memory
        max_body_bytes:
          anyOf:
            - type: string
            - type: integer
            - type: 'null'
          title: Max Body Bytes
        max_env:
          anyOf:
            - type: string
            - type: integer
            - type: 'null'
          title: Max Env
        network:
          anyOf:
            - type: boolean
            - additionalProperties:
                anyOf:
                  - items:
                      type: string
                    type: array
                  - additionalProperties:
                      type: string
                    type: object
              type: object
          title: Network
          default: true
        system_time:
          anyOf:
            - type: string
            - type: 'null'
          title: System Time
        clis:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/CLIBlock'
              type: object
            - type: 'null'
          title: Clis
        runtimes:
          anyOf:
            - items:
                anyOf:
                  - type: string
                  - additionalProperties: true
                    type: object
              type: array
            - type: 'null'
          title: Runtimes
        route_policy:
          anyOf:
            - $ref: '#/components/schemas/ProfilePolicy'
            - type: 'null'
        profiles:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/SessionProfile'
              type: object
            - type: 'null'
          title: Profiles
        profile:
          anyOf:
            - type: string
            - type: 'null'
          title: Profile
        processes:
          anyOf:
            - $ref: '#/components/schemas/ProcessPermissions'
            - type: 'null'
        mode:
          $ref: '#/components/schemas/MountMode'
          default: write
        read:
          anyOf:
            - $ref: '#/components/schemas/ReadPolicy'
            - type: 'null'
        write:
          anyOf:
            - $ref: '#/components/schemas/WritePolicy'
            - type: 'null'
        default_session_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Default Session Id
        workspace_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Workspace Id
        cache:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamCacheBlock'
                - $ref: '#/components/schemas/RedisCacheBlock'
              discriminator:
                propertyName: type
                mapping:
                  ram: '#/components/schemas/RamCacheBlock'
                  redis: '#/components/schemas/RedisCacheBlock'
            - type: 'null'
          title: Cache
        index:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamIndexBlock'
                - $ref: '#/components/schemas/RedisIndexBlock'
              discriminator:
                propertyName: type
                mapping:
                  ram: '#/components/schemas/RamIndexBlock'
                  redis: '#/components/schemas/RedisIndexBlock'
            - type: 'null'
          title: Index
        store:
          anyOf:
            - $ref: '#/components/schemas/StoreBlock'
            - type: 'null'
        env:
          anyOf:
            - additionalProperties:
                anyOf:
                  - type: string
                  - $ref: '#/components/schemas/EnvVar'
              type: object
            - type: 'null'
          title: Env
        secrets:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/SecretSource'
              type: object
            - type: 'null'
          title: Secrets
      additionalProperties: false
      type: object
      required:
        - mounts
      title: WorkspaceConfig
    Error:
      type: object
      properties:
        detail:
          description: What went wrong, as text or a structured record.
        errno:
          type: string
          description: The errno of a failed file call, such as ENOENT.
        refusal:
          type: object
          description: The policy refusal, when a policy refused the call.
      required:
        - detail
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    MountBlock:
      properties:
        vfs:
          type: string
          title: Vfs
        mode:
          anyOf:
            - $ref: '#/components/schemas/MountMode'
            - type: 'null'
        config:
          additionalProperties: true
          type: object
          title: Config
        command_limits:
          additionalProperties:
            $ref: '#/components/schemas/Limit'
          type: object
          title: Command Limits
        backend:
          $ref: '#/components/schemas/MountBackend'
          default: workspace
        mountpoint:
          anyOf:
            - type: string
            - type: 'null'
          title: Mountpoint
        read:
          anyOf:
            - $ref: '#/components/schemas/ReadPolicy'
            - type: 'null'
        ttl:
          anyOf:
            - type: integer
            - type: 'null'
          title: Ttl
        write:
          anyOf:
            - $ref: '#/components/schemas/WritePolicy'
            - type: 'null'
        index:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamIndexBlock'
                - $ref: '#/components/schemas/RedisIndexBlock'
              discriminator:
                propertyName: type
                mapping:
                  ram: '#/components/schemas/RamIndexBlock'
                  redis: '#/components/schemas/RedisIndexBlock'
            - type: 'null'
          title: Index
      additionalProperties: false
      type: object
      required:
        - vfs
      title: MountBlock
    IOConfig:
      properties:
        buffer_bytes:
          type: integer
          maximum: 9007199254740991
          minimum: 16384
          title: Buffer Bytes
          default: 65536
      additionalProperties: false
      type: object
      title: IOConfig
      description: Workspace limits for each in-flight byte queue.
    Limit:
      properties:
        max_bytes:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Max Bytes
        max_lines:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Max Lines
        timeout_seconds:
          anyOf:
            - type: number
              minimum: 0
            - type: 'null'
          title: Timeout Seconds
        walk_limit:
          anyOf:
            - type: integer
              minimum: -1
            - type: 'null'
          title: Walk Limit
        on_exceed:
          $ref: '#/components/schemas/OnExceed'
          default: truncate
      additionalProperties: false
      type: object
      title: Limit
      description: |-
        A bound on a result: the policy layer's limit arm and the shape
        every cap config parses into.

        Carries its fields inline (the Deny precedent: an action is its
        payload). ``kind`` is the wire discriminant; ``aggr`` is the
        composition law (AND to the tightest per bound, ANY on error mode)
        and ``layered`` the resolution law (each field from the most
        specific layer that sets it). ``walk_limit`` caps the entries one
        walk lists on a mount, -1 for no cap.
    CLIBlock:
      properties:
        cli:
          anyOf:
            - type: string
            - type: 'null'
          title: Cli
        script:
          anyOf:
            - type: string
            - type: 'null'
          title: Script
        runtime:
          anyOf:
            - type: string
            - type: 'null'
          title: Runtime
        config:
          additionalProperties: true
          type: object
          title: Config
      additionalProperties: false
      type: object
      title: CLIBlock
      description: |-
        One ``clis:`` entry: install a named CLI with its own config.

        The section key is the installed head word. Exactly one handler
        source: ``cli`` names a registered spec tree; ``script`` references
        a program file whose content is embedded at load (the docker
        build-context model). ``runtime`` optionally pins the world runtime
        entry that runs the script; unset picks the first entry speaking
        the script's language. ``config`` validates through the spec's
        ``config_model`` at install time (fail loud). A CLI never takes a
        mode and never shares a mount's credentials: a binary has no mode,
        the credential does.
    ProfilePolicy:
      properties:
        script:
          anyOf:
            - $ref: '#/components/schemas/ScriptSource'
            - type: string
          title: Script
        runtime:
          anyOf:
            - type: string
            - additionalProperties: true
              type: object
          title: Runtime
          default: monty
        env:
          additionalProperties:
            anyOf:
              - type: string
              - $ref: '#/components/schemas/SecretRef'
          type: object
          title: Env
          default: {}
      additionalProperties: false
      type: object
      required:
        - script
      title: ProfilePolicy
      description: |-
        One program of a profile's policy, as the document states it: the
        program, and the runtime that runs it.

        Args:
            script (ScriptSource | str): the policy program. A ``str`` is
                the path form the config loader accepts and loads; code
                passes the loaded ``ScriptSource``, so a path still spelled
                as a string when the workspace reads it means the config
                layer never saw it, and is refused there.
            runtime (str | dict[str, Any]): the runtime the program runs on:
                a name, or ``{name, config}`` for one that needs settings,
                the shape a ``runtimes`` entry has. Monty when the program
                names none; without the ``monty`` extra installed, such a
                program fails closed with the extra's install hint.
            env (dict[str, str | SecretRef]): variables the program runs
                with beside ``MIRAGE_POLICY_CTX``, on any runtime: a literal,
                or a pointer read from its source when the program first
                runs. None of the session's reach it.
    SessionProfile:
      properties:
        cwd:
          anyOf:
            - type: string
            - type: 'null'
          title: Cwd
        env:
          anyOf:
            - additionalProperties:
                anyOf:
                  - type: string
                  - $ref: '#/components/schemas/EnvVar'
              type: object
            - type: 'null'
          title: Env
        mounts:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/ProfileMount'
              type: object
            - type: 'null'
          title: Mounts
        paths:
          anyOf:
            - $ref: '#/components/schemas/PathsBlock'
            - type: 'null'
        vars:
          anyOf:
            - $ref: '#/components/schemas/VarsBlock'
            - type: 'null'
        commands:
          anyOf:
            - $ref: '#/components/schemas/CommandsBlock'
            - type: 'null'
        policy:
          anyOf:
            - additionalProperties:
                items:
                  $ref: '#/components/schemas/ProfilePolicy'
                type: array
              propertyNames:
                enum:
                  - pre_execute
                  - pre_command
                  - pre_vfs
                  - pre_session
                  - pre_network
                  - post_execute
                  - post_command
                  - post_vfs
                  - post_session
                  - post_network
              type: object
            - type: 'null'
          title: Policy
        command_limits:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/Limit'
              type: object
            - type: 'null'
          title: Command Limits
        processes:
          anyOf:
            - $ref: '#/components/schemas/ProcessPermissions'
            - type: 'null'
        network:
          anyOf:
            - type: boolean
            - additionalProperties:
                anyOf:
                  - items:
                      type: string
                    type: array
                  - additionalProperties:
                      type: string
                    type: object
              type: object
            - type: 'null'
          title: Network
      additionalProperties: false
      type: object
      title: SessionProfile
      description: |-
        One profile: the whole permission document a session runs under.

        A session is created from exactly one of these, and it is the only
        place permissions are written. There is no workspace-wide block and
        no mount-owned block above it, so reading this object is reading
        everything the profile may do; what a profile does not say, it does not
        restrict. Configuration, not enforcement: the resolver compiles it
        onto the session's narrowing fields and the entry points keep enforcing.
        Deliberately not named a View, which per the view convention is a
        handle an agent holds on one entry point, while a profile is what the
        embedder uses to *define* one. Frozen so two agents with the same
        profile share one object and neither can bend the other's view.

        Two rules decide a line against it, and they are the whole law.
        A rule naming no path is read by verb (deny before ask before
        allow), wherever it is written. A rule carrying paths, and every
        hide, is read by anchor depth: the deeper entry wins, ties break by
        verb.

        A profile may also state a ``policy``: for each ``pre_`` method it
        answers at (``pre_execute``, ``pre_command``, ``pre_vfs``,
        ``pre_session``), a list of programs, each with the runtime it runs
        on (``ProfilePolicy``, the shape a ``clis`` entry has). A program's
        function for the method takes its context and returns its answer:
        None for no opinion, a deny, an ask, or at ``pre_execute`` a route.
        They are asked in order and the first deny wins, so a policy expresses
        the conditions a declarative rule cannot; like every policy, it can
        only restrict, never grant past a deny. The document is optional
        beside it: a profile stating only a policy hides nothing, and the
        policy is its whole admission policy.

        Args:
            cwd (str | None): the session's working directory at creation.
            env (dict[str, str | EnvVar] | None): the env entries seeded
                into the session at creation, in the workspace ``env``
                grammar: a bare string is an exported literal, and a
                ``from:`` entry a managed pointer, so a credential is
                named here and fetched, never written as its value.
            mounts (dict[str, ProfileMount] | None): per-mount settings,
                keyed by prefix: a mode, ask and deny rules for lines
                working inside the mount, and hides under it. A mount the
                mapping omits keeps its own mode and gains no rules.
            paths (PathsBlock | None): the profile's hides, absolute.
            vars (VarsBlock | None): the profile's hidden variables.
            commands (CommandsBlock | None): the profile's allow list and its
                ask / deny rules, absolute paths.
            policy (dict[ScriptMethod, list[ProfilePolicy]] | None): the
                profile's policy: each ``pre_`` method's programs, asked in
                order.
            network (bool | dict[str, list[str]] | None): where the
                session's lines may connect, the workspace's ``network``
                grammar, held besides the workspace's own; None leaves the
                workspace's alone.
    ProcessPermissions:
      properties:
        list:
          type: string
          enum:
            - session
            - workspace
          title: List
          default: session
        kill:
          type: string
          enum:
            - session
            - workspace
          title: Kill
          default: session
        max:
          anyOf:
            - type: integer
              minimum: 1
            - type: 'null'
          title: Max
          default: 128
      additionalProperties: false
      type: object
      title: ProcessPermissions
      description: |-
        How far past its own session a profile reaches into processes.

        A session always sees and stops its own processes. ``list`` widens
        what ``ps`` and a handler's process view see; ``kill`` widens what
        they may stop, and never past ``list``. ``max`` caps the live
        processes the session holds, its running line included, as
        ``ulimit -u`` counts the shell. A bare scope sets both. The workspace
        states one for every session and a profile's overrides it field by
        field (``layered``).

        Args:
            list (ProcessScope): whose processes the session sees.
            kill (ProcessScope): whose processes the session may stop.
            max (int | None): most live processes, ``MAX_PROCESSES`` unless
                stated, None for no cap.
    MountMode:
      type: string
      enum:
        - read
        - write
        - exec
      title: MountMode
      description: |-
        What a mount lets commands do, a cumulative ladder.

        READ lists and reads. WRITE also creates, changes and deletes. EXEC
        also lets the interpreter commands (python3, js) run code: a script
        file named as their operand must sit on an EXEC mount, while inline
        code and -m need one somewhere in the workspace (imports are not
        checked by path). Shell scripts need no EXEC, since the shell checks
        each of their commands like a typed one; a ./script whose shebang
        names python3 reaches python3, which does check.
    ReadPolicy:
      type: string
      enum:
        - fresh
        - bounded
        - pinned
      title: ReadPolicy
      description: |-
        How a mount decides whether cached bytes may be served.

        FRESH revalidates against the backend's content token before serving
        a cached copy; BOUNDED serves without revalidating, within the
        staleness bound the mount declares.

        PINNED names the content a commit's fingerprint records. There is no
        version layer to pin to, so a mount declaring it is refused at mount
        time rather than quietly degraded to head: the vocabulary is
        published, so someone will type it, and an informative refusal costs
        one branch over a generic invalid-value error.
    WritePolicy:
      type: string
      enum:
        - unconditional
        - conditional
        - staged
      title: WritePolicy
      description: >-
        Whether a mount's writes carry the version they were based on.


        UNCONDITIONAL replacements use last-write-wins. Shared rewrites that

        observed a missing file require atomic create-only under either policy.

        CONDITIONAL writes send the version the mount last saw for the path

        (the backend's native precondition, If-Match on the S3 family), so a

        write based on a stale read is refused instead of overwriting the newer

        bytes. STAGED names a staging layer mirage does not have; a mount
        declaring it is

        refused at mount time, as ``read: pinned`` is.
    RamCacheBlock:
      properties:
        type:
          type: string
          const: ram
          title: Type
          default: ram
        limit:
          anyOf:
            - type: string
            - type: integer
          title: Limit
          default: 32MB
        max_drain_bytes:
          anyOf:
            - type: integer
            - type: 'null'
          title: Max Drain Bytes
      additionalProperties: false
      type: object
      title: RamCacheBlock
    RedisCacheBlock:
      properties:
        type:
          type: string
          const: redis
          title: Type
        limit:
          anyOf:
            - type: string
            - type: integer
          title: Limit
          default: 512MB
        max_drain_bytes:
          anyOf:
            - type: integer
            - type: 'null'
          title: Max Drain Bytes
        url:
          type: string
          title: Url
          default: redis://localhost:6379/0
        key_prefix:
          anyOf:
            - type: string
            - type: 'null'
          title: Key Prefix
      additionalProperties: false
      type: object
      required:
        - type
      title: RedisCacheBlock
    RamIndexBlock:
      properties:
        type:
          type: string
          const: ram
          title: Type
          default: ram
        ttl:
          type: number
          title: Ttl
          default: 600
      additionalProperties: false
      type: object
      title: RamIndexBlock
    RedisIndexBlock:
      properties:
        type:
          type: string
          const: redis
          title: Type
        ttl:
          type: number
          title: Ttl
          default: 600
        url:
          type: string
          title: Url
          default: redis://localhost:6379/0
        key_prefix:
          anyOf:
            - type: string
            - type: 'null'
          title: Key Prefix
      additionalProperties: false
      type: object
      required:
        - type
      title: RedisIndexBlock
    StoreBlock:
      properties:
        type:
          type: string
          enum:
            - ram
            - disk
            - redis
          title: Type
          default: ram
        url:
          type: string
          title: Url
          default: redis://localhost:6379/0
        key_prefix:
          type: string
          title: Key Prefix
          default: 'mirage:'
        root:
          type: string
          title: Root
          default: ~/.mirage/state
        namespace:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamStoreBlock'
                - $ref: '#/components/schemas/DiskStoreBlock'
                - $ref: '#/components/schemas/RedisStoreBlock'
                - $ref: '#/components/schemas/S3StoreBlock'
              discriminator:
                propertyName: type
                mapping:
                  disk: '#/components/schemas/DiskStoreBlock'
                  ram: '#/components/schemas/RamStoreBlock'
                  redis: '#/components/schemas/RedisStoreBlock'
                  s3: '#/components/schemas/S3StoreBlock'
            - type: 'null'
          title: Namespace
        observer:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamStoreBlock'
                - $ref: '#/components/schemas/DiskStoreBlock'
                - $ref: '#/components/schemas/RedisStoreBlock'
                - $ref: '#/components/schemas/S3StoreBlock'
              discriminator:
                propertyName: type
                mapping:
                  disk: '#/components/schemas/DiskStoreBlock'
                  ram: '#/components/schemas/RamStoreBlock'
                  redis: '#/components/schemas/RedisStoreBlock'
                  s3: '#/components/schemas/S3StoreBlock'
            - type: 'null'
          title: Observer
        workspace:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamStoreBlock'
                - $ref: '#/components/schemas/DiskStoreBlock'
                - $ref: '#/components/schemas/RedisStoreBlock'
                - $ref: '#/components/schemas/S3StoreBlock'
              discriminator:
                propertyName: type
                mapping:
                  disk: '#/components/schemas/DiskStoreBlock'
                  ram: '#/components/schemas/RamStoreBlock'
                  redis: '#/components/schemas/RedisStoreBlock'
                  s3: '#/components/schemas/S3StoreBlock'
            - type: 'null'
          title: Workspace
        jobs:
          anyOf:
            - oneOf:
                - $ref: '#/components/schemas/RamStoreBlock'
                - $ref: '#/components/schemas/DiskStoreBlock'
                - $ref: '#/components/schemas/RedisStoreBlock'
                - $ref: '#/components/schemas/S3StoreBlock'
              discriminator:
                propertyName: type
                mapping:
                  disk: '#/components/schemas/DiskStoreBlock'
                  ram: '#/components/schemas/RamStoreBlock'
                  redis: '#/components/schemas/RedisStoreBlock'
                  s3: '#/components/schemas/S3StoreBlock'
            - type: 'null'
          title: Jobs
      additionalProperties: false
      type: object
      title: StoreBlock
      description: |-
        The workspace state store: one block, five planes.

        The top-level type/url/key_prefix pick the default backend for
        every control-plane group (namespace nodes, observer events,
        sessions + workspace metadata, jobs). The optional per-group
        overrides redirect one group to a different backend, e.g. large
        observer logs to a separate server. Sessions and workspace metadata
        move together by design (the default-session pointer must live
        beside the session table it points into), so there is one
        `workspace` override, not two. An ``s3`` group hosts only the
        sessions+meta group (conditional-PUT CAS), so it is valid as the
        ``workspace`` override, never as the top-level default. A ``disk``
        store hosts the other planes under ``root`` (lockfile CAS,
        machine-local) and keeps jobs in memory, since a job's console is a
        stream other processes follow; ``root`` is only read when a disk
        store is selected. The ``jobs`` group (job lists, consoles, owner
        leases) is therefore ram or redis.
    EnvVar:
      properties:
        value:
          anyOf:
            - type: string
            - type: 'null'
          title: Value
        readonly:
          type: boolean
          title: Readonly
          default: false
        export:
          type: boolean
          title: Export
          default: true
        from:
          anyOf:
            - type: string
            - type: 'null'
          title: From
        ref:
          type: string
          title: Ref
          default: ''
        key:
          anyOf:
            - type: string
            - type: 'null'
          title: Key
        fetch:
          type: string
          enum:
            - lazy
            - eager
          title: Fetch
          default: lazy
      additionalProperties: false
      type: object
      title: EnvVar
      description: |-
        One entry of the env map: a literal value or a managed pointer.

        The env block is one map, name -> entry. A bare string in the map
        is the literal short form and never reaches this model; a dict is
        validated through it. `value` and `from` are mutually exclusive and
        one is required: `export` belongs to a literal entry, `ref`/`key`/
        `fetch` to a managed one, and `readonly` to either.

        Args:
            value (str | None): the literal text; set = a literal entry.
            readonly (bool): compiles to `VarAttr.READONLY`, so the agent
                cannot assign to the name or unset it. Legal on a managed
                entry too, and the point of one: the fetch writes the
                record itself rather than going through the shell's
                assignment gate, so mirage still fills a readonly
                credential while a line that tries to overwrite it is
                refused.
            export (bool): literal-only knob (default on); a managed entry
                is always exported.
            provider (str | None): registered source name; set = a managed
                entry. Spelled `from:` in YAML (python keyword), via alias.
            ref (str): the source's address for the secret.
            key (str | None): which secret field to read; default the
                variable's own name.
            fetch (Literal["lazy", "eager"]): eager joins every line's
                fetch set instead of waiting for a reference.
    SecretSource:
      properties:
        source:
          type: string
          title: Source
        config:
          additionalProperties: true
          type: object
          title: Config
      additionalProperties: false
      type: object
      required:
        - source
      title: SecretSource
      description: |-
        One declared source instance: which source, and its config.

        The `secrets:` block is one map, name -> source, spelled the way
        `mounts:` and `clis:` are: a type beside a config. The
        instance name is what a managed env entry's `from:` names, so two
        accounts of one platform are two instances, and an instance named
        after its source reads as that source configured.

        The config map is untyped here, the way `mounts.*.config` is: each
        source owns its own model, and this block only has to tell a
        pointer from a literal. It does that the way the env plane does,
        by the presence of `from`, so a mapping carrying one is validated
        as a `SecretRef` and every other value passes through to the
        source's model.

        Args:
            source (str): the registered source this instance speaks to.
            config (dict[str, Any]): the source's own config fields; a
                value may be a literal or a `SecretRef`.
    MountBackend:
      type: string
      enum:
        - workspace
        - fuse
        - fskit
        - nfs
      title: MountBackend
      description: |-
        How a mount is exposed to the outside world.

        WORKSPACE is the default: the mount lives only inside mirage's own
        filesystem and is reached through the command surface, with nothing
        registered with the kernel. FUSE and FSKIT additionally expose it as a
        real mountpoint.

        FSKIT is macOS 15.4+ only and needs no kernel extension. It has no
        ``direct_io`` equivalent, so it serves correct reads only for mounts
        that set ``sizes_always_known``; ``mirage.fuse.backend`` warns at mount
        time about mounts whose size-unknown files will read as empty. Writes
        are also limited: appends and metadata ops persist, but the macFUSE
        FSKit shim flushes pages a file did not already have (a new file, or
        truncate-then-write) as NUL bytes, a limit pinned in
        ``integ/fuse/truth_fskit.json``.
        There is deliberately no ``auto``: auto-selecting FSKIT would silently
        degrade every API-backed mount.

        NFS mounts through the operating system's own NFS client, so nothing
        is installed: mirage serves NFSv3 on a local port and runs the system
        ``mount``. Linux and macOS; Linux needs root to mount. It is read-only
        for now, and like FSKIT it reads only as far as the size a file
        reports, so it serves mounts that set ``sizes_always_known``.
    OnExceed:
      type: string
      enum:
        - error
        - truncate
      title: OnExceed
    ScriptSource:
      properties:
        source:
          type: string
          title: Source
        language:
          type: string
          enum:
            - python
            - js
          title: Language
          default: python
        module:
          type: boolean
          title: Module
          default: false
      additionalProperties: false
      type: object
      required:
        - source
      title: ScriptSource
      description: |-
        A program's source: a policy program or a script CLI.

        A yaml ``script:`` value references a ``.py`` or ``.js``/``.mjs``
        file whose content is embedded here at load; code passes the text.
        It runs as a program on the runtime its config names, never edited.

        Args:
            source (str): the script program.
            language (Language): the script's language ("python" or "js"),
                stamped from the file extension at config load; the
                programmatic default is "python".
            module (bool): the source is an ES module (a ``.mjs`` file), so
                a js engine must run it in module mode or ``import`` and
                top-level ``await`` fail. Stamped from the extension at
                load beside ``language``, since the path is gone once the
                source is embedded.
    SecretRef:
      properties:
        from:
          type: string
          title: From
        ref:
          type: string
          title: Ref
          default: ''
        key:
          type: string
          title: Key
      additionalProperties: false
      type: object
      required:
        - from
        - key
      title: SecretRef
      description: |-
        A configured value read from a source instead of written down.

        The plane's one declarative pointer, spelled with the same three
        keys the env plane's managed entry uses, so one grammar covers
        every place a deployment points at a secret: a source's own config,
        a mount's credential, a CLI's.

        Where it may point is the *context's* rule, not this model's.
        `SecretSource` narrows its own config to `BOOTSTRAP_SOURCES`,
        because that is what stops the source table from needing a
        dependency graph; a mount has no such limit, since every source is
        already built by the time one is read.

        Args:
            provider (str): the bootstrap source, `env` or `dotenv`.
                Spelled `from:` in YAML (python keyword), via alias.
            ref (str): the source's address, a file path for `dotenv`.
            key (str): which of the secret's fields holds the value.
    ProfileMount:
      properties:
        mode:
          anyOf:
            - $ref: '#/components/schemas/MountMode'
            - type: 'null'
        commands:
          anyOf:
            - $ref: '#/components/schemas/MountCommandsBlock'
            - type: 'null'
        paths:
          anyOf:
            - $ref: '#/components/schemas/PathsBlock'
            - type: 'null'
      additionalProperties: false
      type: object
      title: ProfileMount
      description: |-
        One mount's entry in a profile: what this profile may do there.

        Every field is optional, and an omitted mount is not a refusal: the
        mount is reachable at the mode it declares in the workspace's
        ``mounts:``, which a profile can only weaken (``weaker_mode``), never
        raise. A profile that must not touch a mount hides it, so the mount
        reads as nonexistent rather than as a permission error naming
        something the profile cannot see.

        ``commands`` here carries ask and deny only: an allow list installs
        a command for the whole session, and visibility is answered before
        any operand exists, so it cannot be per mount. Rules written here
        apply to a line that works inside this mount, by cwd or by operand,
        which is what a path-scoped rule cannot express (``cd /repo && git
        commit`` names no path).

        Args:
            mode (MountMode | None): this profile's mode for the mount; None
                keeps the mount's own.
            commands (MountCommandsBlock | None): ask and deny rules for
                lines working inside it.
            paths (PathsBlock | None): hides under it.
    PathsBlock:
      properties:
        hide:
          items:
            type: string
          type: array
          title: Hide
          default: []
        show:
          items:
            $ref: '#/components/schemas/ShowEntry'
          type: array
          title: Show
          default: []
        reasons:
          items:
            $ref: '#/components/schemas/HideReason'
          type: array
          title: Reasons
          default: []
      additionalProperties: false
      type: object
      title: PathsBlock
      description: |-
        ``paths:`` of a profile, or of one of its mount sections.

        ``hide`` entries use the document's one grammar: an entry with
        ``*``, ``?`` or ``[`` is a pattern, anything else an exact path
        and its subtree (``utils/hidden.classify_paths``); every entry
        holds a token and is absolute or a name pattern, wherever the block
        is written. A hide entry may also be a group
        ``{patterns: [...], reason: ...}``: the patterns join the flat list
        like any other entry and the reason lands in ``reasons``, the
        operator-only side table (:class:`HideReason`).

        ``show`` is the other half of the path axis: a mapping of path to
        mode (``{"/repo/docs": r}``), or a plain list whose entries inherit
        the mount's mode. Every entry is absolute, a subtree or an anchored
        pattern, because a show anchors to a place and a name pattern names
        none. An entry re-opens its subtree inside a hidden region when its
        anchor is deeper than the hide's, and states the mode in force
        below its anchor when it carries one; both on the one anchor-depth
        rule.

        Args:
            hide (tuple[str, ...]): what the profile makes nonexistent.
            show (tuple[ShowEntry, ...]): the profile's show entries, in
                document order.
            reasons (tuple[HideReason, ...]): why grouped hide entries
                exist, for the operator's entry points only.
    VarsBlock:
      properties:
        hide:
          items:
            type: string
          type: array
          title: Hide
          default: []
      additionalProperties: false
      type: object
      title: VarsBlock
      description: |-
        ``vars:`` of a profile.

        Args:
            hide (tuple[str, ...]): variable names or globs over names the
                session reads as unset.
    CommandsBlock:
      properties:
        allow:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Allow
        ask:
          items:
            $ref: '#/components/schemas/CommandRule'
          type: array
          title: Ask
          default: []
        deny:
          items:
            $ref: '#/components/schemas/CommandRule'
          type: array
          title: Deny
          default: []
      additionalProperties: false
      type: object
      title: CommandsBlock
      description: >-
        ``commands:`` at the top level of a profile.


        ``allow`` lists the command patterns the profile allows; a line no

        pattern covers is refused, ``<cmd>: Permission denied`` at 126, like

        any other rule's Deny. Shell builtins are subjects like everything

        else: a list stating only ``cat`` refuses ``echo`` and ``cd``. The
        agent's

        own functions are the one exemption, safe because every line of a

        body passes the gate itself. ``ask`` rules are admitted only with a

        host approval; ``deny`` rules refuse with a reason. A bare string in

        either is one command pattern with the default reason.


        Args:
            allow (tuple[str, ...] | None): the profile's allow patterns;
                None (unstated) allows everything.
            ask (tuple[CommandRule, ...]): what needs sign-off, in order.
            deny (tuple[CommandRule, ...]): the profile's refusals, in order.
    RamStoreBlock:
      properties:
        type:
          type: string
          const: ram
          title: Type
          default: ram
      additionalProperties: false
      type: object
      title: RamStoreBlock
    DiskStoreBlock:
      properties:
        type:
          type: string
          const: disk
          title: Type
        root:
          type: string
          title: Root
          default: ~/.mirage/state
      additionalProperties: false
      type: object
      required:
        - type
      title: DiskStoreBlock
    RedisStoreBlock:
      properties:
        type:
          type: string
          const: redis
          title: Type
        url:
          type: string
          title: Url
          default: redis://localhost:6379/0
        key_prefix:
          type: string
          title: Key Prefix
          default: 'mirage:'
      additionalProperties: false
      type: object
      required:
        - type
      title: RedisStoreBlock
    S3StoreBlock:
      properties:
        timeout:
          type: number
          exclusiveMinimum: 0
          title: Timeout
          default: 30
        region:
          anyOf:
            - type: string
            - type: 'null'
          title: Region
        aws_access_key_id:
          anyOf:
            - type: string
              format: password
              writeOnly: true
            - type: 'null'
          title: Aws Access Key Id
        aws_secret_access_key:
          anyOf:
            - type: string
              format: password
              writeOnly: true
            - type: 'null'
          title: Aws Secret Access Key
        aws_session_token:
          anyOf:
            - type: string
              format: password
              writeOnly: true
            - type: 'null'
          title: Aws Session Token
        aws_profile:
          anyOf:
            - type: string
            - type: 'null'
          title: Aws Profile
        bucket:
          type: string
          title: Bucket
        endpoint_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Endpoint Url
        path_style:
          type: boolean
          title: Path Style
          default: false
        proxy:
          anyOf:
            - type: string
              format: password
              writeOnly: true
            - type: 'null'
          title: Proxy
        key_prefix:
          anyOf:
            - type: string
            - type: 'null'
          title: Key Prefix
          default: mirage/
        default_content_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Default Content Type
        type:
          type: string
          const: s3
          title: Type
      additionalProperties: false
      type: object
      required:
        - bucket
        - type
      title: S3StoreBlock
      description: |-
        An ``S3Config`` plus the union discriminator: the block IS the
        backend config, so new S3Config fields flow into the store block
        without re-declaring them here.
    MountCommandsBlock:
      properties:
        ask:
          items:
            $ref: '#/components/schemas/CommandRule'
          type: array
          title: Ask
          default: []
        deny:
          items:
            $ref: '#/components/schemas/CommandRule'
          type: array
          title: Deny
          default: []
      additionalProperties: false
      type: object
      title: MountCommandsBlock
      description: |-
        ``commands:`` of one mount section: ``ask`` and ``deny`` only.

        A mount rule applies to a line that works inside the mount (its cwd
        or one of its paths lies under the root); its ``paths`` are
        absolute, like every other path in the document, and must name
        something under that root. There is no ``allow`` here: what a
        session can see is a property of the session, and an operand cannot
        make a command "not found".

        Args:
            ask (tuple[CommandRule, ...]): what needs sign-off here.
            deny (tuple[CommandRule, ...]): what is refused here.
    ShowEntry:
      properties:
        path:
          type: string
          title: Path
        mode:
          anyOf:
            - $ref: '#/components/schemas/MountMode'
            - type: 'null'
      additionalProperties: false
      type: object
      required:
        - path
      title: ShowEntry
      description: |-
        One ``show`` entry of a profile's path axis, compiled.

        Args:
            path (str): the entry as written: an exact subtree or an
                anchored pattern, always absolute. A slashless name pattern
                is refused at validation, because a show anchors to a place
                and a name pattern names none.
            mode (MountMode | None): the mode the entry states for its
                subtree; None for a list-form entry, which inherits the
                mount's.
    HideReason:
      properties:
        patterns:
          items:
            type: string
          type: array
          title: Patterns
        reason:
          type: string
          title: Reason
      additionalProperties: false
      type: object
      required:
        - patterns
        - reason
      title: HideReason
      description: >-
        Why one group of hide entries exists, for the operator only.


        The document may state a hide as ``{patterns: [...], reason: ...}``;

        the patterns compile into the flat hide spec like any other entry,

        and this side table keeps the reason beside them for the host's

        entry points (audit, read-back). It is never rendered to the agent: a
        hide

        answers ENOENT, and a reason on a nonexistent path would confirm

        the path exists.


        Args:
            patterns (tuple[str, ...]): the group's entries, as compiled
                (a mount section's entries anchored to its root).
            reason (str): why the operator hid them.
    CommandRule:
      properties:
        reason:
          type: string
          title: Reason
        commands:
          items:
            type: string
          type: array
          title: Commands
          default: []
        paths:
          items:
            type: string
          type: array
          title: Paths
          default: []
        mount:
          type: string
          title: Mount
          default: ''
      additionalProperties: false
      type: object
      required:
        - reason
      title: CommandRule
      description: >-
        One admission rule of the permissions document: refuse (or ask

        about) matching commands, on matching paths when it names any.


        It is the compiled element of ``commands.deny`` and ``commands.ask``

        wherever the profile writes one, and reaches the workspace only inside

        that document; ``PermissionsPolicy`` is what evaluates it. The

        document writes a rule in one of three shapes, and each compiles to

        rules of this class: a list of command patterns (a whole-line rule

        on each, no paths), a mapping of command pattern to its paths (one

        command to many paths, one rule per command, so a path is never

        stated beside a command it was not meant for), or paths alone (a

        rule on every command, at the dispatcher too). A command entry is a

        token-prefix pattern over the line as the entry point normalizes it
        (``rm``

        is every rm line, ``git push`` every ``git push ...``, a ``*`` token

        any one token). Path entries use the document's one grammar: an

        entry with ``*``, ``?`` or ``[`` is a pattern (repo fnmatch dialect,

        ``*`` crossing ``/``, a slashless pattern matching any name

        component), anything else is an exact path and its subtree. Every

        entry is absolute or a name pattern, holds a token (a blank one

        would be the root), and inside a mount section must name something

        under that mount root.


        Args:
            reason (str): why the command is refused, carried on the
                result's refusal record.
            commands (tuple[str, ...]): command patterns the rule applies
                to; empty means every command. A path-scoped rule carries
                exactly one.
            paths (tuple[str, ...]): path entries; empty refuses the
                command regardless of its operands.
            mount (str): set by the compiler for a rule written under a
                ``mounts.<prefix>`` section, the mount root it is scoped to:
                it applies only to a line whose cwd or paths lie under it.
                Empty for a rule written at the top level; never typed in
                the document.
  responses:
    '401':
      description: The token is missing or wrong
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        text/plain:
          schema:
            type: string
            description: The Python daemon answers Unauthorized as plain text.
    '429':
      description: Past a rate limit, or a new session past max_sessions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
            minimum: 0
    '501':
      description: >-
        The server requires accounts; saved configs are kept only on a server of
        one account
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        The server's token (MIRAGE_AUTH_TOKEN) or a JWT. A daemon in the default
        local mode with no token accepts requests without one.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.