---
document: solvotix-agent-guide
document_version: "1.0"
language: en
audience: autonomous-coding-agent
read_mode: sequential
api_base_url: https://backend.solvotix.org
openapi_url: https://backend.solvotix.org/v3/api-docs
swagger_url: https://backend.solvotix.org/swagger-ui/index.html
manifest_url: https://solvotix.net/ai-first/agent-manifest.json
authentication: solvotix-api-user-token
tenant_header: Tenant
status: live
---

# SOLVOTIX AGENT EXECUTION GUIDE

## 0. EXECUTION DIRECTIVE

You are integrating software with the Solvotix physical-device platform.

Follow these instructions in order.

1. Read this document completely before changing code.
2. Retrieve the live OpenAPI document before selecting endpoints or generating types.
3. Treat OpenAPI as authoritative for paths, methods, parameters, schemas, and documented responses.
4. Use this document as authoritative for sequencing, physical semantics, verification, risk, and approval rules.
5. Do not invent endpoints, fields, device capabilities, success states, or retry behavior.
6. Begin with authentication and read-only discovery.
7. Do not execute a physical operation until the tenant, device ID, device type, and real-world purpose are known.
8. An HTTP success response can mean accepted or queued. It does not prove physical completion.
9. Verify physical operations through queue state, events, and current device state when available.
10. Never expose tokens, passwords, refresh tokens, Wi-Fi credentials, access codes, private keys, or service-account files.
11. Never automatically retry a non-idempotent physical command.
12. Stop and report uncertainty when this guide, OpenAPI, inventory, and observed state disagree.

## 1. MACHINE RESOURCES

```yaml
html_guide: https://solvotix.net/ai-first/agent-guide
raw_markdown: https://solvotix.net/ai-first/agent-guide.md
structured_manifest: https://solvotix.net/ai-first/agent-manifest.json
openapi_json: https://backend.solvotix.org/v3/api-docs
swagger_ui: https://backend.solvotix.org/swagger-ui/index.html
production_api: https://backend.solvotix.org
```

Preferred read order:

1. `agent-manifest.json`
2. `agent-guide.md`
3. live OpenAPI JSON
4. project-local conventions and existing generated clients

## 2. REQUIRED INPUTS

```text
SOLVOTIX_API_BASE_URL=https://backend.solvotix.org
SOLVOTIX_API_TOKEN=<sat_ token copied from the Solvotix portal>
SOLVOTIX_TENANT_ID=<tenant selected when the API user was created>
```

If the API token or its tenant ID is unavailable, stop and ask the system owner to create an API user in the Solvotix portal. Do not request human login credentials, create placeholder tokens, or embed a token in source code.

## 3. SYSTEM MODEL

```text
agent/application
  -> Solvotix REST API
  -> authenticated tenant context
  -> persistent command queue
  -> selected gateway
  -> physical device
  -> queue result / event / device state
```

```yaml
entities:
  api_user: tenant-bound Solvotix machine identity
  tenant: isolated organization, site, or installation
  gateway: connection between Solvotix Cloud and local devices
  sensor: generic API model for a connected node or device
  message_frame: hardware command accepted or queued by the backend
  event: structured hardware or system activity record
  queue: command delivery state between backend, gateway, and device
```

## 4. OPENAPI ACQUISITION

Retrieve the current specification:

```bash
curl --fail --silent --show-error \
  https://backend.solvotix.org/v3/api-docs \
  --output solvotix-openapi.json
```

Validate all of the following:

```yaml
required_top_level_fields:
  - openapi
  - info
  - servers
  - paths
  - components
required_component_fields:
  - schemas
required_security_scheme:
  name: bearerAuth
  type: http
  scheme: bearer
  bearer_format: JWT
```

OpenAPI processing algorithm:

