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

# sinker policy

> View and manage AI agent policy settings — tip caps, retry limits, queue bounds, and throughput controls.

## Overview

The `sinker policy` namespace gates what the AI agent is allowed to do. Policies set hard limits on tip size, how aggressively the agent escalates on retries, how many bundles can be in-flight at once, and more.

Settings persist in `sinker.policy.json` in the working directory. Both the sidecar and the agent read the file once on startup. Restart the stack to apply any changes.

```
sinker policy <sub-command>
```

<Note>
  The policy file is **partial by design** — only the keys you change need to be present. Missing keys resolve silently to built-in defaults. An empty file (or no file at all) means "use all defaults."
</Note>

***

## Policy keys

These keys are accepted by `sinker policy set` and `sinker policy reset <key>`.

### Tip controls

| Key              | Default  | Unit     | Description                                                                           |
| ---------------- | -------- | -------- | ------------------------------------------------------------------------------------- |
| `max-tip`        | `500000` | lamports | Hard ceiling — agent cannot recommend above this regardless of network conditions     |
| `max-tip-ratio`  | `5.0`    | %        | Tip cannot exceed N% of the transaction's transfer value                              |
| `tip-percentile` | `p75`    | —        | Percentile the agent targets when the network is calm (`p50` / `p75` / `p95` / `p99`) |
| `stale-after`    | `2000`   | ms       | Maximum age of tip oracle data before the agent refuses to proceed                    |

### Bundle & retry controls

| Key               | Default | Unit     | Description                                                                     |
| ----------------- | ------- | -------- | ------------------------------------------------------------------------------- |
| `max-retries`     | `3`     | —        | Maximum re-submission attempts before a bundle is declared expired              |
| `expiry-slots`    | `150`   | slots    | How many slots past enqueue the agent keeps retrying before dropping the bundle |
| `escalation-step` | `5000`  | lamports | Maximum tip increase per retry cycle — prevents runaway escalation              |
| `max-queue`       | `20`    | —        | Maximum in-flight bundles at any time — new enqueues are rejected above this    |

### Throughput controls

| Key          | Default | Unit | Description                                                                               |
| ------------ | ------- | ---- | ----------------------------------------------------------------------------------------- |
| `rate-limit` | `60`    | /min | Maximum transactions accepted per minute across all callers                               |
| `priority`   | `auto`  | —    | Pin all bundles to a tier (`normal` / `high` / `urgent`) or let the agent decide (`auto`) |

***

## Commands

### `sinker policy set <key> <value>`

Set a single policy value. The change is written to `sinker.policy.json` immediately.

```bash theme={null}
sinker policy set max-tip 100000
sinker policy set tip-percentile p95
sinker policy set priority high
sinker policy set max-retries 5
```

```
  set max-tip = 100000
  saved → sinker.policy.json
```

The stack must be restarted for the new value to take effect.

***

### `sinker policy show`

Print all policy values as a table — current effective value, built-in default, and which keys have been explicitly set.

```bash theme={null}
sinker policy show
```

```
┌─ Policy ─────────────────────────────────────────────────────────────────
│  KEY               CURRENT          DEFAULT
│  ──────────────────────────────────────────────────────────────────────
│  max-tip           100000L          500000L          ← set
│  max-tip-ratio     5.0%             5.0%
│  tip-percentile    p75              p75
│  stale-after       2000ms           2000ms
│  max-retries       3                3
│  expiry-slots      150              150
│  escalation-step   5000L            5000L
│  max-queue         20               20
│  rate-limit        60/min           60/min
│  priority          auto             auto
│  ──────────────────────────────────────────────────────────────────────
│  file: sinker.policy.json (1 override)
└──────────────────────────────────────────────────────────────────────────
```

***

### `sinker policy reset [<key>]`

Reset a single key back to its built-in default, or reset all keys if no key is given.

```bash theme={null}
# Reset one key
sinker policy reset max-tip

# Reset everything
sinker policy reset
```

`reset` without a key writes an empty `{}` JSON file — all keys will resolve to defaults on next start. The file itself is kept; use `sinker policy clear` to delete it entirely.

***

### `sinker policy clear`

