# Coder profiles

Source: https://opvs.ai/docs/guides/coder-profiles

> A coder profile is the set of settings a builder uses for one card: the model, the effort, a turn or step guard, and how long the build may run.

A coder profile is the set of settings a builder uses for one card: the model, the effort, a turn or step guard, and how long the build may run. OPVS keeps one catalog of profiles. A card names the profile it wants, the builder's desk fetches it when the build starts, and your workspace can change three of its settings. The dashboard's **Coder settings** page uses the same routes.

## Before you call

Every route takes a personal access token, `Authorization: Bearer $OPVS_PAT`, and acts on the workspace the token belongs to. No extra token scope is needed.

Group

Who may call

Token scope

Read profiles and their history

any active member

any

Change or reset a setting

a workspace admin

any

A change applies to builds that **start** after it. A build already running keeps the settings it started with.

## Profile keys

A key is `<coder>.<tier>`. The coders your workspace can use are `claude`, `codex`, `openhands`, `opencode` and `pi`; the `coder` field of a profile spells Claude as `claude_code`. The tiers are the five card task types, `coding`, `docs`, `research`, `design` and `test`, plus `hard`.

To use a profile, put its key in the card's `agent_context.profile`, for example `codex.coding`. A desk whose coder does not match the key skips the profile and builds with its own defaults; a profile never fails a build.

### The hard tier

Every coder has a `.hard` profile for risky or large cards, such as sidecar, migration, security or billing work. It uses the highest effort and the largest turn or step guard that coder takes, and lets the build run for 180 minutes. The dashboard's Coder profiles page shows only the five task-type profiles of each coder, so read and change the hard tier through these routes.

Key

Model

Effort

Guard

Time limit

`claude.hard`

`claude-opus-5-5`

`max`

400 turns

180 min

`codex.hard`

the account's default

`high`

none

180 min

`openhands.hard`

the model the card pins

`high`

500 steps

180 min

`opencode.hard`

`MiniMax-M3`

`high`

300 steps

180 min

`pi.hard`

`MiniMax-M3`

`high`

none

180 min

### How long a build may run

A profile's `limits.wall_minutes` asks for a time limit; the desk decides. A build gets the desk's own limit (120 minutes unless the desk owner changed it) or the profile's request, whichever is longer, and never more than the desk's ceiling (240 minutes by default). A profile with `wall_minutes: null` runs on the desk's own limit. `wall_minutes` cannot be changed per workspace.

### How much context an OpenCode or Pi build gets

An OpenCode or Pi build takes its context window and output limit from the model it runs. The build's output limit is the model's own, capped at the desk's output limit (131,072 tokens) and at half the window less 16,384 tokens, and the build compacts its conversation early enough that this output plus 16,384 tokens still fits in the window. A model with a 262,144 token window, for example, builds with an output limit of 114,688 and compacts with 131,072 tokens to spare.

The model list a card can be pinned to, `GET /api/v1/factory/subscriptions/servable`, shows each model's `context_window` and `max_output`. A desk's own fallback values describe `MiniMax-M3` only. A build on any other model whose `context_window` and `max_output` are both `null` therefore stops before the coder starts, and its run records the failure cause `harness_limits_unknown`. Pin such a card to a model that lists its limits.

## The profile object

Field

Type

Meaning

`key`

string

The profile key, such as `codex.hard`

`version`

string

`sha256:` and 12 hex characters, a digest of the settings a build receives. It changes when any of them change

`coder`

string

`claude_code`, `codex`, `openhands`, `opencode` or `pi`

`recommended_for`

array of strings

The cards the profile is meant for: a task type for a task-type profile, one sentence for a hard profile

`model`

string or null

The model; `null` means the coder's own default, or for OpenHands the model the card pins

`effort`

string or null

The reasoning effort the coder is started with

`fallback_model`

string or null

Always `null` today

`limits.max_turns`

integer or null

Claude's turn guard

`limits.max_steps`

integer or null

OpenHands' and OpenCode's step guard

`limits.wall_minutes`

number or null

The time limit the profile asks for (see above)

`env`

object or null

OpenHands settings the desk applies; platform only

`reason`

string

Why the platform chose these values

`sources.model`, `sources.effort`, `sources.limit_value`

