# Configure Pointsman without guessing

[Documentation](../public-index.md) / How-to / Configuration

A gateway's configuration covers several different jobs: connecting infrastructure,
choosing models, granting access and controlling how requests behave. Putting all of
those settings in one long list makes the product harder to learn. This guide starts
with the change you want to make and shows where it belongs, when it takes effect
and how to verify it.

Complete the [quickstart](../tutorial/README.md) first. The
[dashboard tour](../tutorial/dashboard.md) shows the corresponding screens.

## Choose the right configuration surface

| You want to change… | Where it belongs | How it becomes active |
|---|---|---|
| Credentials, database/Redis connections, process resources | Deployment environment and secret configuration | Recreate/restart the relevant service with the new environment; follow its startup checks. |
| Provider/model records and model metadata | Providers/Models or the registry admin API | Save the record and verify the registry's current state; credential environment changes still need deployment. |
| Routing groups and their candidate lists | Operator configuration; Routing can prepare a group draft | Merge the exported configuration and restart the gateway. |
| Selected scalar gateway settings | Operator configuration; Studio helps inspect and draft them | Follow the reported activation method: boot, operator refresh or runtime update. Export alone applies nothing. |
| Application access, keys and limits | Scope/key/budget editors or their admin APIs | Successful authorized writes change the stored records. Inspect effective access/limits afterward. |
| Supported guardrail overrides | Dedicated guardrail editor/admin API | Supported runtime fields can be saved; boot-only fields remain deployment-owned. |
| Learner process settings | The policy service's own environment | Apply through the policy-service deployment, separately from the gateway. |

The dashboard's effective-configuration surface reports selected operational
settings. It is not a complete editor for every Spring property, secret or model
record. The [environment reference](../reference/configuration.md) is generated
from `docker/.env.example`; additional typed configuration is defined in the source
and explained by the feature guides.

## Understand the labels

**Restart required (`boot`)** means the running process read the value at startup.
Editing a file or exporting a draft does not alter that process.

**Operator refresh (`refreshable`)** means the setting supports a documented refresh
path. It does not mean the UI changes the environment or invokes refresh for you.
Use the feature's procedure; do not assume a generic refresh reloads everything.

**Runtime value (`live`)** means an appropriate management operation can update that
value. Use its dedicated editor/API. Studio still only prepares a draft, even when
the setting supports runtime changes.

**Current value** is what the connected gateway reports. **Draft value** is an
unapplied proposal. **Default** is a fallback when you have not overridden the setting;
it is not necessarily the current value. Read units alongside every number: an entry
count, bytes, milliseconds and a monthly currency amount are different constraints.

## Configure a local Compose installation

The quickstart copies `docker/.env.example` to `docker/.env`. Edit your copy; keep the
example as a documented template. Typical initial values are:

```dotenv
POINTSMAN_AUTH_PEPPER=<stable-random-secret-from-the-quickstart>
POINTSMAN_KEY_ENVIRONMENT=test
POINTSMAN_ADMIN_USERNAME=admin
POINTSMAN_ADMIN_PASSWORD=<your-admin-password>
OPENAI_API_KEY=<your-provider-api-key>
```

This is a fragment, not a complete `.env`. Keep the other required values from the
quickstart, including the bootstrap provider-client requirements. An admin bootstrap
password seeds an empty admin table; changing that environment variable is not a
password-reset procedure for an existing account. Keep the key pepper stable and
back it up with your deployment secrets.

There are two layers to understand:

1. **Compose constructs the container environment.** The repository uses both
   `env_file` and explicit `environment` entries. Explicit entries win over `env_file`;
   interpolation uses the shell environment ahead of values in `--env-file`.
2. **Spring resolves gateway settings inside the container.** Packaged YAML supplies
   settings, and external property sources can override them. An environment variable
   only helps if it is passed into the container and maps to the intended property.
   Avoid defining the same setting in several places.

Use the same Compose files and `--env-file` arguments every time. A shell export can
make your new `.env` value appear ineffective; inspect your shell's overrides when
that happens. Do not paste a rendered configuration containing secrets into an issue.

```bash
# Validate Compose syntax/interpolation without printing resolved secrets.
docker compose --env-file docker/.env -f docker/docker-compose.yml config --quiet
```

For an approved change in your local evaluation stack, recreate the gateway so it
receives the new environment. This command affects the running gateway; schedule
production changes through your rollout procedure.

```bash
docker compose --env-file docker/.env -f docker/docker-compose.yml up -d gateway
curl --fail --show-error http://localhost:8080/actuator/health/readiness
```

`docker compose restart` restarts the existing container; it does not apply a changed
container environment. If readiness fails, inspect startup logs and the named
validation failure before sending traffic.

## Example: create a two-model routing group

Suppose your application requests `support-chat`. You want to distribute eligible
requests between two models, while keeping the application's model name stable.
Both models must already exist, be enabled and be accessible to the intended key.

The group's configuration looks like this:

```yaml
pointsman:
  routing:
    groups:
      support-chat:
        strategy: weighted-random
        candidates:
          - provider: openai
            model: gpt-4o-mini
            weight: 9
          - provider: openai
            model: gpt-4o
            weight: 1
```

These are example registered model identifiers, not a promise of current provider
availability. Replace them with your configured entries. Weights are relative
selection weights, not a guarantee that every ten requests split nine to one.