Delete the policy file. All settings revert to built-in defaults on the next sidecar or agent start.

```bash theme={null}
sinker policy clear
```

```
  delete sinker.policy.json? All settings revert to defaults on next start. [y/N]
```

Pass `--yes` / `-y` to skip the confirmation prompt (useful in CI or setup scripts):

```bash theme={null}
sinker policy clear --yes
```

***

### `sinker policy validate`

Check the current effective policy for contradictions and dangerous values.

```bash theme={null}
sinker policy validate
```

**Errors** (exit code 1 — block correct operation):

| Condition                     | Error                                                       |
| ----------------------------- | ----------------------------------------------------------- |
| `escalation-step` > `max-tip` | Every retry would immediately exceed the tip ceiling        |
| `max-tip` = 0                 | Jito requires a non-zero tip — all bundles will be rejected |
| `max-tip-ratio` ≤ 0           | Invalid — would block all tips                              |
| `expiry-slots` = 0            | Bundles expire immediately and can never be submitted       |
| `max-queue` = 0               | All enqueues will be rejected                               |

**Warnings** (informational — do not exit non-zero):

| Condition              | Warning                                                       |
| ---------------------- | ------------------------------------------------------------- |
| `stale-after` \< 400ms | Shorter than one Solana slot — oracle may always appear stale |
| `max-tip-ratio` > 100% | Tip can exceed the transaction value                          |
| `max-retries` = 0      | Failed bundles will not be retried                            |
| `rate-limit` = 0       | All incoming transactions will be rejected                    |

Example output with issues:

```
  validating policy from sinker.policy.json

  ✗ error: escalation-step (600000L) > max-tip (500000L): every retry would immediately exceed the tip ceiling
  ⚠ warning: stale-after (200ms) is shorter than one slot (~400ms): tip oracle may always appear stale

  1 error(s) found — run `sinker policy set` to fix before starting the stack
```

***

### `sinker policy export [--path <file>]`

Export the current effective policy — with all defaults resolved — to a JSON file. Unlike the live policy file (which only stores overrides), the export includes every key. Useful for sharing a policy between Sinker deployments.

```bash theme={null}
# Export to the default path (sinker.policy.json)
sinker policy export

# Export to a custom path
sinker policy export --path /shared/prod.policy.json
```

```
  policy exported → /shared/prod.policy.json
  all 10 keys written (defaults resolved)
```

The exported file can be applied on another machine with `sinker policy import`.

***

### `sinker policy import <file>`

Load a policy JSON file, validate it, and apply it as the active policy. Errors block the import; warnings are printed but do not block it.

```bash theme={null}
sinker policy import /shared/prod.policy.json
```

```
  imported /shared/prod.policy.json → sinker.policy.json
  restart the stack to apply the new policy
```

If validation errors are found, the import is aborted and the existing policy is left unchanged:

```
  ✗ error: max-queue is 0: all enqueues will be rejected

  import aborted — 1 error(s) found in '/shared/prod.policy.json'. Fix and retry.
```

***

## Storage and load order

The policy file is looked up in this order on every `sinker start` or `sinker up`:

1. Path in `SINKER_POLICY_FILE` env var — custom override
2. `./sinker.policy.json` — working directory
3. Built-in defaults — no file required, no warning

```bash theme={null}
# Use a shared policy file across multiple deployments
SINKER_POLICY_FILE=/etc/sinker/policy.json sinker start
```

The file format is plain JSON. Keys not present resolve to defaults — you only need to store values you change:

```json theme={null}
{
  "max_tip_lamports": 100000,
  "tip_percentile": "p75",
  "priority": "high"
}
```

***

## Recommended starting policy

For most production deployments, a conservative starting point:

```bash theme={null}
sinker policy set max-tip 200000        # cap at 200k lamports (~0.0002 SOL)
sinker policy set max-tip-ratio 3       # tip cannot exceed 3% of tx value
sinker policy set escalation-step 5000  # raise by at most 5k lamports per retry
sinker policy set max-retries 4         # up to 4 re-submissions per bundle
sinker policy set max-queue 30          # allow up to 30 in-flight bundles
sinker policy validate                  # confirm no contradictions
```