```text
1. Validate the document structure.
2. Select https://backend.solvotix.org as the production server.
3. Index operations by tag, operationId, method, and path.
4. Resolve every local $ref.
5. Read request parameters and requestBody schemas.
6. Read every documented response schema and status.
7. Generate types using the project's existing generator when one exists.
8. Place authentication, tenant selection, safety, and retry behavior in a wrapper.
9. Never edit generated client files directly.
10. Record the OpenAPI info.version, retrieval time, and content hash.
```

Optional client generation:

```bash
npx @openapitools/openapi-generator-cli generate \
  -i https://backend.solvotix.org/v3/api-docs \
  -g typescript-fetch \
  -o generated/solvotix

openapi-generator-cli generate \
  -i https://backend.solvotix.org/v3/api-docs \
  -g python \
  -o generated/solvotix
```

Conflict rule:

```yaml
if_written_example_conflicts_with_openapi:
  action: stop
  report:
    - operation
    - written_value
    - openapi_value
    - proposed_resolution
  forbidden: guessing
```

## 5. CREATE THE SOLVOTIX SYSTEM AND API USER

API users are machine identities for integrations, scripts, and external systems. An API user belongs to exactly one tenant, uses a long-lived bearer token, does not require an interactive user account at runtime, can expire, and can be revoked or rotated.

Human setup sequence:

1. Open `https://portal.solvotix.org/login`.
2. Press **Register here** and create the Solvotix system owner account.
3. Sign in and open `https://portal.solvotix.org/home/settings#system-users`.
4. Select the target tenant/system.
5. Create an API user with a descriptive integration name and an expiration date when appropriate.
6. Copy the displayed `sat_...` token immediately.
7. Store the token in a secrets manager or protected environment variable.
8. Record the tenant ID selected during creation.

The plaintext token is displayed only when the API user is created or rotated. It cannot be retrieved later.

```yaml
api_user:
  identity_type: machine
  belongs_to_tenants: exactly-one
  token_prefix: sat_
  token_lifetime: long-lived
  expiration: optional
  revocable: true
  rotatable: true
  runtime_interactive_account_required: false
  may_manage_api_users: false
```

## 6. STORE THE TOKEN

```text
SOLVOTIX_API_TOKEN=sat_REPLACE_WITH_COPIED_TOKEN
SOLVOTIX_TENANT_ID=REPLACE_WITH_BOUND_TENANT_ID
```

Mandatory token rules:

```yaml
token_storage:
  permitted:
    - secrets manager
    - protected server environment variable
  forbidden:
    - frontend or browser bundle
    - Git repository
    - URL or query parameter
    - application log
    - analytics event
    - error report
on_exposure: rotate immediately in the Solvotix portal
```

Do not build an API-token integration as browser-only code. The token grants broad access inside its bound tenant and must remain on a trusted server.

## 7. API-USER AUTHENTICATION

Every API request uses the copied token in the standard bearer header:

```http
GET /api/sensor
Authorization: Bearer sat_<TOKEN>
Tenant: <TENANT_ID>
Accept: application/json
```

```bash
curl "https://backend.solvotix.org/api/sensor" \
  -H "Authorization: Bearer $SOLVOTIX_API_TOKEN" \
  -H "Tenant: $SOLVOTIX_TENANT_ID" \
  -H "Accept: application/json"
```

The `sat_` prefix tells the backend to authenticate a Solvotix API user.

```yaml
authorization_header: Authorization
authorization_format: Bearer sat_<TOKEN>
tenant_header: Tenant
tenant_header_recommended: true
tenant_derived_from_token_when_omitted: true
tenant_mismatch_result: 401 Unauthorized
token_refresh_flow: none
token_rotation: human owner action in portal
```

The token is bound to the tenant selected during creation. Never substitute another tenant ID. Although the backend can derive tenant context from the token, include the `Tenant` header for consistency with generated clients and existing API calls.

## 8. VERIFY AUTHENTICATION

Use a read-only endpoint from the live OpenAPI specification. Start with device inventory:

```http
GET /api/sensor
Authorization: Bearer sat_<TOKEN>
Tenant: <TENANT_ID>
```

Interpret failures:

