All docs

Gambit Permissions Guide

Gambit Permissions Guide

This guide explains Gambit's permission contract for deck execution and how to
inspect effective permissions in traces.

Overview

Gambit models permissions with five Deno-native kinds:

  • read
  • write
  • run
  • net
  • env

Permissions can be declared in workspace config (gambit.toml) and in deck
metadata (PROMPT.md or TS deck definitions). Effective permissions are
computed by monotonic intersection: child scopes can only stay the same or get
narrower.

Where You Can Declare Permissions

Workspace Ceiling (gambit.toml)

Use workspace permissions to set a root ceiling.

[workspace]
permissions.read = ["./decks", "./shared"]
permissions.write = ["./workspace"]
permissions.net = false
permissions.env = false

[workspace.permissions.run]
commands = ["deno", "node"]
paths = ["./bin/safe-tool"]

Deck Declaration (PROMPT.md front matter)

+++
label = "my-deck"
permissions.read = ["./docs"]
permissions.write = false

[permissions.run]
commands = ["deno"]
+++

Reference Override ([[actions]], [[scenarios]], [[graders]])

+++
[[actions]]
name = "do_thing"
path = "./actions/do/PROMPT.md"
description = "Runs a child action"
actions.permissions.read = ["./shared"]
+++

Notes:

  • Relative paths are resolved from the owner declaration location.
  • Unspecified kinds in a declaration normalize to deny (false) for that layer.

Run Semantics

run supports:

  • boolean (true / false)
  • command list (run = ["deno", "node"])
  • object form:
[permissions.run]
commands = ["deno"]
paths = ["./bin/tool"]

Path grants and command grants are intentionally separate:

  • paths checks exact normalized path matches.
  • commands checks exact command-name matches.
  • No implicit basename fallback between the two modes.
  • In object form, paths and commands must be arrays.
  • paths = true / commands = true are invalid; use run = true for full run
    access.

Trace Observability

Gambit traces include effective permissions and layer decisions on:

  • run.start
  • deck.start
  • action.start

Example trace fragment:

{
  "type": "run.start",
  "runId": "run-...",
  "permissions": {
    "baseDir": "/workspace",
    "effective": {
      "read": ["/workspace/shared"],
      "write": false,
      "run": { "paths": [], "commands": ["deno"] },
      "net": false,
      "env": false
    },
    "layers": [
      {
        "name": "host",
        "effective": {
          "read": true,
          "write": true,
          "run": true,
          "net": true,
          "env": true
        }
      },
      {
        "name": "workspace",
        "effective": {
          "read": ["/workspace/shared"],
          "write": false,
          "run": { "paths": [], "commands": ["deno"] },
          "net": false,
          "env": false
        }
      }
    ]
  }
}

Debugging Checklist

  • Confirm the event has a permissions block.
  • Check effective first (what was actually applied).
  • Then inspect layers in order to see where a permission narrowed.
  • Validate baseDir when a relative path grant looks unexpected.

Compatibility

This phase documents and surfaces permission computation; it does not enforce
new worker behavior by itself. Existing deck-loading compatibility remains in
place, with warnings for deprecated metadata where applicable.