**Routing → Create group** can prepare this kind of YAML. It is a fragment to merge
into the configuration your deployment actually loads. The stock Compose setup does
not automatically load an arbitrary YAML file just because you downloaded it.

For the stock local Compose setup, one way to supply nested configuration is an
entry in `docker/.env`:

```dotenv
SPRING_APPLICATION_JSON='{"pointsman":{"routing":{"groups":{"support-chat":{"strategy":"weighted-random","candidates":[{"provider":"openai","model":"gpt-4o-mini","weight":9},{"provider":"openai","model":"gpt-4o","weight":1}]}}}}}'
```

If you already use `SPRING_APPLICATION_JSON`, merge into that JSON object rather
than adding a second entry or discarding existing groups. Recreate the gateway,
check readiness, then inspect **Routing → Current settings**. Call `support-chat`
using the [application API](../reference/client-api.md) and inspect request evidence.
A single successful answer does not statistically validate a weighting ratio.

[Traffic-split guide](split-traffic-between-models.md) ·
[Routing strategies](../routing-strategies.md)

## Example: inspect and adjust a cache setting

Open **Configuration studio → Cache → Exact-cache capacity**. Studio shows a friendly
name, the current value, activation mode and technical key
`pointsman.cache.l1.max-size`. Try a local draft, then review the before/after values.
An exported fragment might look like:

```yaml
pointsman:
  cache:
    l1:
      max-size: 12000
```

This is an illustrative value, not a sizing recommendation. L1 is also constrained
by its configured weight budget. Read [operational limits](../reference/operational-limits.md)
before increasing capacity. Merge the fragment with existing configuration, follow
the restart requirement, then fetch current values again. Changing an entry cap
alone does not prove a particular memory footprint or hit rate.

Use **Configuration delivery** to retain the reviewed baseline, proposed values and
rollback values. Its verification reads current values and compares them with the
package; it does not deploy the package or prove that a workload meets its targets.

## Example: set an application's spending policy

Use **API keys** or the relevant **Budgets & limits** scope. First inspect the key's
owner and effective inherited limits. Then choose a cap/rule for that scope and save
through the dedicated editor. Read back the effective limit and which ancestor binds
it; the child's own value is not always the final constraint.

If you automate this through the admin API, check each endpoint's semantics. Many
limits `PUT` operations replace the full set of fields: omitting a field can remove
that cap. Do not assume a partial JSON object is a patch.

Gateway usage and cost can include estimates, especially for interrupted streams.
Budget controls are not a provider-invoice hard cap. A fenced/unverifiable budget
store needs its documented recovery procedure, not a larger cap or an automatic
counter reset. [Keys and budgets](issue-keys-and-set-budgets.md) ·
[Admin API](../reference/admin-api.md) · [Operating notes](../operating-notes.md).

## Read back the effective settings

In the dashboard, use **Fetch current values** and check that the fetch succeeded.
An administrator can also inspect the same selected configuration surface with
Basic authentication; curl prompts for the password:

```bash
curl --fail-with-body --silent --show-error --user admin \
  http://localhost:8080/admin/control/effective | jq .
```

This endpoint reports the gateway instance that answered. With several instances,
verify all intended replicas through your deployment tooling rather than assuming
one load-balanced read proves fleet-wide activation. It does not replace the
registry, effective-limit or guardrail-specific read APIs.

## A repeatable change procedure

1. State the intended behavior and affected scope. Save the existing configuration
   or current record and its relevant inherited settings.
2. Prepare a small change. Review types, units, supported bounds and activation mode.
3. Validate it in your normal development/staging workflow. Keep the complete
   configuration around partial exports and full-replacement API operations.
4. Apply it using the appropriate deployment or management operation.
5. Check readiness and read back the effective value or saved record.
6. Verify behavior with an authorized test request and inspect its evidence. For
   capacity, recovery or routing-quality changes, run the corresponding qualification.
7. If the result is wrong, apply the reviewed rollback through the same mechanism
   and verify again. Reverting configuration does not undo requests or charges.

## Troubleshooting

| Symptom | First check |
|---|---|
| The UI shows the old value | Draft versus current state; successful fetch; restart/refresh requirement; the instance you are reading. |
| An `.env` edit appears ignored | Shell exports, Compose overrides and whether the container was recreated. |
| A downloaded file changed nothing | It must be merged into a configuration source your deployment loads. |
| A new group cannot be called | Group deployment, candidate records, key allow set and model discovery with the same key. |
| A provider is enabled but calls fail | Credential reference, endpoint/adapter and recorded probe result; enabled does not mean healthy. |
| A field is read-only | Activation mode, supported editor surface and your role. |
| A budget is smaller than the value you set | Effective inherited constraints and the scope that binds them. |

## Reference material

- [Environment settings and defaults](../reference/configuration.md): generated catalogue.
- [Resource limits and units](../reference/operational-limits.md).
- [Admin API](../reference/admin-api.md): authentication, request shapes and mutations.
- [Deployment guide](deploy.md): networking, persistence and rollout requirements.
- [Dashboard walkthrough](../tutorial/dashboard.md): screens and task explanations.

See [Dashboard configuration ownership](../reference/dashboard-configuration.md) for conditional registry edits, Jev partial deployment drafts, operational observations and intentional API/deployment-only scope.