```yaml
401:
  possible_causes:
    - token missing
    - token malformed
    - token expired
    - token revoked
    - Tenant header does not match token tenant
  action: stop and ask system owner to verify or rotate the API user
403:
  possible_causes:
    - API user attempted API-user credential management
    - operation is not permitted for this identity
  action: stop; do not attempt privilege escalation
```

## 9. API-USER LIFECYCLE BOUNDARY

The integration cannot create, list, rotate, or revoke API users. Those operations require an authenticated regular portal user with tenant membership.

The current API-user implementation does not provide per-token scopes. A token has normal authenticated access within its bound tenant. Create API users only for trusted integrations and isolate each integration with its own token so it can be revoked or rotated independently.

```yaml
credential_management:
  portal: https://portal.solvotix.org/home/settings#system-users
  performed_by: human tenant member
  create: POST /api/api-users
  list: GET /api/api-users
  rotate: POST /api/api-users/{id}/rotate
  revoke: DELETE /api/api-users/{id}
  api_user_calling_management_endpoint: 403 Forbidden
rotation_effect:
  old_token: invalid-immediately
  new_token_visibility: one-time
  revoked_user_reenabled: true
  expiration_preserved: true
access:
  tenant_boundary: enforced
  per_token_scopes_supported: false
  trust_requirement: trusted-integration-only
```

When a runtime request returns `401`, do not attempt an interactive sign-in. Stop and request API-user verification or rotation from the system owner.

## 10. READ-ONLY DISCOVERY

Execute in this order:

```yaml
steps:
  - method: GET
    path: /api/gateways
    purpose: list tenant gateways
  - method: GET
    path: /api/sensor
    purpose: list tenant devices
  - method: GET
    path: /api/gateways/{gatewayId}/sensors
    purpose: map devices to gateways
  - method: GET
    path: /api/gateways/{gatewayId}/metering/latest
    purpose: inspect gateway metering
  - method: GET
    path: /api/sensor/{deviceId}/pairings
    purpose: inspect device relationships
```

Build this inventory:

```yaml
device_inventory_fields:
  - id
  - name
  - type
  - online_state
  - gateway_ids
  - configuration
  - paired_device_ids
  - supported_operations_from_openapi
  - known_real_world_purpose
```

Do not map a generic `sensor` to an operation until its device type and compatible endpoint are established.

## 11. CLAIMING DEVICES

```text
GET  /api/sensor/{deviceId}/taken
POST /api/gateways/{gatewayId}/{urlEncodedName}
POST /api/sensor/{deviceId}/claim/{urlEncodedName}
```

```yaml
operation_class: ownership-changing
approval_required: true
preconditions:
  - target tenant confirmed
  - physical identifier confirmed
  - current ownership checked
automatic_retry: false
```

## 12. SMART LOCK RECIPES

### 12.1 Pulse-open

```yaml
operation: pulse_open_smart_lock
risk: physical
approval_required: true
idempotent: false
method: POST
path: /api/smartlocks/{lockId}/pulse-open
body: null
preconditions:
  - lockId belongs to selected tenant
  - device type supports smart-lock operations
  - door purpose is known
success_meaning: command accepted or queued
physical_completion_confirmed: false
verification:
  - inspect device queue
  - inspect sensor events
  - re-read device state when available
automatic_retry: forbidden
```

Prefer `pulse-open` for ordinary access. Persistent operations require stronger confirmation:

```text
POST /api/smartlocks/{lockId}/open
POST /api/smartlocks/{lockId}/close
```

### 12.2 Add access codes

```http
POST /api/smartlocks/{lockId}/codes/add
Content-Type: application/json
```

```json
{ "codes": ["1234", "98765"] }
```

```yaml
risk: security-sensitive
approval_required: true
code_constraint: 4-7 digits per current backend documentation
log_codes: forbidden
automatic_retry: forbidden
verification:
  - GET /api/smartlocks/{lockId}/codes/slots
  - inspect queue and related events
```

Remove selected codes with `POST /api/smartlocks/{lockId}/codes/remove`.