string

`platform`, or `brand` when your workspace changed that setting

`platform_defaults`

object

`model`, `effort` and `limit_value` as the platform sets them: what a reset returns to

`limit_value` is the turn guard for a Claude profile and the step guard for an OpenHands or OpenCode profile.

## Read profiles

### `GET /api/v1/factory/coder-profiles`

Returns every profile your workspace can use, with your workspace's changes applied.

```bash
curl "https://api.opvs.ai/api/v1/factory/coder-profiles?coder=codex&task_type=coding" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200, application/json
# [{"key": "codex.coding", "version": "sha256:77f8246408d6", "coder": "codex",
#   "recommended_for": ["coding"], "model": null, "effort": "high",
#   "fallback_model": null,
#   "limits": {"max_turns": null, "max_steps": null, "wall_minutes": null},
#   "env": null,
#   "reason": "Seat requires the account-default model; owner-equivalent high effort",
#   "sources": {"model": "platform", "effort": "platform", "limit_value": "platform"},
#   "platform_defaults": {"model": null, "effort": "high", "limit_value": null}}]

# Without a token the route returns a 401 error.
```

**Query parameters:** `coder` (string, optional): one coder, such as `codex`. `task_type` (string, optional): profiles recommended for that task type. A value that matches nothing returns `[]`. Hard profiles carry a sentence in `recommended_for`, so `task_type` does not select them: read them by key.

**Errors**

Status

When

Resolution

`401`

no token, or the token is not valid

send `Authorization: Bearer $OPVS_PAT` with a live token

### `GET /api/v1/factory/coder-profiles/{key}`

Returns one profile, with your workspace's changes applied. This is the call a desk makes when a build starts.

```bash
curl "https://api.opvs.ai/api/v1/factory/coder-profiles/codex.hard" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200, application/json
# {"key": "codex.hard", "version": "sha256:0fd3789f000f", "coder": "codex",
#  "recommended_for": ["Risky or large cards, especially sidecar, migration, security, or billing work"],
#  "model": null, "effort": "high", "fallback_model": null,
#  "limits": {"max_turns": null, "max_steps": null, "wall_minutes": 180.0},
#  "env": null,
#  "reason": "Hard tier: account-default Codex model, highest effort, and extended wall time",
#  "sources": {"model": "platform", "effort": "platform", "limit_value": "platform"},
#  "platform_defaults": {"model": null, "effort": "high", "limit_value": null}}

# A key that does not exist returns a 404 error.
```

**Errors**

Status

When

Resolution

`401`

no token, or the token is not valid

send a live token

`404` `Not found`

no profile has that key, or its coder is not available to your workspace

list the profiles and use a returned `key`

### `GET /api/v1/factory/coder-profiles/{key}/history`

Returns every change your workspace made to one profile, newest first. A profile nobody changed returns `[]`.

```bash
curl "https://api.opvs.ai/api/v1/factory/coder-profiles/claude.hard/history" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200, application/json (one change shown)
# [{"id": 41, "profile_key": "claude.hard", "field": "effort",
#   "old_value": null, "new_value": "high",
#   "actor_user_id": 482, "actor_role": "brand_admin",
#   "created_at": "2026-10-16T12:04:51.203117Z"}]

# A key that does not exist returns a 404 error.
```

**Response:** `field` is `model`, `effort` or `limit_value`. `old_value` and `new_value` are strings, or `null` when the setting was at the platform default. `actor_role` is `brand_admin` or `platform_admin`.

**Errors**

Status

When

Resolution

`401`

no token, or the token is not valid

send a live token

`404` `Not found`

no profile has that key, or its coder is not available to your workspace

use a `key` from the profile list

## Change a profile for your workspace

A workspace admin can change three settings of any profile: `model`, `effort` and `limit_value`. Each change is recorded in the history. Everything else, including the time limit, stays as the platform sets it.

### `PUT /api/v1/factory/coder-profiles/{key}/override`

Sets one or more settings and returns the profile as builds will now receive it. Settings you leave out keep their current value.

