Coder profiles
On this page
- Before you call
- Profile keys
- The hard tier
- How long a build may run
- How much context an OpenCode or Pi build gets
- The profile object
- Read profiles
- GET /api/v1/factory/coder-profiles
- GET /api/v1/factory/coder-profiles/{key}
- GET /api/v1/factory/coder-profiles/{key}/history
- Change a profile for your workspace
- PUT /api/v1/factory/coder-profiles/{key}/override
- DELETE /api/v1/factory/coder-profiles/{key}/override/{field}
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 |
|---|---|---|---|---|
|
|
| 400 turns | 180 min |
| the account's default |
| none | 180 min |
| the model the card pins |
| 500 steps | 180 min |
|
|
| 300 steps | 180 min |
|
|
| 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 |
|---|---|---|
| string | The profile key, such as |
| string |
|
| string |
|
| array of strings | The cards the profile is meant for: a task type for a task-type profile, one sentence for a hard profile |
| string or null | The model; |
| string or null | The reasoning effort the coder is started with |
| string or null | Always |
| integer or null | Claude's turn guard |
| integer or null | OpenHands' and OpenCode's step guard |
| number or null | The time limit the profile asks for (see above) |
| object or null | OpenHands settings the desk applies; platform only |
| string | Why the platform chose these values |
| string |
|
| object |
|
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.
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 |
|---|---|---|
| no token, or the token is not valid | send |
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.
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 |
|---|---|---|
| no token, or the token is not valid | send a live token |
| no profile has that key, or its coder is not available to your workspace | list the profiles and use a returned |
GET /api/v1/factory/coder-profiles/{key}/history
Returns every change your workspace made to one profile, newest first. A profile nobody changed returns [].
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 |
|---|---|---|
| no token, or the token is not valid | send a live token |
| no profile has that key, or its coder is not available to your workspace | use a |
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.
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 |
|---|---|---|
| string |
|
| string |
|
| integer | From 1 up to the profile's |
Errors
Status | When | Resolution |
|---|---|---|
| no token, or the token is not valid | send a live token |
| you are not an admin of this workspace | ask an admin, or make the change in Coder settings as one |
| no profile has that key, or its coder is not available to your workspace | use a |
| the body is empty | send |
| the body names | send only |
| the body names any other unknown field, such as | send only |
|
| leave |
|
| pin the model on the card instead |
| any other model name | use one of the two names |
|
| leave |
| any other effort, including | use |
|
| leave |
|
| send an integer of 1 or more |
|
| send a value up to |
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.
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 |
|---|---|---|
| no token, or the token is not valid | send a live token |
| you are not an admin of this workspace | ask an admin |
| no profile has that key, or its coder is not available to your workspace | use a |
|
| use one of the three |
| the profile has no such setting, such as | nothing to reset; leave it |