Delete all codes with `DELETE /api/smartlocks/{lockId}/codes`. This is destructive and requires explicit confirmation.

### 12.3 Configure a lock

```http
PUT /api/smartlocks/{lockId}/configuration
Content-Type: application/json
```

```json
{
  "soundEnabled": true,
  "lightEnabled": false,
  "openSeconds": 6
}
```

Resolve the live request schema before use.

## 13. RELAY RECIPES

```text
POST /api/relay/{relayId}/open
POST /api/relay/{relayId}/open-until-closed
POST /api/relay/{relayId}/close
POST /api/relay/{relayId}/pulse/ms/{milliseconds}
POST /api/relay/{relayId}/pulse/seconds/{seconds}
POST /api/relay/{relayId}/pulse/minutes/{minutes}
POST /api/relay/{relayId}/pulse-open
```

```yaml
risk: physical-or-operationally-dangerous
approval_required: true
idempotent: false
mandatory_preconditions:
  - relay real-world purpose known
  - safe duration known
  - target device and tenant confirmed
warning: relay may operate a door, heater, motor, appliance, or alarm interface
automatic_retry: forbidden
```

Set default pulse duration:

```http
PUT /api/relay/{relayId}/default-milliseconds
Content-Type: application/json
```

```json
{ "openMilliseconds": 150 }
```

## 14. THERMOSTAT AND TEMPERATURE RECIPES

```http
POST /api/thermostat/{thermostatId}/target-temperature
Content-Type: application/json
```

```json
{
  "temperature": 21.0,
  "gw_id": "<OPTIONAL_GATEWAY_ID>"
}
```

```text
POST /api/thermostat/{thermostatId}/on
POST /api/thermostat/{thermostatId}/off
POST /api/thermostat/{thermostatId}/restart
POST /api/thermostat/{thermostatId}/wifi
POST /api/thermostat/{thermostatId}/delete-wifi
GET  /api/temperature-control/stats
GET  /api/temperature-control/history/{sensorId}
```

Wi-Fi credentials are secrets. Never print or persist them outside the intended secret store.

## 15. DEVICE PAIRING

```http
PUT /api/sensor/{sensorId}/pairings
Content-Type: application/json
```

```json
{
  "sensorIds": [
    "<PAIRED_DEVICE_ID_1>",
    "<PAIRED_DEVICE_ID_2>"
  ]
}
```

```yaml
read_current: GET /api/sensor/{sensorId}/pairings
fetch_from_hardware: POST /api/sensor/{sensorId}/pairings/fetch
risk: configuration-changing
approval_required: true
verification: compare stored and fetched pairings
```

## 16. FIRMWARE LIFECYCLE

```text
GET    /api/node-updates/firmwares
POST   /api/node-updates/sensors/{sensorId}
DELETE /api/node-updates/sensors/{sensorId}
DELETE /api/node-updates/sensors/{sensorId}/queue
```

Start payload:

```json
{ "version": "<AVAILABLE_VERSION>" }
```

```yaml
risk: operationally-dangerous
approval_required: true
automatic_retry: forbidden
preconditions:
  - version exists in firmware catalog
  - device compatibility confirmed
  - stable power confirmed
  - connectivity confirmed
  - maintenance window confirmed
  - rollback expectations understood
```

## 17. QUEUE AND EVENT VERIFICATION

```yaml
queue_endpoints:
  tenant: GET /api/gateways/getqueue
  device: GET /api/gateways/queue/device/{deviceId}
  gateway: GET /api/gateways/{gatewayId}/gwqueue
event_endpoints:
  tenant: GET /api/events
  device: GET /api/events/sensor/{sensorId}
  room: GET /api/events/byRoom/{roomId}
```

Verification algorithm:

```text
1. Capture the returned message ID and target device.
2. Set local status to requested or queued.
3. Inspect device and gateway queue state.
4. Inspect relevant events.
5. Re-read current device state when supported.
6. Report exactly one state:
   requested | queued | delivered | confirmed | failed | unknown
7. Never translate queued into completed.
```

