Project configurations
Workflow, Conversation and Kanban share one configuration model. Open Project configurations from the Studio or CLI Web toolbar, or the configuration tab in Server Web project details. Projects without declared fields can still add custom fields.
Declare fields
The project root configuration.json declares structure and safe defaults. Manage actual values in the panel:
{
"version": 1,
"fields": [
{ "name": "API_KEY", "type": "string", "secret": true, "required": true },
{ "name": "retries", "type": "number", "defaultValue": 2 },
{ "name": "enabled", "type": "boolean", "defaultValue": false },
{ "name": "regions", "type": "string", "multiple": true, "options": [{ "value": "east" }, { "value": "west" }] },
{ "name": "metadata", "type": "json", "defaultValue": { "tags": [] } }
]
}
Types are string, finite number, boolean, json and file. String fields support enum options. Optional properties are label, description, defaultValue, required, secret, control, options and accept. Defaults use native JSON types. Keep real sensitive values out of declarations. Configuration fields are separate from execution input parameters.
A file field lets users choose a local file and upload it to the connected Server, up to 50 MiB per file, using published field rules and account isolation (personal attachments do not require Server data write access). accept supports MIME types (such as image/png or image/*) and extensions (such as .json); mismatched files are rejected before upload. Successful uploads display the file name and take effect after saving the configuration. Failures preserve the previous reference. A single file value is server metadata containing id, name, mimeType, size and storage: "server", without local paths, file bytes or connection credentials. multiple: true means a string array for strings or up to 32 server file references for files. Clearing a value removes the configuration reference and keeps the server file.
{ "name": "imageFile", "type": "file", "label": "Map image", "accept": ["image/png", "image/jpeg", "image/webp", "image/gif"] }
Keys start with a letter or underscore and then allow letters, digits, underscores, dots and hyphens, up to 200 characters. Keys must be unique. Custom field definitions belong to the whole project, while each profile stores its own values. Users and assistants can create, edit, rename and delete custom fields. Declarations remain managed by configuration.json; custom fields cannot override them. Renaming a custom key updates every profile. Deleting it clears that key from every profile.
Manage profiles
Studio, CLI Web and Server Web open on a configuration list. The active profile has a highlighted row and an In use badge with an icon; other profiles offer a Use this configuration button. Click a profile name to open its details and edit its fields. The plus icon creates a profile; row actions copy, rename or delete it. Use this configuration explicitly changes the execution selection. Switching shows progress and disables duplicate actions; failure retains the previous selection and allows retrying. Viewing or saving another profile preserves that selection. Use Back to list in the detail header; save or discard unsaved values or publication rules before returning.
Import / export groups JSON operations and explains that exports include sensitive values. Export all profiles from the list or the viewed profile from its details. The fields section has its own Add field action, with pencil and trash icons beside custom fields. The save area shows draft status; its refresh icon discards the draft. Icons include action labels and support keyboard access.
Create, copy, rename, select and delete named profiles. At least one profile must remain. Edit fields directly, then click Save at the bottom to apply changes together. The reset icon beside a field removes its override and immediately restores the declared default, or clears and unsets it when there is no default. Untouched fields retain their existing state. Boolean values and multiple options keep their own checkboxes. Incomplete required fields may be saved; execution validates them. New declared fields use defaults, and removed fields no longer reach the runtime.
Removing a declaration or visiting another source version retains saved values, so restoring the field restores its value. A project declaration temporarily hides an existing custom definition with the same name; removing that declaration restores the custom definition. Runs and exports include only currently effective fields. Explicitly deleting a custom field still clears its value from every profile.
Writes check revision and commit atomically. Changes from another window or the assistant update committed state. Unsaved drafts keep their original version and content, with a conflict message. Refresh and discard the draft before editing again. Failed requests do not partially write data.
Studio, standalone CLI and CLI Web share local user storage. A valid UUID in package.json.id binds profiles, custom fields, values and the active selection to the application across windows and installation directories, with automatic updates. Different application IDs remain separate; directories without a valid application ID keep canonical real-path isolation. When no application store exists, first use adopts the current directory's existing profiles. Existing application data takes precedence over legacy values in another directory. Sessions and run state remain independent, and waiting runs retain their original directory-scoped configuration snapshots. Server storage is isolated by project and signed-in account. Accounts with project read access manage their own profiles. Values stay outside source files, source downloads and immutable source versions. Transfer configurations between local and Server storage with import/export.
Import and export
Export the current profile or all profiles as JSON with version: 1 and kind: "steamharness-project-configurations". The file includes field definitions and complete effective values, including sensitive values. Profiles contain names and values, without original IDs. File fields export complete server references, without binary content; imported references still require access to the original server and project files.
Import adds profiles with new IDs and preserves the active selection. Missing fields become custom fields. Conflicting types, multiple flags, options or accepted file types, undeclared value keys, invalid JSON/types and requests above 1 MiB reject the entire batch. No partial fields or profiles are written. Store exported sensitive values carefully.
Agent model list
Core Agent projects show AI models as the first field in configuration details. Add model and row edit actions open a separate dialog. A segmented source selector shows either the System AI or Third-party AI form. The saved list can contain both sources. Cancel or Escape discards only the model draft and restores focus to the list action.
In Studio and CLI Web, an empty model list in the active profile makes the Workflow and Conversation model button display Configure model. Click it to open the active profile directly at AI models. Failed Conversation messages offer the same action. Adding and saving a model restores the saved-model selector. Navigation preserves the message draft and execution profile; save or discard existing configuration or publication drafts before using the shortcut. The toolbar gear still opens the configuration list.
- System AI loads the current account's subscriptions on demand. Select Provider, then model; the display name comes from the model automatically, with no name input. Refreshing preserves the model draft. A removed selection never switches automatically to another subscription or model, and execution asks you to check its availability. An empty catalogue links to subscription management. A missing system AI connection does not prevent third-party setup.
- Third-party AI accepts a display name, model ID, API Key, Base URL and API protocol:
openai-completions,openai-responsesoranthropic-messages. Keys use password inputs and never appear in list rows. - Edit, delete or set a model as default in the list. Apply the model draft before saving the profile; unfinished drafts block saving or navigation. The first entry is the default. The composer only selects saved models and no longer manages Provider.
The list uses the reserved STEAMHARNESS_AGENT_MODELS JSON field with control: "ai-models". Core statically detects calls to createAgentNode, createAgentConversationProject, createAgentProjectParamResolver or defineAgentConversationExecutor and adds it without executing project code. Local configuration services update discovery after source changes without reopening the panel. For indirect wrappers that static discovery cannot see, declare the field explicitly in configuration.json with secret: true, defaultValue: [] and sharing: { "publish": true, "includeValue": false, "editable": true }.
To allow only system AI, explicitly declare the model field in the project's source configuration.json with allowThirdParty: false:
{
"version": 1,
"fields": [{
"name": "STEAMHARNESS_AGENT_MODELS",
"type": "json",
"control": "ai-models",
"allowThirdParty": false,
"secret": true,
"defaultValue": [],
"sharing": { "publish": true, "includeValue": false, "editable": true }
}]
}
Omitting the option or setting it to true keeps both sources available. With false, Studio, CLI Web and Server Web hide the source selector and third-party form. Direct saves, imports and assistant CRUD reject third-party entries; imported definitions cannot relax the project's declaration. Existing third-party entries remain available for inspection, full backups, deletion or replacement with system AI, but are excluded from runtime options. The first available system entry becomes the default. Core also rejects explicit URLs, API keys and injected model collections; remove custom direct-endpoint branches from the project. The rule freezes with the execution snapshot, including waiting-run recovery. Publishing the model field includes the rule without automatically including personal values. This is a source declaration, so someone holding a source copy can still edit the code.
Publication drafts, previews and downloaded templates all honor the source restriction; older drafts or templates cannot relax it. Distributed files retain it in top-level agentModelPolicy metadata even when the author excludes the entire model field. Drafts with historical third-party values remain editable and can be published when those values are excluded; including them prevents publication.
Every entry has a unique id, name, model and source. System entries use source: "system" and credentialId; third-party entries use source: "third-party", apiKind, baseUrl and apiKey. The model input parameter stores the list entry ID, which the runtime maps to the actual model ID. System execution verifies that the current account still has that subscription and model and never falls back to another subscription. Third-party execution calls its configured endpoint without requiring system AI sign-in.
Lists belong to named profiles and freeze with execution snapshots. Saving another profile preserves the execution selection; the next turn or run reads the selected profile. Model lists share import/export, revision checks, permissions and assistant CRUD with other configuration fields. Automatically added fields publish their structure without values by default, so keys are not automatically included in templates. Complete backups still contain keys and must be kept private.
Conversation and Studio Assistant support switching models within the same conversation. Editing, deleting or replacing configured models preserves completed replies and the model names recorded for those turns. Subsequent messages use the currently selected available model and retain conversation context. If the new model fails to start, that send operation returns the error while completed replies remain visible.
Runtime access
const token = steamharness.getConfig<string>("API_KEY");
const task = steamharness.defineProject({
name: "configured-task",
async run(input, context) {
return { errCode: 0, errMessage: "", enabled: context.config.enabled };
},
});
The SDK exposes ProjectConfigurationSnapshot, context.config and steamharness.getConfig(key). Parameter resolvers, executors, nodes and agents share an immutable execution scope. Configuration never enters global process.env. Outside an execution scope, getConfig returns undefined. Direct SDK callers may supply an explicit configuration snapshot or use createLocalProjectConfigurationStore(projectDir).
Explicit snapshots are also persisted by runId: resuming without configuration reuses the original values. Hosts that reload configuration for a durable session retaining its runId pass a new configurationRunId; resuming that generation must keep the same configurationRunId. The local store's snapshot({ runId, configuration }) also persists the supplied snapshot only on the first use of that identity.
- Workflow freezes configuration at execution start and reuses it when resuming a waiting task.
- Conversation uses current configuration on the next turn. Durable agents stop the old worker after current tasks, queued inputs and approvals finish, then reload with the next input's parameters while preserving history, branches and recovery state.
- Saving Kanban configuration updates both the main page and resource previews. HTML reads native values from
window.steamHarnessKanban.getConfiguration().paramsand listens forsteamharness:kanban-configuration-change. Previews with an explicit profile ID keep that reference; deleting the profile makes it unavailable.
Business configuration does not load .env, use .env.example, or fall back to process variables. Existing project env and old Kanban profiles are not migrated. Enter values again in the panel. Server deployment, CI and internal Studio transport variables remain host managed.
CLI and assistant tools
Use the same local storage without a UI through JSON input/output:
printf '%s' '{"action":"get"}' | steamharness configuration ./my-project
Studio Control exposes get_configurations, manage_configurations and open_configurations. Each tool accepts an input JSON string. Local requests specify storage: "local" and projectDir. Server requests specify storage: "server", projectId and target (draft, latest, or a version). The panel can be closed.
{
"storage": "local",
"projectDir": "/projects/my-project",
"call": { "action": "save", "revision": 3, "id": "profile-id", "values": { "enabled": true }, "unset": ["API_KEY"] }
}
Queries return fields, profiles, active ID and revision. Management actions are create, duplicate, rename, save, select, delete, field.save, field.delete and import. Query with export: true to export all profiles, optionally specifying id for one profile. Every mutation requires the queried revision; profile value operations also specify the ID. Read-only mode rejects management, and Studio retains its existing directory/project permission policy. Preserve proposed values, query again and reconcile conflicts before retrying.
Read Server configuration with GET /api/projects/:id/configurations?target=draft. Submit { "target": "draft", "call": { ... } } to POST /api/projects/:id/configurations. Success uses the standard errCode: 0 envelope. Conflicts return HTTP 409 and data.code: "CONFIGURATION_CONFLICT". Server stores static definitions and values without executing project code.
Sharing and permissions (v2)
Personal values, publication drafts and immutable version templates are separate. In Publication and permissions, authors select profiles and a default profile, then control publish (include the field), includeValue (carry its value) and editable (allow recipient edits) independently. Defaults are public fields, editable values and no carried values. defaultValue is filtered as a value too. Existing v1 projects keep their behavior until an author explicitly saves a publication draft; historical personal values are never automatically published.
Configuration fields have distinct bordered groups, and model lists mark their default entry. When publication management is unavailable, fields appear directly without a lone Configuration values tab. Authors retain both tabs. Server Web arranges configuration values in responsive columns, with inline boolean controls and wrapping multiple-choice options. Publication editors in Server Web, Studio, and CLI Web group profiles and the default selection in a compact toolbar and align field permissions in columns. Expand JSON paths when needed, use the action menu to refresh published values or fields, and use the eye icon to preview the recipient configuration.
{
"version": 2,
"fields": [
{ "name": "privateToken", "type": "string", "secret": true, "sharing": { "publish": false } },
{ "name": "userToken", "type": "string", "secret": true },
{ "name": "endpoint", "type": "string", "defaultValue": "https://api.example.com", "sharing": { "includeValue": true, "editable": false } },
{ "name": "preferences", "type": "json", "defaultValue": { "region": "default", "theme": "auto" }, "sharing": { "includeValue": true }, "paths": { "/region": { "editable": false } } }
]
}
Object paths use JSON Pointer: encode / as ~1 and ~ as ~0. Children inherit parent rules, with more specific rules taking precedence. Excluding an entire field excludes all its descendants. Arrays are indivisible. The panel offers property controls and raw JSON editing; the service checks actual changes at every path. Parent replacement, clearing, imports and assistant operations cannot bypass locks. Invalid batches are rejected atomically with CONFIGURATION_FORBIDDEN (HTTP 403). Required locked fields need a published value.
When an excluded JSON parent explicitly publishes a child, that child retains its inherited value inclusion and editing rules. Filtering the parent does not remove the child's lock.
Inspect the recipient preview before saving. Drafts freeze selected profile values; after changing personal values, explicitly refresh published values and save the draft again. Publication checks the source digest and draft revision, then generates filtered configuration.json, configuration.template.json and configuration-assets/ in a staging directory without changing the author's files. Published templates are fixed to project versions. Source downloads, share links and Store deliver the same version bundle. Complete backups still contain every readable value and are separate from sharing templates.
Maintainers, owners and system administrators can manage official drafts and templates. Developers may publish prepared project versions but cannot change official rules. Downloads, copied projects or client role parameters never grant access to the original project. Recipients manage personal profiles and custom fields, while author definitions, permissions and templates remain immutable. Runtime snapshots combine the template with permitted personal values. Personal profiles store actual overrides only, so untouched initial values follow template upgrades. Upgrades preserve permitted personal changes and custom fields, stop applying newly locked overrides and retain type conflicts as drafts for resolution. Running or waiting Workflow tasks retain their original snapshot.
Publication copies referenced attachments into immutable version files and excludes unshared files. Downloads verify source and attachment digests and cache validated templates and bytes outside source. Validated versions and permitted personal edits work offline; official changes, publication and new version downloads require a connection. Newly selected files must upload successfully before saving. Downloaded bundles contain only the corresponding template and selected attachments. Reading live project data requires current guest access.
When source changes to an unverified template, configuration reads and writes require downloading that version online first. Personal values stay intact, and running tasks can resume their original snapshots. Attachment uploads use the current verified version's permissions, independently of permission changes in the latest version.
API and assistant access
GET /api/projects/:id/configurationsreturns personal profiles,fieldCapabilitiesand lock reasons; authors also receivepublicationand the currentsourceHash. For v2 projects, non-managers default to the latest published template even when they may read source drafts. Unpublished role-controlled configurations require publishing a template first.POST /api/projects/:id/configurationsacceptspublication.save(revisionpluspublication, including its ownrevision, fields, profiles anddefaultConfigurationId) andpublication.preview. Draft conflicts return HTTP 409.GET /api/projects/:id/configurations/template?target=1.0.0reads published templates only.POST /api/projects/:id/configurations/files?target=1.0.0&key=background&fileName=map.png&mimeType=image/pnguploads personal attachments using the specified version's permissions;GET /api/projects/:id/configurations/files/:fileId?target=1.0.0reads authorized attachments only.POST /api/projects/:id/publishtakesexpectedSourceHash,expectedVersionandexpectedConfigurationRevision, the publication draft revision.
Studio Control get_configurations returns permissions; preview: true requests a recipient preview. manage_configurations supports publication.save. Both work with the panel closed. Official changes require online Server storage and maintainer or owner authorization. Read-only mode rejects writes.
Distributed templates omit excluded field and child-path names. Generated opaque rule hashes retain collision and hidden-path checks; they do not replace authenticated source download and integrity verification.
Business roles combine project and ancestor-group memberships. Guests may manage personal configurations within published field rules. Managing official configurations and publication rules requires maintainer access. Local configurations and frozen execution snapshots retain their existing behavior.
Restrict profiles by project role
Declare profilePolicy in configuration.json v2 to bind runtime modes to roles. Projects without this policy keep their existing personal configuration behavior.
{
"version": 2,
"fields": [{"name":"MODE","type":"string","sharing":{"publish":true,"includeValue":true,"editable":false}}],
"profilePolicy": {
"version": 1,
"defaultProfileKey": "ask",
"manageMinimumRole": "developer",
"profiles": [
{"key":"ask","name":"Ask","minimumRole":"guest","fixedValues":{"MODE":"ask"},"tags":["Read only"]},
{"key":"build","name":"Build","minimumRole":"developer","fixedValues":{"MODE":"build"},"tags":["Collect and write"]}
]
}
}
key is a stable source-owned identity. minimumRole uses effective project and inherited group roles: guest, developer, maintainer, and owner. Optional description and tags supply list summaries without exposing secrets. All base profiles fix the same set of fields. Fixed assignments override personal values and cannot be cleared. The default must be available to guests, and fixed values must be included in published templates.
Guests see only accessible base profiles. They may edit author-approved values, including models, but cannot create, copy, rename, delete, import, or manage fields. Users meeting manageMinimumRole may manage personal profiles; each inherits its profileKey, minimum role, and fixed assignments. Names, tags, imported metadata, and templateId cannot lower permission requirements. Base names and identities remain source-owned. Responses include capabilities, configurationCapabilities, and lock reasons. Opening details does not select a runtime profile; the composer displays a read-only mode label.
Restricted local values are scoped by application, Server, and account, and shared between windows of the same account. Signed-out users and failed online checks get only the guest default; previous Build permission is not reused. Reads and parameter discovery use a short-lived role cache rather than requests on each keystroke. Writes, sends, queue starts, restores, and restricted tool calls recheck online authority. Conversation history, stored personal values, and editing drafts are preserved; a draft does not grant authority.
Supplied configuration snapshots and resumed runs revalidate the current account, role, stable identity, and fixed assignments. Unauthorized profiles are rejected; an active Build task is never silently continued as Ask. Published templates freeze the policy using version 3, which unsupported hosts must reject with an upgrade prompt. Projects can check steamharness.getProjectConfiguration()?.profilePolicyVersion. Personal exports and configuration responses include only visible profiles and attachments; source archives still carry the complete official template and never automatically include personal credentials.
Server authorizes the actual authenticated actor and inherited roles, ignoring client roles and tags. Maintainers and above keep official template management. Studio Control uses the same service even with the panel closed; read-only mode additionally rejects writes. This policy does not prevent users from modifying their own source copies.
Supplied and restored run snapshots also enforce official field and JSON-path locks and the current source system-only AI policy. Waiting runs record their verified template and retain its values across upgrades; the current role, fixed mode and model-source restrictions still apply. Omitting or relaxing agentModelPolicy cannot enable third-party models.