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

# Configuration reference

# Configuration reference

sesame reads its settings from an environment file when it starts. This page lists every
setting the app reads, with its meaning, its default, the values it accepts and whether it is
required. It also lists the settings of the deploy tools. It is for the person who runs the
server. The deploy guide tells you when to set each one: [Deploy and run sesame](deploy/index.md).

## How the settings are read

| Question | Answer |
| - | - |
| Where is the file on the server? | `/opt/sesame/sesame.env`. Create it as in [First deploy, step 3](deploy/2-first-deploy.md#step-3-create-the-settings-file). Edit it with `sudoedit /opt/sesame/sesame.env` |
| Where is the file in development? | `.env` in the repository root, copied from `.env.example`. Task loads it for `task dev` |
| What is the format? | One `NAME=value` line for each setting. A line that starts with `#` is a comment |
| When does a change apply? | At the next start. On the server, run `task deploy:start` on your computer after each change |
| What does an empty value do? | An empty value is the same as no line: the default applies. The refused settings are the exception ([Rules checked at start](#rules-checked-at-start)) |
| What if a value is wrong? | The app does not start. Its log names each wrong setting and the rule it breaks |

**Secret** marks a value that must stay on the server. Do not paste it into a chat, a ticket,
an email or an AI agent session, and do not commit it. The app never writes a secret to its
log, its errors or its API.

## The settings you must fill in

| Setting | Required | Default | Allowed values | What it is |
| - | - | - | - | - |
| `UI_PASSWORD_HASH` (secret) | Yes | None | An argon2id hash that starts `$argon2id$`, inside single quotes | Your login password, stored as a hash. On the server, make it with `sudo docker run --rm -it --network none sesame:<tag> hash-password`. In development, use `task hash-password`. Write it as `UI_PASSWORD_HASH='$argon2id$…'` |
| `SESSION_SECRET` (secret) | Yes | None | Hex or base64 that decodes to at least 32 bytes | A random value. It protects the login sessions and signs each backup. Make it with `openssl rand -hex 32` and keep a copy in your password manager. A backup restores only with the secret that wrote it. A new value ends every login session |

### To connect your Polymarket account

Add these settings after the server passes its security checks, as in
[Go live](deploy/4-go-live.md). To create the Session Key, follow
[Session Key setup](../runbooks/session-key-setup.md).

| Setting | Required | Default | Allowed values | What it is |
| - | - | - | - | - |
| `POLYMARKET_WALLET_ADDRESS` | With a Session Key or CLOB credentials | Empty | 40 hex characters, with or without `0x` | Your account's Deposit Wallet address, from the profile menu on polymarket.com. It is not the address you sign in with, and not the Session Key's address. With only this setting, the app shows positions and activity but not cash or orders |
| `POLYMARKET_SESSION_KEY` (secret) | To trade | Empty | 64 hex characters, with or without `0x`. It must be a valid private key | The private key of the Session Key. A Session Key can trade but cannot act as the account owner. Never put the owner key here |
| `POLYMARKET_OWNER_ADDRESS` | No, but recommended | Empty | 40 hex characters, with or without `0x` | The public address you sign in to polymarket.com with. When it is set, the app does not start if the owner key is in `POLYMARKET_SESSION_KEY` |
| `LIVE_TRADING` | No | Off | Only the exact value `true` turns it on. Any other value keeps it off | The app sends real orders only when this is `true`. Set it after the [live verification](../runbooks/live-verification.md). Set it to `false` in an emergency |

## Settings you may want to change

| Setting | Required | Default | Allowed values | What it does |
| - | - | - | - | - |
| `TELEGRAM_BOT_TOKEN` (secret) | With `TELEGRAM_CHAT_ID` | Empty | Digits, a colon, then 30 to 100 letters, digits, `_` or `-` | The token of the bot that sends you notifications. How to get it: [Telegram notifications](../runbooks/telegram.md) |
| `TELEGRAM_CHAT_ID` | With `TELEGRAM_BOT_TOKEN` | Empty | A number of 1 to 20 digits. A group or channel id is negative. An `@name` is refused | The chat the bot sends to |
| `BACKUP_INTERVAL` | No | `6h` | A duration such as `6h` or `30m`, at least `1m`. `0` turns scheduled backups off | How often the app writes a backup. Each scheduled backup also deletes the oldest backups above `BACKUP_KEEP`. With `0`, nothing deletes old backups, so the backups from `backup-now` and from each deploy stay. Keep it above `0` on the server |
| `BACKUP_KEEP` | No | `28` | A whole number from 1 to 10000 | How many backups to keep. The count includes the backups from `backup-now` and from each deploy. Keep it below about 60 on the server: the folder of encrypted copies holds at most 128 files, two for each backup. When it is full, the backup machine gets no new copies |
| `LOG_LEVEL` | No | `info` | `debug`, `info`, `warn` or `error` | How much the app writes to its log. Use `debug` for a short time to find a problem |

### Risk ceilings

Each risk limit in the app's **Settings** has a ceiling, set here. The limit that applies is the
lower of the two. **Settings** refuses to save a limit above its ceiling and shows
`Ceiling <value>` under each field.

| Setting | Default ceiling | Allowed values | Caps this limit in Settings | Default limit |
| - | - | - | - | - |
| `RISK_CEILING_ORDER_NOTIONAL` | `50000` | An amount in pUSD | **Max order notional** | 25,000 |
| `RISK_CEILING_POSITION_NOTIONAL` | `250000` | An amount in pUSD | **Max position notional** | 100,000 |
| `RISK_CEILING_DAILY_NOTIONAL` | `5000000` | An amount in pUSD | **Max daily notional** | 1,000,000 |
| `RISK_CEILING_OPEN_ORDERS` | `200` | A whole number from 0 to 1000000 | **Max open orders** | 100 |
| `RISK_CEILING_ORDERS_PER_MINUTE` | `120` | A whole number from 0 to 1000000 | **Max orders per minute** | 60 |
| `RISK_CEILING_COMBO_NOTIONAL` | `25000` | An amount in pUSD | **Max combo notional**, for one combo buy | 5,000 |
| `RISK_CEILING_COMBO_EXPOSURE` | `100000` | An amount in pUSD | **Max combo exposure**, the cost of all open combos | 25,000 |
| `RISK_CEILING_COMBO_LEGS` | `50` | A whole number from 2 to 50 | **Max combo legs** | 10 |

* None of these settings is required.
* Write an amount without separators: `50000`, not `50,000`. It can have up to 6 decimal
  places.
* A ceiling of `0` blocks every order of that kind.
* You can set a ceiling below a limit that is saved in **Settings**. The app uses the ceiling
  from the next start.
* To raise a limit in **Settings**, the app asks for your login password.
* The [live verification](../runbooks/live-verification.md#11-risk-limits-for-the-run) gives
  values for a first live run.

The other limits in **Settings** have fixed maximums and no setting here:

| Limit in Settings | Allowed values |
| - | - |
| **Price band** | 1 to 50 ticks |
| **Exit slippage** | 0 to 50 ticks |
| **Duplicate window** | 0 to 10,000 ms |
| **Armed idle timeout** | 1 to 240 minutes |

## Rules checked at start

If a setting breaks one of these rules, the app does not start. Its log names the setting and
the rule. What to do next is in
[troubleshooting](deploy/troubleshooting.md#the-deploy-stops-and-the-app-does-not-start).

* **Single quotes around a value with `$`.** `UI_PASSWORD_HASH` needs them. Without them, the
  parts after each `$` are replaced and the value breaks.
* **Telegram: both or neither.** Set `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` together, or
  leave both empty.
* **The wallet goes with the key.** A Session Key or CLOB credentials need
  `POLYMARKET_WALLET_ADDRESS`.
* **Never the owner.** The Session Key's address, `POLYMARKET_SIGNER_ADDRESS` and the wallet
  address must all differ from `POLYMARKET_OWNER_ADDRESS`. The wallet address must also differ
  from the Session Key's address.
* **CLOB credentials: all three or none.** With CLOB credentials and no Session Key,
  `POLYMARKET_SIGNER_ADDRESS` is required. With a Session Key, `POLYMARKET_SIGNER_ADDRESS`
  must be that key's address.
* **The cookie setting matches the origin.** `COOKIE_SECURE` is `true` when
  `SESAME_PUBLIC_ORIGIN` starts with `https`, and `false` when it starts with `http`.
* **The fake venue is for development only.** `SESAME_FAKE_VENUE=1` needs a development build.
  It is refused with `LIVE_TRADING=true`, with a Session Key and with CLOB credentials.
* **Refused settings.** The app does not start while one of these lines is in the file, even
  with an empty value. Delete the line.

  | Setting | Why |
  | - | - |
  | A name that starts with `POLYMARKET_RELAYER_`, `POLYMARKET_BRIDGE_URL`, `POLY_BUILDER_` or `POLYMARKET_BUILDER_`, in any letter case | These are for services that move money. The app only trades and never moves funds. Builder keys stay on the account owner's machine |
  | `GEOBLOCK_URL` | The location check always uses `https://polymarket.com/api/geoblock`. You cannot change it |
  | `POLYMARKET_PRIVATE_KEY` | The old name of `POLYMARKET_SESSION_KEY`. Rename the line, and make sure the value is a Session Key, not the owner key |

## Do not set these on the server

On the server, the file `deploy/compose.yaml` sets the settings in the table below that have a
value in the **On the server** column. Those values override `sesame.env`, so a value you write
there has no effect. The deploy also refuses to start while `sesame.env` sets a proxy
variable.

## Advanced and developer-only

Leave these settings out on the server unless a row says otherwise.

### Polymarket credentials and endpoints

| Setting | Required | Default | Allowed values | What it does |
| - | - | - | - | - |
| `POLYMARKET_CLOB_API_KEY`, `POLYMARKET_CLOB_SECRET`, `POLYMARKET_CLOB_PASSPHRASE` (secrets) | No | Empty | All three, or none | The CLOB API credentials of the Session Key. Leave them empty: the app makes them from the Session Key at each start and keeps them in memory only. If you set them, clear them when you rotate the key |
| `POLYMARKET_SIGNER_ADDRESS` | With CLOB credentials and no Session Key | Empty | 40 hex characters, with or without `0x` | The Session Key's address, for a host that has the CLOB credentials but not the key |
| `POLYMARKET_GAMMA_URL` | No | `https://gamma-api.polymarket.com` | See the note below | The market catalogue |
| `POLYMARKET_CLOB_URL` | No | `https://clob.polymarket.com` | See the note below | Order books and orders |
| `POLYMARKET_DATA_API_URL` | No | `https://data-api.polymarket.com` | See the note below | Positions and activity |
| `POLYMARKET_WS_MARKET_URL` | No | `wss://ws-subscriptions-clob.polymarket.com/ws/market` | See the note below | The market data feed |
| `POLYMARKET_WS_USER_URL` | No | `wss://ws-subscriptions-clob.polymarket.com/ws/user` | See the note below | The account feed |
| `POLYMARKET_WS_SPORTS_URL` | No | `wss://sports-api.polymarket.com/ws` | See the note below | The scores feed |
| `POLYMARKET_WS_LIVE_URL` | No | `wss://ws-live-v2.polymarket.com/ws` | See the note below | The live activity feed |
| `POLYMARKET_COMBOS_URL` | No | `https://combos-rfq-gateway-requester-api.polymarket.com` | See the note below. The Combos client also accepts only its default host | Combo quotes and accepts |

Note: an endpoint must use the scheme of its default (`https` or `wss`). It must have no user
name or password, and its host must be `polymarket.com` or a subdomain of it. Change an
endpoint only if Polymarket moves it before a new release of the app does.

### Server and development

| Setting | Required | Default | Allowed values | On the server | What it does |
| - | - | - | - | - | - |
| `HTTP_ADDR` | No | `127.0.0.1:8080` | `host:port`, port 1 to 65535. An empty host listens on every address | `[::]:8080` | The address the app listens on. The `healthcheck` command also reads it |
| `DATA_DIR` | No | `data` | A folder path | `/data` | The folder of the database and of `backups/` |
| `COOKIE_SECURE` | No | `false` | `true` or `false` | `true` | Sends the login cookie over HTTPS only. See [Rules checked at start](#rules-checked-at-start) |
| `SESAME_PUBLIC_ORIGIN` | No | `http://` and the value of `HTTP_ADDR` | `http` or `https`, then `://host` and an optional `:port`, with no path. Not `0.0.0.0` or `::` | `https://` and the `DOMAIN` from `/etc/sesame/deploy.conf` | The address browsers use for the app. A request for another host gets status 421. A change from another origin gets status 403 |
| `SESAME_DEV_ORIGIN` | No | Empty | Plain `http` on `localhost`, `127.0.0.1` or `[::1]`. Must be empty when `COOKIE_SECURE` is `true` | Empty | The address of the Vite dev server, which `task dev` starts |
| `TRUSTED_PROXY` | No | Empty, which trusts no proxy | IP addresses or networks, separated by commas. A network that covers every address is refused | `172.29.53.10,fd53:5e5a:6d65::10`, the Caddy proxy | The reverse proxies whose `X-Forwarded-For` header the app trusts for the client address |
| `LOG_FORMAT` | No | `text` | `text` or `json` | `json` | The format of the log lines |
| `SESAME_FAKE_VENUE` | No | Empty | `1`, or empty | Empty | `1` shows made-up market data from memory and keeps its data in `<DATA_DIR>/fake`. `task dev:fake` sets it |
| `SESAME_FAKE_VENUE_STRESS` | No | Empty | `1`, or empty. Needs `SESAME_FAKE_VENUE=1` | Empty | Fills the fake venue with the longest text and largest numbers, for layout tests |
| `SESAME_FAKE_VENUE_GAME_START` | No | Empty | A whole number of seconds from 1. Needs `SESAME_FAKE_VENUE=1` | Empty | An upcoming fake game starts this many seconds after the app starts, for game start tests |
| `TELEGRAM_API_BASE_URL` | No | `https://api.telegram.org` | Tests only. Any other value needs `SESAME_FAKE_VENUE=1` and is `scheme://host[:port]`: `https`, or `http` to `localhost` or `127.0.0.1` | Not set. Only the default is accepted | Sends Telegram messages to a local test stub |
| `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, `ALL_PROXY` and the lower-case names | No | Empty | Do not set | Empty. The deploy refuses to start while `sesame.env` sets one | Standard proxy settings. The Polymarket and Telegram connections follow `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`. The location check never uses a proxy |

## Settings of the deploy tools

These settings are not in `sesame.env`. The deploy scripts read them, not the app. None of
them is a secret.

### Your computer: `deploy/.deploy.env`

Copy `deploy/deploy.env.example` to `deploy/.deploy.env`, or set the same names in the shell.
A value in the shell wins. [First deploy, step 1](deploy/2-first-deploy.md#step-1-fill-in-your-computers-deploy-settings)
tells you when to fill them in.

| Setting | Required | Default | Allowed values | What it is |
| - | - | - | - | - |
| `SESAME_DEPLOY_HOST` | Yes | None | A host name or an IP address | The server. Its host key must already be in `~/.ssh/known_hosts` ([Record the server's fingerprint](deploy/1-prepare-server.md#step-12-record-the-servers-fingerprint)) |
| `SESAME_DEPLOY_USER` | No | `deploy` | A user name | The deploy account on the server |
| `SESAME_DEPLOY_PORT` | No | `22` | 1 to 65535 | The SSH port of the server |
| `SESAME_DEPLOY_KEY` | Yes | None | A path to a private key file. The key must be a FIDO2 key or have a passphrase | The deploy key. Use it for this server only and do not add it to an ssh-agent |
| `SESAME_ALLOWED_SIGNERS` | Yes, for every `task deploy` command | None | A path to a file that is not empty. `~/` is allowed | Your `allowed_signers` file. The tasks run only from a release tag that this file verifies ([Set up release signing](deploy/1-prepare-server.md#step-8-set-up-release-signing-and-sign-the-first-release)) |
| `SESAME_BACKUP_USER` | No | `sesame-backup` | A user name | The read-only account that the backup machine uses |
| `SESAME_BACKUP_KEY` | On the backup machine, for `task deploy:pull-backups` | None | A path to a private key file | The key of that read-only account |

### The server: `/etc/sesame/deploy.conf`

The file is owned by root and is readable by all users. The deploy refuses a line with any
other name.

| Setting | Required | Default | Allowed values | What it is |
| - | - | - | - | - |
| `DOMAIN` | Yes | None | A host name in lower case | The public name of the app. The app's address is `https://<DOMAIN>` |
| `ACME_EMAIL` | Yes | None | An email address | The contact address for the Let's Encrypt account |
| `REPO_URL` | Yes | None | An `https://`, `ssh://` or `git@` git address | Where the server gets release tags. A private repository uses `ssh` ([Private repository](deploy/advanced.md#private-repository)) |
| `VERIFY_TAGS` | Yes | None | `yes` or `no` | `yes` deploys only tags signed by a key in `/etc/sesame/allowed_signers`. `no` deploys any tag of that name |

The deploy writes `/opt/sesame/.env` for Docker Compose. It holds `DOMAIN`, `ACME_EMAIL`,
`SESAME_IMAGE_TAG` and `SESAME_PREVIOUS_IMAGE_TAG`. Do not edit it.


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