## 18. ERROR POLICY

```yaml
http_400:
  meaning: invalid request or payload
  action: validate against live OpenAPI
  retry_unchanged: false
http_401:
  meaning: missing, invalid, expired, revoked, or tenant-mismatched API token
  action: stop and request API-user verification or rotation from the system owner
  automatic_retry: false
http_403:
  meaning: authorization or tenant access denied
  action: verify roles and selected tenant
  bypass: forbidden
http_404:
  meaning: endpoint or resource unavailable
  action: refresh OpenAPI and inventory
http_409:
  meaning: state conflict
  action: inspect current state before resolution
http_5xx:
  meaning: server failure
  read_retry: exponential backoff permitted
  physical_command_retry: forbidden until queue and events are inspected
network_failure_after_send:
  state: ambiguous
  action: inspect queues and events before any retry
```

## 19. RISK AND APPROVAL MATRIX

```yaml
read_only:
  examples: [inventory, state, history, metering, queues]
  default_agent_permission: execute
reversible:
  examples: [temperature target, ordinary short pulse]
  default_agent_permission: confirm target and bounds
security_sensitive:
  examples: [access codes, users, permissions]
  default_agent_permission: require explicit approval
destructive:
  examples: [delete device, tenant, codes, queue data]
  default_agent_permission: require explicit confirmation
ownership_changing:
  examples: [claim gateway, claim sensor]
  default_agent_permission: require explicit approval
operationally_dangerous:
  examples: [persistent relay, persistent lock, Wi-Fi, firmware]
  default_agent_permission: require purpose, safe conditions, and explicit approval
```

## 20. SECRET HANDLING

Never expose or log:

```yaml
secrets:
  - Solvotix sat_ API token
  - private key
  - Solvotix session cookie
  - Wi-Fi SSID when classified as private
  - Wi-Fi password
  - smart-lock access code
  - any internal API token
```

Use redaction markers such as `<REDACTED_TOKEN>` and `<REDACTED_ACCESS_CODE>`.

## 21. COMPLETION CRITERIA

Do not report the integration complete until all applicable statements are true:

```yaml
completion:
  - live OpenAPI retrieved and validated
  - generated or typed client matches project conventions
  - API token is loaded only from a protected secret source
  - API token begins with sat_
  - bound tenant ID is explicit
  - read-only authentication check succeeds
  - gateway inventory loads
  - device inventory loads
  - device capabilities are mapped from type and OpenAPI
  - secrets are redacted
  - physical commands are approval-gated
  - non-idempotent commands are not automatically retried
  - accepted, queued, delivered, and confirmed states remain distinct
  - queue and event verification is implemented
  - failure and ambiguity are surfaced to the caller
```

## 22. BOOTSTRAP PROMPT

```text
Integrate this project with Solvotix. First retrieve and read https://solvotix.net/ai-first/agent-manifest.json, https://solvotix.net/ai-first/agent-guide.md, and https://backend.solvotix.org/v3/api-docs. Read all three before editing code. The system owner creates the Solvotix system at https://portal.solvotix.org/login and creates a tenant-bound API user at https://portal.solvotix.org/home/settings#system-users. Use the copied sat_ token only from a protected server-side secret and send it as Authorization: Bearer sat_<TOKEN> with the bound Tenant header. Do not implement interactive user authentication for the integration. Identify the project's language, architecture, existing HTTP client, and code-generation conventions. Implement typed API access, gateway discovery, device discovery, and queue/event verification. Treat hardware commands as asynchronous. Never report physical success solely from an accepted or queued response. Never log tokens, Wi-Fi credentials, access codes, or private customer data. Begin with read-only discovery. Require explicit approval for physical, security-sensitive, destructive, ownership-changing, Wi-Fi, and firmware operations. Do not automatically retry non-idempotent physical commands. If the guide, OpenAPI, inventory, and observed state disagree, stop and report the conflict instead of guessing.
```
