Configuration
The account service belongs to OHarness Cloud. The client knows only its public origin, not the Supabase project or Composio project API key.
| Location | Responsibility |
|---|---|
~/.oharness/config.json | General runtime preferences: models, permissions, logging, sync |
~/.oharness/cloud.json | Optional public Cloud address: { "siteUrl": "https://oharness.ai" } |
~/.oharness/plugins.json | { "runtimePlugins": [...] }; optional plugins for declarative bundles |
~/.oharness/mcp.json | { "mcpServers": { ... } }; Web connector changes write here |
| Cloud deployment environment/secrets | Supabase configuration and platform-owned service keys |
| Credential store | User login credentials; not any of the config files above |
OHARNESS_HOME redirects all four client files. The official Cloud origin is the default; self-hosted/development overrides use OHARNESS_SITE_URL, then cloud.json, then the packaged public origin. HTTP is allowed only for loopback development. Repository config cannot choose the Cloud origin or load runtime plugin code. Programmatic Harness.create({ config, runtimePlugins }) still supports explicitly supplied configurations.
Memory
Durable notes are configured under memory in config.json (or a project's oharness.config.json): limits, per-message recall and automatic extraction. Project notes live as Markdown under <project>/MEMORY/; cross-project user notes live under ~/.oharness/memory/user/. Sync consent and machine-local indexes remain in the user directory. A project config may tune recall or switch extraction off, but only the user's own config can switch extraction on, since it spends the user's model credit. Memory lists every setting.
Artifacts
A session in a registered project saves each artifact under <project>/ARTIFACTS/: the newest revision as a plain file (ARTIFACTS/blue-field.html), the revisions it replaced under ARTIFACTS/.versions/<name>/v<N>.<ext>. A session can make several artifacts, each its own file; the same name from another session gets a suffix (blue-field-2.html). Editing the top file in an editor changes what the panel shows. ~/.oharness/storage/artifact/<session>.jsonl stays the index — which session made what, and each revision's version and sync fields — without the content. Deleting a session removes the index and leaves the files in the project. Sessions outside a registered project, and raster images, keep their content in the index as before. Content recorded inline before this moves into the project the next time the session is opened.
Sync
The self-hosted destination and session credential belong only in the user's config.json:
{
"sync": {
"url": "https://sync.example.com",
"token": "opaque-session-token",
"enabled": true
}
}
Current precedence is user sync.url, then OHARNESS_SYNC_URL, then the built-in official destination. Repository configuration cannot set the URL, token or team because that would let a cloned repository redirect transcripts; it may only turn sync off or add exclusions. Restart OHarness after changing the destination. See Running your own sync server to deploy the bundled service and Sync protocol to implement a compatible one.
Compatible migration
Existing config.json sections are read only as a fallback while their separate file is absent. An existing separate file is authoritative, including an empty plugin list or empty MCP map. Legacy account.siteUrl is accepted; legacy Supabase fields are no longer used by the client.
npm run config:migrate # Preview filenames only; no secrets printed
npm run config:migrate -- --apply # Back up, split, then clean the old sections
The migration preserves unrelated preferences and does not overwrite existing split files. It saves a private config.before-split.<id>.json backup and writes the general config last. Files are atomically replaced with mode 0600. Do not edit config concurrently with migration or run multiple migration processes. The backup can contain old credentials: keep it private and remove it yourself after verification. Migration never modifies login credentials or authorizes apps.
Account transport
Browser login still uses Cloud /auth/desktop and /api/desktop/exchange. Refresh and terminal OTP fallback now use /api/desktop/auth/refresh, /otp, and /verify. Update Cloud before restarting an updated client. An older Cloud returns an explicit error; the client does not fall back to direct Supabase calls.
Cloud uses its configured auth project, validates inputs, limits requests and response sizes, and returns only session fields. Tokens are never logged or included in errors. Requests are not automatically retried; responses are no-store. Newly acquired credentials record their Cloud origin; changing it requires signing in again before refresh. Legacy credentials acquire this origin on the first successful refresh against the current trusted Cloud address.
The Cloud endpoint's rate limit is per process. Production deployments should also enforce shared edge rate limiting. Website Supabase settings remain in the Cloud project; no database schema changes are required for this migration.
The hosted Cloud connector keeps the Composio key and app allowlist in Cloud. Its built-in connector-cloud runtime plugin shows Web chat authorization cards and resumes the waiting tool after verified binding. plugins.json controls the plugin switch; it contains no platform credentials.