```bash
curl -X PUT "https://api.opvs.ai/api/v1/factory/coder-profiles/claude.hard/override" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"effort": "high", "limit_value": 300}'

# Response 200, application/json
# {"key": "claude.hard", "version": "sha256:814f7fca5264", "coder": "claude_code",
#  "recommended_for": ["Risky or large cards, especially sidecar, migration, security, or billing work"],
#  "model": "claude-opus-5-5", "effort": "high", "fallback_model": null,
#  "limits": {"max_turns": 300, "max_steps": null, "wall_minutes": 180.0},
#  "env": null,
#  "reason": "Hard tier: strongest Claude model and effort, largest turn guard, and extended wall time",
#  "sources": {"model": "platform", "effort": "brand", "limit_value": "brand"},
#  "platform_defaults": {"model": "claude-opus-5-5", "effort": "max", "limit_value": 400}}

# A member who is not an admin gets a 403 error; a value the profile does not take gets a 422 error.
```

**Request body** (send at least one):

Field

Type

Accepted values

`model`

string

`claude-opus-5-5` or `claude-sonnet-5`. Codex and OpenHands profiles take no model

`effort`

string

`low`, `medium` or `high`. OpenHands profiles take no effort

`limit_value`

integer

From 1 up to the profile's `platform_defaults.limit_value`. Only a profile with a turn or step guard takes one

**Errors**

Status

When

Resolution

`401`

no token, or the token is not valid

send a live token

`403` `Brand admin access required`

you are not an admin of this workspace

ask an admin, or make the change in Coder settings as one

`404` `Not found`

no profile has that key, or its coder is not available to your workspace

use a `key` from the profile list

`422` `Set at least one override field`

the body is empty

send `model`, `effort` or `limit_value`

`422` `<field> is platform-only and cannot be overridden`

the body names `fallback_model`, `tools`, `permissions`, `credentials`, `env` or `OPVS_OH_VENV`

send only `model`, `effort` or `limit_value`

`422` `<field> is not an editable coder profile field`

the body names any other unknown field, such as `wall_minutes`

send only `model`, `effort` or `limit_value`

`422` `Codex doesn't take a model choice in a profile`

`model` on a Codex profile

leave `model` out; Codex uses the account's default model

`422` `OpenHands profiles take their model from the build, not the profile`

`model` on an OpenHands profile

pin the model on the card instead

`422` `model must be one of: claude-opus-5-5, claude-sonnet-5`

any other model name

use one of the two names

`422` `OpenHands doesn't take an effort choice in a profile`

`effort` on an OpenHands profile

leave `effort` out

`422` `effort must be one of: low, medium, high`

any other effort, including `max`

use `low`, `medium` or `high`; reset the field to return to the platform's value

`422` `This profile doesn't take a limit choice`

`limit_value` on a profile whose `platform_defaults.limit_value` is `null`

leave `limit_value` out

`422` `limit_value must be from 1 up to the platform default of 400`

`limit_value` is not a whole number, or is below 1

send an integer of 1 or more

`422` `500 is above the platform limit of 400 for this profile. Lower it, or leave it at the platform default.`

`limit_value` is above the platform default

send a value up to `platform_defaults.limit_value`

The numbers in the last two messages are the profile's own platform default; `400` and `500` are an example.

### `DELETE /api/v1/factory/coder-profiles/{key}/override/{field}`

Returns one setting to the platform's value and returns the profile as builds will now receive it. `{field}` is `model`, `effort` or `limit_value`. Resetting a setting your workspace never changed changes nothing and returns the profile.

```bash
curl -X DELETE "https://api.opvs.ai/api/v1/factory/coder-profiles/claude.hard/override/effort" \
  -H "Authorization: Bearer $OPVS_PAT"

# Response 200: the profile, with "effort": "max" and sources.effort = "platform" again.
# A member who is not an admin gets a 403 error.
```

**Errors**

Status

When

Resolution

`401`

no token, or the token is not valid

send a live token

`403` `Brand admin access required`

you are not an admin of this workspace

ask an admin

`404` `Not found`

no profile has that key, or its coder is not available to your workspace

use a `key` from the profile list

`422` `<field> is platform-only and cannot be overridden` or `<field> is not an editable coder profile field`

`{field}` is not `model`, `effort` or `limit_value`

use one of the three

`422` with the same message as the PUT

the profile has no such setting, such as `model` on a Codex profile

nothing to reset; leave it
