{"id":"6b7397ee-66bb-4cf0-bb40-fcd661a23bd8","entityType":"agent","slug":"clawhub-olares-olares-settings","name":"Olares Settings (olares-cli settings)","canonicalUrl":"https://www.xpersona.co/agent/clawhub-olares-olares-settings","canonicalPath":"/agent/clawhub-olares-olares-settings","generatedAt":"2026-10-14T14:07:29.399Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":null},"description":"Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirr...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 979 downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1718vftp5x2gwbtzenpt3kxch87k6j0:olares-settings","sourceUrl":"https://clawhub.ai/olares/olares-settings","homepage":"https://clawhub.ai/olares/skills/olares-settings","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/olares/olares-settings","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/olares/skills/olares-settings","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Olares Settings (olares-cli settings) technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":null},"stars":null,"forks":null,"downloads":979,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"4.0.1","tractionLabel":"979 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:08:15.373Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T23:08:15.435Z","lastCrawledAt":"2026-10-11T23:08:15.373Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T23:08:15.373Z","lastVerifiedAt":null,"highlights":[{"version":"4.0.1","createdAt":"2026-05-29T05:54:47.556Z","changelog":"Migrate ownership from @pengpeng to @olares (no content change vs 4.0.0)","fileCount":8,"zipByteSize":20048},{"version":"4.0.0","createdAt":"2026-05-29T04:53:52.530Z","changelog":"Automated publish from cli/skills/publish.sh","fileCount":8,"zipByteSize":20075},{"version":"1.2.0","createdAt":"2026-05-28T09:28:10.830Z","changelog":"Automated publish from cli/skills/publish.sh","fileCount":3,"zipByteSize":15619},{"version":"1.1.0","createdAt":"2026-04-30T13:23:25.880Z","changelog":"Automated publish from cli/skills/publish.sh","fileCount":2,"zipByteSize":11857}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1718vftp5x2gwbtzenpt3kxch87k6j0:olares-settings","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s1718vftp5x2gwbtzenpt3kxch87k6j0:olares-settings` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/olares/olares-settings before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-14T14:07:29.397Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-olares-olares-settings/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":null},"readme":"Skill: Olares Settings (olares-cli settings)\n\nOwner: olares\n\nSummary: Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirr...\n\nTags: latest:4.0.1\n\nVersion history:\n\nv4.0.1 | 2026-05-29T05:54:47.556Z | user\n\nMigrate ownership from @pengpeng to @olares (no content change vs 4.0.0)\n\nv4.0.0 | 2026-05-29T04:53:52.530Z | user\n\nAutomated publish from cli/skills/publish.sh\n\nv1.2.0 | 2026-05-28T09:28:10.830Z | user\n\nAutomated publish from cli/skills/publish.sh\n\nv1.1.0 | 2026-04-30T13:23:25.880Z | user\n\nAutomated publish from cli/skills/publish.sh\n\nArchive index:\n\nArchive v4.0.1: 8 files, 20048 bytes\n\nFiles: references/olares-settings-apps.md (7907b), references/olares-settings-backup.md (4591b), references/olares-settings-integration.md (5568b), references/olares-settings-users.md (5376b), references/olares-settings-vpn.md (6093b), skill-card.md (3329b), SKILL.md (13365b), _meta.json (134b)\n\nFile v4.0.1:SKILL.md\n\n---\r\nname: olares-settings\r\nversion: 4.0.1\r\ndescription: \"Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirror of every section the Olares Settings SPA exposes (https://docs.olares.com/manual/olares/settings/). Read-only coverage: users, appearance, apps (list, get, entrances, env, domain, policy), integration accounts, VPN (devices, ACL, SSH, subroutes, public-domain policy), network (reverse proxy, frp, hosts file), GPU, video, search status + dirs, backup plans + snapshots, restore plans, advanced (containerd registries, images, env system / user), plus a `me` self-service tree (whoami on Olares, version, check-update, SSO list). Verified mutating verbs: appearance language set, search rebuild, integration accounts add awss3|tencent / delete, VPN SSH enable/disable, VPN ACL add/remove, users create/delete (new Olares ID). Use when the user mentions Olares, Olares ID, Olares Settings, olares-cli settings, the Olares Settings UI, role (owner / admin / normal) on Olares, integration accounts, SSO tokens, GPU mode, search index, backup / restore plans, containerd registries, VPN ACLs, language preference, or 'who am I on this Olares instance'.\"\r\nmetadata:\r\n  requires:\r\n    bins: [\"olares-cli\"]\r\n  cliHelp: \"olares-cli settings --help\"\r\n---\r\n\r\n# settings (Olares Settings UI mirror)\r\n\r\n**CRITICAL — before doing anything, MUST use the Read tool to read [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) for profile selection, login, automatic token refresh, and the auth-error recovery table.**\r\n\r\n> **Source of truth for flags is always `olares-cli settings <area> <verb> --help`.** This file only carries what `--help` cannot give: routing, the 13-section index, the role-caching / admin-vs-normal floor, the wire-format cheat sheet, and the common-errors table.\r\n\r\n## Routing\r\n\r\n| User intent | Use this skill? |\r\n|---|---|\r\n| \"Change language / theme / appearance\" | ✅ yes |\r\n| \"Add a user / delete a user\" | ✅ yes |\r\n| \"Edit my app's entrance / domain / policy / env\" | ✅ yes (post-install surface) |\r\n| \"Add an S3 / Tencent integration account\" | ✅ yes |\r\n| \"Manage VPN devices / ACL / SSH toggle\" | ✅ yes |\r\n| \"Browse backup plans / snapshots / restore plans\" | ✅ yes |\r\n| \"Install / uninstall / upgrade / start / stop an Olares app\" | ❌ use [`olares-market`](../olares-market/SKILL.md) (this is post-install) |\r\n| \"Identify / log in / switch profile\" | ❌ use [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) (`profile login`) |\r\n| \"Inspect pods / workloads / nodes\" | ❌ use [`olares-cluster`](../olares-cluster/SKILL.md) |\r\n| \"Show CPU / memory / disk metrics\" | ❌ use [`olares-dashboard`](../olares-dashboard/SKILL.md) |\r\n\r\n> **Mental model:** `settings` covers configuration that the Olares Settings SPA exposes — **post-install per-app config**, mesh / VPN, backup, accounts, system appearance. Lifecycle and runtime live in sibling skills.\r\n\r\n## 13 area sub-trees\r\n\r\nThe umbrella registers the 12 canonical Settings docs sections, plus a 13th non-canonical `me` self-service tree:\r\n\r\n```\r\nusers         appearance   apps          integration   vpn         network\r\ngpu           video        search        backup        restore     advanced\r\n+ me (self-service: whoami / version / check-update / sso list)\r\n```\r\n\r\nShape is always `olares-cli settings <area> <verb>` (or `<area> <noun> <verb>` when the area has multiple sub-resources, e.g. `vpn devices list`, `backup plans list`).\r\n\r\n### Per-area `--help` and references\r\n\r\nFor every area, **start with `olares-cli settings <area> --help`**. References below cover the non-trivial sub-trees:\r\n\r\n| Area | `--help` first, then... |\r\n|---|---|\r\n| `me` | `olares-cli settings me --help` (whoami / version / check-update / sso list) |\r\n| `users` | [references/olares-settings-users.md](references/olares-settings-users.md) |\r\n| `apps` | [references/olares-settings-apps.md](references/olares-settings-apps.md) (entrances / domain / policy / auth-level pipeline) |\r\n| `vpn` | [references/olares-settings-vpn.md](references/olares-settings-vpn.md) (ACL deltas, SSH / subroutes / public-domain-policy) |\r\n| `integration` | [references/olares-settings-integration.md](references/olares-settings-integration.md) (`accounts add awss3|tencent`) |\r\n| `backup` | [references/olares-settings-backup.md](references/olares-settings-backup.md) (plans / snapshots / password) |\r\n| `appearance` | `olares-cli settings appearance --help` (`get`, `language set`) |\r\n| `network` | `olares-cli settings network --help` (read-only reverse-proxy / frp / hosts-file; writes blocked by JWS gap — see below) |\r\n| `gpu` | `olares-cli settings gpu --help` (read-only `list`) |\r\n| `video` | `olares-cli settings video --help` (read-only `config get`) |\r\n| `search` | `olares-cli settings search --help` (`status`, `rebuild`, `dirs list`) |\r\n| `restore` | `olares-cli settings restore --help` (read-only `plans list`) |\r\n| `advanced` | `olares-cli settings advanced --help` (read-only `status`, `registries list`, `images list`, `env (system|user) list`) |\r\n\r\n## Role caching + admin/normal floor\r\n\r\nA profile carries the role its user has on the Olares instance — `owner`, `admin`, or `normal` — cached locally so the CLI can short-circuit gated verbs without a round-trip. Populated on `profile login` / `profile import`, refreshed by `olares-cli profile whoami --refresh`.\r\n\r\n### Three whoami aliases, one driver\r\n\r\n```bash\r\nolares-cli profile whoami\r\nolares-cli settings users me\r\nolares-cli settings me whoami\r\n```\r\n\r\nAll three delegate to the same driver — same output, same caching, same `--refresh`. **Never** suggest the user \"should use the other one\" — they are aliases on purpose.\r\n\r\n### Floor table (admin-gated vs normal)\r\n\r\n| Floor | Verbs |\r\n|---|---|\r\n| **Admin (owner / admin)** | `users list / get / create / delete`; `network reverse-proxy get`, `network frp list`, `network hosts-file get`; `gpu list`; `advanced status / registries list / images list`; `vpn ssh status/enable/disable`, `vpn subroutes status`, `vpn acl all/get/add/remove`, `vpn public-domain-policy get` |\r\n| **Normal (any authenticated user)** | `me whoami / version / check-update / sso list`; `apps list/get`, `apps entrances list`, `apps env get`, `apps domain get`, `apps policy get`; `vpn devices list / routes <id>`; `appearance get`, `appearance language set`; `integration accounts list / list-by-type / get / add / delete`; `video config get`; `search status / dirs list / rebuild`; `backup plans list`, `backup snapshots list`; `restore plans list`; `advanced env (system|user) list` |\r\n\r\n### Soft preflight behavior\r\n\r\n- Admin-floor verbs check the cached role and fail fast with `role required: this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\"` **before any HTTP call**.\r\n- Server-side 401 / 403 (e.g. role changed since last cache write) still gets the same refresh-and-retry hint, even on verbs that don't preflight.\r\n- If role isn't cached yet, preflight is **soft**: it lets the call through and lets the server be authoritative.\r\n- **The standard refresh path is `olares-cli profile whoami --refresh`** — recommend it whenever a settings verb returns a permission-shaped error.\r\n\r\n## Output convention\r\n\r\nEvery read verb accepts `-o / --output {table,json}` (default `table`):\r\n\r\n- `table` is tabwriter-formatted; columns differ per verb but always print a clear \"no X\" sentinel when the result set is empty.\r\n- `json` round-trips the upstream's already-unwrapped data verbatim. **Use `-o json` whenever the agent needs to feed the result into another tool** — column ordering, truncation, and human-friendly relabeling only happen in table mode.\r\n- A handful of verbs (`video config get`, `advanced status`) downgrade table output to a one-line summary because the upstream config is large; the hint to switch to JSON is printed inline.\r\n\r\n## Wire-format cheat sheet\r\n\r\nDifferent upstream services return JSON in different envelopes. The CLI normalizes them per-area; this table is the cheat sheet for \"what's the wire format for area X\" when you need to fish out a non-tabled field via `-o json`:\r\n\r\n| Area | Endpoint family | Wire envelope |\r\n|---|---|---|\r\n| `me`, `apps`, `network`, `appearance`, `integration`, `gpu`, `video`, `search`, `advanced` | `/api/*` (user-service / BFL / terminusd) | Unwrapped BFL `{data: ...}` envelope |\r\n| `users` | `/api/users/v2`, `/api/users/:name`, `POST/DELETE /api/users/...` | List-result decoder; mutating returns axios-inner `{name}` |\r\n| `vpn` devices / ACL | `<SettingsURL>/headscale/machine`, `/headscale/machine/:id/routes` | Raw Headscale JSON (NO envelope), `route.id` is a string |\r\n| `vpn` public-domain-policy | `/api/launcher-public-domain-access-policy` | Already-unwrapped `{deny_all: 0|1}` |\r\n| `backup`, `restore` | `<SettingsURL>/apis/backup/v1/*` | BFL envelope; **different ingress prefix** (`/apis/backup/v1`, not `/api`) |\r\n| `video config get` | `/api/files/video/config` | BFL envelope, inner data as `json.RawMessage` (provider-versioned) |\r\n\r\n## Currently-implemented mutating verbs\r\n\r\nVerbs marked **VERIFIED** have been confirmed against a live Olares instance. Verbs flagged **UNVERIFIED** ship in the binary but are tracked as experimental; the CLI emits a one-line \"experimental\" stderr hint when they run.\r\n\r\n| Area | Verb | Status |\r\n|---|---|---|\r\n| `appearance` | `language set <code>` | VERIFIED |\r\n| `users` | `create` / `delete` (with `--watch`) | VERIFIED |\r\n| `search` | `rebuild`, `dirs add / remove` | VERIFIED (rebuild + dirs writes) |\r\n| `vpn ssh` | `enable` / `disable` | VERIFIED |\r\n| `vpn acl` | `add` / `remove` | VERIFIED |\r\n| `integration accounts` | `add awss3` / `add tencent` / `delete` | VERIFIED |\r\n| `apps` | `suspend [--all]` / `resume`, `env set`, `domain set/finish`, `policy set`, `auth-level set` | UNVERIFIED |\r\n| `backup` | `password set` | UNVERIFIED |\r\n\r\n**Not yet implemented** (and the CLI deliberately does NOT register them):\r\n\r\n- App lifecycle (`install` / `uninstall` / `upgrade` / `start` / `stop` / `cancel` / `clone`) → use [`olares-market`](../olares-market/SKILL.md) instead\r\n- Per-app secrets / permissions / providers (Infisical-backed) → admin / chart-side tooling\r\n- Network writes requiring a JWS-signed device-id header (`hosts-file set`, `frp set`, `ssl enable/disable/update`)\r\n- Containerd registry mutations (`registries mirrors put/delete`, `images delete/prune`) — JWS-gated\r\n- Hardware / restart-class (reboot, shutdown, ssh-password, OS upgrade) — JWS-gated via TermiPass QR callback\r\n- Backup plan create / update (needs full `BackupPolicy` + `LocationConfig` vector design)\r\n- Restore plan update / non-cancel delete — backup-server has no routes\r\n\r\n**Don't suggest the deferred verbs today** — they will error with \"command not found\".\r\n\r\n## Security rules\r\n\r\n- **Never** echo `<access_token>` or any field returned by `me sso list` into the terminal beyond what the table view shows. SSO tokens identify a TermiPass-bound device session and should never be logged or pasted into chat.\r\n- For writes that take secrets (`integration accounts add awss3|tencent`, future `backup password set`), **always read the secret from an env var or stdin pipe** — never paste it into chat or expand it inline in a suggested `olares-cli ...` command line.\r\n- `users create` / `users delete` are destructive. `delete` needs the whole word `yes` unless `--yes`. `delete` refuses owner accounts (rejected before DELETE). `create` always prints the initial password once to stdout — treat transcripts accordingly.\r\n- Read-only verbs do NOT carry \"this will change X\" prompts. **Don't fabricate one for read verbs.**\r\n- The `profile whoami --refresh` recovery path is the only authentication-adjacent action this skill recommends. **All** other auth recovery belongs in [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).\r\n\r\n## Common errors → fixes\r\n\r\n| Error | Cause | Fix |\r\n|---|---|---|\r\n| `this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\"` | Cached role below the verb's floor | If your role on the server changed: `olares-cli profile whoami --refresh`. Otherwise ask owner to grant the role |\r\n| `HTTP 403 while attempting to <verb>` (with refresh hint) | Server rejected even though cache said OK — stale role cache | `olares-cli profile whoami --refresh`, retry the verb |\r\n| `refresh token for <id> became invalid at <ts>; please run: olares-cli profile login --olares-id <id>` | The refresh_token itself is dead — see [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) | `olares-cli profile login --olares-id <id>` |\r\n| `no access token for <id>; run: olares-cli profile login --olares-id <id>` | Keychain has no entry for the active profile | `olares-cli profile login` or `profile import` |\r\n| `unsupported --output \"<x>\" (allowed: table, json)` | Typo on `-o` | Use `-o table` or `-o json` |\r\n| `GET <path>: upstream returned code <N>: <msg>` | user-service / BFL / backup-server returned non-success envelope | Read the message verbatim; it almost always carries actionable detail (e.g. \"user not found\") |\r\n\r\nFor the full auth-error matrix see [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).\n\nFile v4.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn7153k9wp5dwxsm6getv104r985vrf5\",\n  \"slug\": \"olares-settings\",\n  \"version\": \"4.0.1\",\n  \"publishedAt\": 1780034087556\n}\n\nFile v4.0.1:references/olares-settings-apps.md\n\n# settings apps (post-install configuration)\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings apps --help` and `olares-cli settings apps <verb> --help`.\r\n\r\nThe **post-install** surface for an Olares app. Inspect the app, list its entrances, edit per-entrance domain / policy / auth-level / env vars, suspend / resume.\r\n\r\n> **NOT for install / uninstall / upgrade / clone / start / stop** — use [`olares-market`](../../olares-market/SKILL.md) for app lifecycle. `settings apps` is for tweaking an app that's already installed.\r\n\r\n## Verbs at a glance\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `list [--all] [--show-system]` | normal | VERIFIED | Installed apps for the current user. Default filter mirrors the SPA |\r\n| `get <app>` | normal | VERIFIED | Detail view (filtered client-side; no per-app endpoint) |\r\n| `entrances list <app>` | normal | VERIFIED | **Live** entrance vector — names, state, auth-level |\r\n| `env get <app>` | normal | VERIFIED | Current per-app env vector |\r\n| `env set <app> KEY=VALUE [KEY=VALUE...]` | normal | UNVERIFIED | Replace the env vector |\r\n| `domain get <app> <entrance>` | normal | VERIFIED | Per-entrance custom-domain setup |\r\n| `domain list <app>` | normal | VERIFIED | Every entrance's domain setup |\r\n| `domain set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `domain finish <app> <entrance>` | normal | UNVERIFIED | Confirm third-party CNAME after DNS propagates |\r\n| `policy get <app> <entrance>` | normal | VERIFIED | Per-entrance auth policy |\r\n| `policy list <app>` | normal | VERIFIED | Every entrance's policy |\r\n| `policy set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `auth-level set <app> <entrance> --level X` | normal | UNVERIFIED | `private` / `public` / `internal` |\r\n| `suspend <app> [--all]` | normal | UNVERIFIED | Suspend running app |\r\n| `resume <app>` | normal | UNVERIFIED | Resume suspended app |\r\n\r\n## The per-entrance editing pipeline\r\n\r\nMost per-entrance edits follow a 4-step pattern:\r\n\r\n```bash\r\n# 1. Discover entrances on the app.\r\nolares-cli settings apps entrances list firefox\r\n# → produces ENTRANCE / STATE / AUTH LEVEL / DOMAIN columns\r\n\r\n# 2. Inspect current setup of the entrance you want to edit.\r\nolares-cli settings apps domain get firefox www\r\nolares-cli settings apps policy get firefox www\r\n\r\n# 3. RMW update (unspecified flags survive).\r\nolares-cli settings apps domain set firefox www --third-level my-firefox\r\nolares-cli settings apps policy set firefox www --default-policy two_factor\r\n\r\n# 4. For third-party domains: confirm CNAME after DNS propagation.\r\nolares-cli settings apps domain set firefox www --third-party firefox.example.com \\\r\n  --cert-file /path/to/cert.pem --key-file /path/to/key.pem\r\nolares-cli settings apps domain finish firefox www\r\n```\r\n\r\n## `domain set` — RMW semantics + cert/key handling\r\n\r\n```bash\r\n# Update third-level only (host under .<terminus>).\r\nolares-cli settings apps domain set firefox www --third-level my-firefox\r\n\r\n# Update third-party domain — REQUIRES --cert-file AND --key-file.\r\nolares-cli settings apps domain set firefox www \\\r\n  --third-party firefox.example.com \\\r\n  --cert-file /etc/letsencrypt/live/firefox.example.com/fullchain.pem \\\r\n  --key-file /etc/letsencrypt/live/firefox.example.com/privkey.pem\r\n\r\n# Explicitly drop a domain dimension (RMW would otherwise preserve it).\r\nolares-cli settings apps domain set firefox www --clear-third-party\r\nolares-cli settings apps domain set firefox www --clear-third-level\r\n```\r\n\r\n- **Unspecified flags survive** — RMW under the hood. Pass `--clear-*` to drop a dimension.\r\n- **Third-party domains REQUIRE both `--cert-file` AND `--key-file`** (unless `--clear-third-party`). The PEM bytes are POSTed verbatim as multi-line strings.\r\n- After `domain set --third-party`, run `domain finish` once the CNAME propagates. Without `finish`, the SPA shows \"pending\" status.\r\n\r\n## `policy set` — replace sub-policies\r\n\r\n```bash\r\n# Update default policy.\r\nolares-cli settings apps policy set firefox www --default-policy two_factor\r\n\r\n# Set one-time-link mode (factor cap).\r\nolares-cli settings apps policy set firefox www --one-time true --valid-duration 3600\r\n\r\n# Replace sub-policies (any --sub-policy flag drops the existing set).\r\nolares-cli settings apps policy set firefox www \\\r\n  --sub-policy \"uri=/admin,policy=two_factor\" \\\r\n  --sub-policy \"uri=/api,policy=public\"\r\n\r\n# Explicitly drop sub-policies.\r\nolares-cli settings apps policy set firefox www --clear-sub-policies\r\n\r\n# Bulk file form.\r\nolares-cli settings apps policy set firefox www --sub-policies-file ./sub-policies.json\r\n```\r\n\r\n- `--default-policy` values: `system` | `one_factor` | `two_factor` | `public`\r\n- Default-policy / one-time / valid-duration flags follow RMW semantics.\r\n- **Sub-policy entries are REPLACED in full whenever any sub-policy flag is passed.** This is intentional — partial sub-policy edits don't compose safely. Pass `--clear-sub-policies` to drop the existing set without adding new ones.\r\n\r\n## `auth-level set` — no GET endpoint upstream\r\n\r\n```bash\r\nolares-cli settings apps auth-level set firefox www --level public\r\n```\r\n\r\n| Level | Reachability |\r\n|---|---|\r\n| `private` | Only the app's owner |\r\n| `public` | Any authenticated user |\r\n| `internal` | Intra-cluster traffic only |\r\n\r\n> **There is no `auth-level get` verb** because no GET endpoint exists upstream. To inspect the current level, run `apps entrances list <app>` and read the `AUTH LEVEL` column.\r\n\r\n## `env get` / `env set`\r\n\r\n```bash\r\nolares-cli settings apps env get gitea\r\nolares-cli settings apps env set gitea GITEA_TOKEN=abc DB_PASS=xyz\r\n```\r\n\r\n- `env set` REPLACES the full env vector. Read current env first if you only want to add a single var.\r\n- For secrets, pipe via env var or stdin redirection. Don't paste the value into chat.\r\n\r\n## `list` filters\r\n\r\n```bash\r\nolares-cli settings apps list                  # SPA-equivalent filtered view (current user, no system apps)\r\nolares-cli settings apps list --show-system    # include system apps\r\nolares-cli settings apps list --all            # every state + every kind (cluster-wide for admins)\r\n```\r\n\r\n`get <app>` filters client-side — there is no per-app endpoint upstream. For multi-instance / cloned apps, pass the per-instance name (e.g. `windowsefe992`), not the source name (`windows`).\r\n\r\n## Agent best practices\r\n\r\n- **Always run `entrances list <app>` before any per-entrance edit.** Don't assume entrance names; the user-facing names (e.g. `www`) often differ from the chart-defined service names.\r\n- **For `policy set`**, surface `policy get` output to the user BEFORE applying — the sub-policy replacement semantics are easy to misuse.\r\n- **For `domain set --third-party`**, remind the user to set up the CNAME at their DNS provider AND run `domain finish` once it propagates.\r\n- **For UNVERIFIED verbs**, the CLI emits a one-line \"experimental\" hint on stderr — don't suppress it.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `entrance '<name>' not found on app '<app>'` | Typo / chart vs user-facing name mismatch | `apps entrances list <app>` to enumerate |\r\n| `--cert-file and --key-file are required when --third-party is set` | Third-party domain without cert | Provide both, or use `--clear-third-party` |\r\n| `--default-policy: invalid value 'X' (allowed: system, one_factor, two_factor, public)` | Typo | Use one of the four valid values |\r\n| `auth-level get is not supported (no upstream endpoint); use 'apps entrances list <app>' to read the AUTH LEVEL column` | Tried to GET auth-level | Read from `entrances list` |\r\n| `experimental: this verb is not yet smoke-verified` (stderr) | UNVERIFIED verb | Informational; proceed with caution |\n\nFile v4.0.1:references/olares-settings-backup.md\n\n# settings backup\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings backup --help` and `olares-cli settings backup <noun> <verb> --help`.\r\n\r\nManage backup plans (BFL backup-server) and the repository encryption password.\r\n\r\n> **Different ingress prefix** — `<SettingsURL>/apis/backup/v1/*` rather than `/api/*`. The CLI handles this transparently, but errors carrying the path will mention `/apis/backup/v1/...`.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `plans list` | normal | VERIFIED | List backup plans (with pagination) |\r\n| `snapshots list <backup-id>` | normal | VERIFIED | List snapshots for one plan |\r\n| `password set <name>` | normal | UNVERIFIED | Set / rotate the repository encryption password |\r\n\r\n## `plans list`\r\n\r\n```bash\r\nolares-cli settings backup plans list                     # default 50\r\nolares-cli settings backup plans list --limit 100\r\nolares-cli settings backup plans list --offset 50 --limit 50\r\nolares-cli settings backup plans list -o json\r\n```\r\n\r\nReturns each plan with name, ID, schedule, target (cloud / local / S3 / ...), status. Fields not surfaced in the table view are available via `-o json` (the SPA's axios interceptor unwraps `data.data`, which is why upstream code reads `{backups: [...]}` directly).\r\n\r\n`--offset` / `--limit` mirror the SPA's pagination behavior. Default `--limit` is 50.\r\n\r\n## `snapshots list <backup-id>`\r\n\r\n```bash\r\nolares-cli settings backup snapshots list <backup-id> --limit 50\r\nolares-cli settings backup snapshots list <backup-id> -o json\r\n```\r\n\r\nRequires the **backup ID** (from `plans list`, NOT the plan name). Returns the snapshot timeline for that plan: snapshot ID, taken-at timestamp, size, status, restic / kopia snapshot identifier.\r\n\r\n## `password set <name>` (UNVERIFIED)\r\n\r\n```bash\r\n# Interactive TTY prompt (default; no echo).\r\nolares-cli settings backup password set my-plan\r\n\r\n# Stdin pipe (scripted).\r\necho -n \"my-secret-password\" | olares-cli settings backup password set my-plan --password-stdin\r\n```\r\n\r\n- Sets / rotates the encryption password for one backup plan's repository.\r\n- **Default reads from a TTY without echo.** `--password-stdin` reads once from stdin (newline-terminated; trim newline if your producer adds one).\r\n- **Losing the password means losing the ability to decrypt existing snapshots.** The upstream cannot recover this password — make sure the user has it stored somewhere safe (password manager) BEFORE the call.\r\n\r\n## Plan create / update — out of scope (today)\r\n\r\n`plans create` and `plans update` are **not implemented yet**. They need either:\r\n\r\n- A `--from-file plan.json` mode (still pending design — the full `BackupPolicy` + `LocationConfig` vector is large), or\r\n- An upstream \"create from defaults\" shortcut that doesn't yet exist.\r\n\r\nUntil then, **create / update backup plans via the SPA** (Settings → Backup). The CLI's read verbs can still inspect plans created via the SPA.\r\n\r\n## Agent best practices\r\n\r\n- **For \"rotate the backup password\"** → always run interactively via TTY prompt unless explicitly scripted. The `--password-stdin` flow is for CI / non-interactive contexts only.\r\n- **For \"show me my backups\"** → `plans list` is the right verb. If the user then asks \"what snapshots are in plan X\", `snapshots list <backup-id>` (use the ID from `plans list -o json`).\r\n- **NEVER paste the backup password into the agent transcript or shell history.** Even in scripted form, prefer reading from a secret manager / env var that doesn't persist in scrollback.\r\n- **Surface the irreversibility warning before any `password set` interactive flow.** The user must understand that the password is the only key to existing encrypted snapshots — there is no recovery path.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `plan '<name>' not found` | Wrong backup-id or name | `plans list` to enumerate |\r\n| `snapshots list: backup-id required` | Missing positional | Provide the backup-id from `plans list` |\r\n| `failed to read password from stdin: EOF` | `--password-stdin` invoked without piped input | Pipe from `echo -n` / a file / a secret manager |\r\n| `experimental: this verb is not yet smoke-verified` (stderr) | UNVERIFIED (`password set`) | Proceed with caution; verify result manually |\r\n| `GET /apis/backup/v1/plans/backup: upstream returned code N` | Backup-server unreachable / 5xx | Check `settings advanced status` for backup-server health |\n\nFile v4.0.1:references/olares-settings-integration.md\n\n# settings integration\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings integration accounts --help` and `olares-cli settings integration accounts <verb> --help`.\r\n\r\nExternal integration accounts (S3 / Tencent COS / Google Drive / Dropbox / Olares Space / NFT cloud binding).\r\n\r\n## What's covered by the CLI\r\n\r\n| Account type | CLI verb | Why |\r\n|---|---|---|\r\n| AWS S3 (or S3-compatible endpoint) | `accounts add awss3` | Direct credentials — no OAuth |\r\n| Tencent COS | `accounts add tencent` | Direct credentials — no OAuth |\r\n| Google Drive | (SPA only) | OAuth-bound browser session |\r\n| Dropbox | (SPA only) | OAuth-bound browser session |\r\n| Olares Space / NFT cloud binding | (SPA only) | Browser- and wallet-bound by design |\r\n\r\n> **OAuth and wallet flows stay in the SPA.** The access tokens they produce are scoped to a browser session and have no useful one-shot CLI capture. If the user asks to add Google Drive / Dropbox / Olares Space / NFT integrations via CLI, direct them to the Settings → Integration page in the SPA.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Notes |\r\n|---|---|---|\r\n| `accounts list` | normal | `accountMini` shape (no `raw_data`) |\r\n| `accounts list-by-type <type>` | normal | Filter by account type |\r\n| `accounts get <type> [name]` | normal | `accountFull` shape (includes `raw_data`); `name` optional for single-tenant types |\r\n| `accounts add awss3 [flags]` | normal | AWS S3 / S3-compatible |\r\n| `accounts add tencent [flags]` | normal | Tencent COS |\r\n| `accounts delete <type> [name]` | normal | `name` optional for single-tenant types |\r\n\r\n## `accounts add awss3`\r\n\r\n```bash\r\nolares-cli settings integration accounts add awss3 \\\r\n  --access-key-id     \"$AWS_ACCESS_KEY_ID\" \\\r\n  --access-key-secret \"$AWS_SECRET_ACCESS_KEY\" \\\r\n  --endpoint          \"https://s3.amazonaws.com\" \\\r\n  --bucket            \"my-bucket\"\r\n```\r\n\r\n- `--bucket` is **optional** — omit for \"any bucket the credentials can reach\"; provide for \"scope to this bucket\".\r\n- `--endpoint` accepts any S3-compatible endpoint (MinIO, Backblaze B2 via S3 API, etc.) — not just AWS.\r\n\r\n## `accounts add tencent`\r\n\r\n```bash\r\nolares-cli settings integration accounts add tencent \\\r\n  --access-key-id     \"$TENCENT_SECRET_ID\" \\\r\n  --access-key-secret \"$TENCENT_SECRET_KEY\" \\\r\n  --endpoint          \"https://cos.ap-shanghai.myqcloud.com\"\r\n```\r\n\r\n- Region is encoded in the endpoint URL — e.g. `cos.ap-beijing.myqcloud.com`, `cos.ap-shanghai.myqcloud.com`.\r\n- Tencent COS is **single-tenant**: no `--bucket` flag, no `<name>` argument on add. There is at most one Tencent account per profile.\r\n\r\n## `accounts get` / `accounts delete` — name handling\r\n\r\n```bash\r\n# Multi-tenant types (S3, Drive, Dropbox) — need a name.\r\nolares-cli settings integration accounts get awss3 my-bucket\r\nolares-cli settings integration accounts delete awss3 my-bucket\r\n\r\n# Single-tenant types (Tencent, Space, NFT) — name omitted.\r\nolares-cli settings integration accounts get tencent\r\nolares-cli settings integration accounts delete tencent\r\n```\r\n\r\nThe store key is composed as `integration-account:<type>:<name>` (or `integration-account:<type>` when no name is supplied), matching the SPA's `getStoreKey`.\r\n\r\n## Secret handling — agent rules\r\n\r\n**The single most important rule in this sub-tree: NEVER paste secret-key values into the agent transcript.**\r\n\r\n- **Always recommend env vars or stdin pipes**: `--access-key-secret \"$AWS_SECRET_ACCESS_KEY\"`.\r\n- Bash history retention is the user's responsibility, but the agent's default phrasing should make it easy to keep secrets out of the transcript / scrollback.\r\n- For the agent's own suggestions: write `--access-key-secret \"$AWS_SECRET_ACCESS_KEY\"` (placeholder), NOT `--access-key-secret \"AKIA...\"` (real-looking).\r\n\r\n## `accounts get` JSON shape\r\n\r\n```bash\r\nolares-cli settings integration accounts get awss3 my-bucket -o json\r\n```\r\n\r\nReturns the `accountFull` shape including the un-redacted `raw_data` field. **The secret-key value WILL appear in the output** — pipe to `jq` and select only the fields you need rather than dumping the whole payload.\r\n\r\n## Agent best practices\r\n\r\n- For \"add my S3 credentials\" → prompt the user to **set the secret in an env var FIRST**, then construct the command using `\"$VAR\"` interpolation.\r\n- For \"show me my integration accounts\" → `accounts list` (no secrets) instead of `accounts get` (with secrets) unless the user specifically needs the credential payload.\r\n- For \"delete my old S3 account\" → `accounts list-by-type awss3` first to confirm the right name, then `accounts delete awss3 <name>`.\r\n- If the user asks for Google Drive / Dropbox / Olares Space / NFT cloud binding, **redirect to the SPA** — explain that OAuth tokens are browser-scoped and can't be captured by one-shot CLI calls.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `account 'X' of type '<type>' not found` | Wrong name / never added | `accounts list-by-type <type>` to enumerate |\r\n| `missing required flag: --access-key-id` (or `--access-key-secret` / `--endpoint`) | Mandatory flag omitted | Provide all three for S3 / Tencent |\r\n| `account already exists` | Single-tenant type (Tencent / Space) already has one | `accounts delete <type>` first, then add |\r\n| Secret value shows up in shell history | The user (or agent) embedded the secret on the command line directly | Re-issue from env var; clear shell history manually |\n\nFile v4.0.1:references/olares-settings-users.md\n\n# settings users\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) (especially \"Role caching + admin/normal floor\") first.\r\n> **Flags & examples:** `olares-cli settings users --help` and `olares-cli settings users <verb> --help`.\r\n\r\nInstance roster — list / get / create / delete users on the active Olares. **Admin floor** (`owner` / `admin` only).\r\n\r\n> **Not the same as `olares-cli user create`** (kube / cluster CR). `settings users` hits Termipass user-service routes; `user` writes a cluster-level CR. Mention this if the user mixes them up.\r\n\r\n## Verbs at a glance\r\n\r\n| Verb | Floor | Notes |\r\n|---|---|---|\r\n| `list` | admin | Server-side role-filtered (normal users see only themselves) |\r\n| `get <username>` | admin | Single user record (email / olaresId / role / quota) |\r\n| `me` | normal | Alias of `profile whoami` (same driver) |\r\n| `create <username>` | admin | Two flag groups: `--defaults` OR explicit `--role` / `--cpu` / `--memory-gb` |\r\n| `delete <username>` | admin | **Destructive**. Owner accounts refused. Whole-word `yes` prompt unless `--yes` |\r\n\r\n## `create` — two mutually-exclusive flag groups\r\n\r\n```bash\r\n# Group A: SPA preset (normal, 1 CPU, 4G memory; auto-generated password; DID precheck)\r\nolares-cli settings users create bob --defaults\r\nolares-cli settings users create bob --defaults --watch\r\n\r\n# Group B: explicit\r\nolares-cli settings users create alice --role admin --cpu 2 --memory-gb 8\r\nolares-cli settings users create alice --role normal --cpu 1 --memory-gb 4 --watch\r\n```\r\n\r\n- `--defaults` is mutually exclusive with `--role` / `--cpu` / `--memory-gb`.\r\n- `--role` may only be `admin` or `normal`. **The SPA account dialog cannot create an owner**, and neither can the CLI.\r\n- The initial password is **always auto-generated** by the CLI — no `--password` flag exists. The password is printed once to stdout on success; treat transcripts as sensitive.\r\n- DID precheck runs before the create POST. A username that conflicts with an existing DID fails fast with a copy-pasteable error.\r\n\r\n## `delete` — destructive, owner-safe\r\n\r\n```bash\r\nolares-cli settings users delete bob                       # whole-word \"yes\" prompt\r\nolares-cli settings users delete bob --yes                 # script mode\r\nolares-cli settings users delete bob --yes --watch         # block until Deleted\r\n```\r\n\r\n- **Owner accounts cannot be deleted** — the CLI rejects via GET before sending DELETE, matching `olares-cli user delete`.\r\n- The prompt expects the **whole word `yes`** (like ssh `yes/no`), not `y`. Reduces accidental confirmation.\r\n- Default is accepted-then-exit — the row may still appear briefly in `users list` while controllers tear it down. Use `--watch` to block until `Deleted`.\r\n\r\n## `--watch` (block until terminal state)\r\n\r\nSame shape as [`olares-cli market --watch`](../../olares-market/SKILL.md): opt-in `-w/--watch`, companion `--watch-timeout` (default 15m), `--watch-interval` (default 2s). Polls user-service's `/status` endpoint. Gives up after 5 consecutive transport errors. SIGINT-graceful.\r\n\r\n| Op | Terminal-success | Terminal-failure | absentMeansSuccess |\r\n|---|---|---|---|\r\n| `create` | `Created` | `Failed` / `Deleted`* | false |\r\n| `delete` | `Deleted` | (timeout only) | true (defensive HTTP 404) |\r\n\r\n\\* `Deleted` during a create watch means the row vanished mid-watch (controller cleanup raced) — reported as failure so JSON consumers see a non-zero exit.\r\n\r\n## JSON output shapes\r\n\r\n```jsonc\r\n// Without --watch\r\n{\"name\":\"alice\",\"original_password\":\"...\",\"status\":\"Accepted\"}\r\n{\"name\":\"bob\",\"status\":\"Accepted\"}\r\n\r\n// With --watch (final_status added)\r\n{\"name\":\"alice\",\"original_password\":\"...\",\"status\":\"Created\",\"final_status\":\"Created\",\"wizard_url\":\"https://wizard-alice.example.com\"}\r\n{\"name\":\"bob\",\"status\":\"Deleted\",\"final_status\":\"Deleted\"}\r\n```\r\n\r\n`wizard_url` appears on a successful create `--watch` — surface it to the user so they can finish setting up the new account.\r\n\r\n## Agent best practices\r\n\r\n- **Always run `users get <name>` before `users delete <name>`** in interactive sessions to confirm role and quota — gives the user a chance to back out if they targeted the wrong account.\r\n- For \"create user and tell me when they can log in\" → `users create <name> --defaults --watch -o json | jq '.wizard_url'`.\r\n- **NEVER paste the auto-generated password into chat.** Recommend the user copy it directly from the CLI output.\r\n- The opt-in `--watch` shape **flipped from a prior default of \"wait by default + `--no-wait`\"** — existing scripts that relied on blocking semantics must add `--watch` explicitly.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `cannot create user: --role required (or use --defaults)` | Group A vs B confusion | Pick one set of flags |\r\n| `cannot delete owner user` | DELETE blocked client-side | Owner accounts are unmanageable; use a different verb / SPA action |\r\n| `confirmation rejected: type the whole word 'yes' to delete` | Y/N-style answer to whole-word prompt | Type `yes`, or pass `--yes` |\r\n| `did precheck failed: <reason>` | Username conflicts with an existing DID | Pick a different username |\r\n| Watcher hangs near `Failed` | Backend create / provisioning failed | Check `users get <name>` for `status`; retry or rollback |\n\nFile v4.0.1:references/olares-settings-vpn.md\n\n# settings vpn (Headscale mesh)\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings vpn --help` and `olares-cli settings vpn <noun> <verb> --help`.\r\n\r\nManage the per-Olares Headscale mesh — devices, routes, per-app ACL, SSH toggle, sub-route toggle, public-domain-policy.\r\n\r\n## Sub-tree summary\r\n\r\n| Sub-tree | Floor | Verbs |\r\n|---|---|---|\r\n| `devices` | normal | `list`, `routes <id>` |\r\n| `ssh` | admin | `status`, `enable`, `disable` |\r\n| `subroutes` | admin | `status` (read-only) |\r\n| `acl` | admin | `all`, `get`, `add`, `remove` (alias `rm`) |\r\n| `public-domain-policy` | admin | `get` (read-only `deny_all` 0/1 flag) |\r\n\r\n## `devices` — Headscale machines\r\n\r\n```bash\r\nolares-cli settings vpn devices list\r\nolares-cli settings vpn devices routes <device-id>\r\n```\r\n\r\n- Hits `<SettingsURL>/headscale/machine` — settings nginx, not desktop.\r\n- **Raw Headscale JSON** (no envelope). `route.id` is a `string`.\r\n- `devices list` is the only normal-floor verb in this sub-tree.\r\n\r\n## `ssh` — boolean toggle\r\n\r\n```bash\r\nolares-cli settings vpn ssh status\r\nolares-cli settings vpn ssh enable\r\nolares-cli settings vpn ssh disable\r\n```\r\n\r\n- `enable` / `disable` send an explicit empty `{}` body to match the SPA's request shape, even though the upstream doesn't read it.\r\n- Run `vpn ssh status` after to confirm the resulting state.\r\n\r\n## `subroutes` — read-only toggle\r\n\r\n```bash\r\nolares-cli settings vpn subroutes status\r\n```\r\n\r\nReturns the `allow_subroutes` flag plus the current sub-route list. `-o json` emits the unwrapped `[]string` the SPA reads.\r\n\r\n## `acl` — per-app ACL (RMW under the hood)\r\n\r\nThe most flag-rich sub-tree here. **The upstream replaces the whole per-app ACL vector on every POST** — there is no add / remove endpoint. `vpn acl add` and `vpn acl remove` are read-modify-write sugar so unrelated entries survive untouched.\r\n\r\n### Read\r\n\r\n```bash\r\nolares-cli settings vpn acl all                # every app that currently has an ACL row\r\nolares-cli settings vpn acl get my-app         # per-app ACL vector\r\nolares-cli settings vpn acl get my-app -o json # full payload\r\n```\r\n\r\n### Add / remove — destination format\r\n\r\nEvery `--tcp` / `--udp` / `--any-proto` value is a **Headscale destination spec `<host>:<port>`**, NOT a bare port number.\r\n\r\n| Spec | Meaning |\r\n|---|---|\r\n| `'*:8080'` | Any source, port 8080 (this is what the Web UI's \"Add ACL\" implicitly sends) |\r\n| `'192.168.1.0/24:22'` | Restrict source CIDR |\r\n| `'tag:api:443'` | Tag-based source |\r\n| `'example-host:*'` | Allow all ports on one host |\r\n| `'*:8000-8100'` | Port range (Headscale accepts; CLI doesn't validate ranges specifically) |\r\n| `'*:*'` | Allow everything (Headscale accepts) |\r\n\r\n**Bare port numbers are rejected** by the Headscale policy parser with `invalid port format`. The CLI now pre-validates the `<host>:<port>` shape and surfaces a copy-pasteable suggestion rather than letting BFL reject the POST.\r\n\r\n### `--any-proto` = SPA \"Add ACL\" parity\r\n\r\nThe Settings page's \"Add ACL\" dialog only collects a port, hardcodes the app to the system `olares-app`, sets the source host to `*`, and posts with `proto=\"\"` so Tailscale expands to ICMPv4 / ICMPv6 / TCP / UDP. To mirror that one-for-one:\r\n\r\n```bash\r\n# SPA \"Add ACL\" port 8080 equivalent:\r\nolares-cli settings vpn acl add olares-app --any-proto '*:8080'\r\n```\r\n\r\n`--tcp` / `--udp` are strictly more expressive (per-protocol slots, named app, custom hosts/CIDRs/tags) but always emit a typed proto. `add` / `remove` use case-insensitive proto matching on the merge / subtract paths, so empty-proto entries created via `--any-proto` round-trip cleanly alongside `--tcp` / `--udp` ones.\r\n\r\n### Examples\r\n\r\n```bash\r\n# Merge a single TCP destination.\r\nolares-cli settings vpn acl add my-app --tcp '*:8080'\r\n\r\n# Merge multiple destinations (repeated flag OR comma-separated; both work, both de-dupe).\r\nolares-cli settings vpn acl add my-app --tcp '*:80' --tcp '*:443' --udp '*:53'\r\nolares-cli settings vpn acl add my-app --tcp '*:80,*:443'\r\n\r\n# Restrict source CIDR.\r\nolares-cli settings vpn acl add my-app --tcp '192.168.1.0/24:22'\r\n\r\n# Remove a destination.\r\nolares-cli settings vpn acl remove my-app --tcp '*:80'\r\nolares-cli settings vpn acl rm     my-app --udp '*:53'   # alias\r\n\r\n# SPA Web parity (all protocols).\r\nolares-cli settings vpn acl add olares-app --any-proto '*:8080'\r\n```\r\n\r\n## `public-domain-policy` — read-only switch\r\n\r\n```bash\r\nolares-cli settings vpn public-domain-policy get\r\n```\r\n\r\nReturns the `deny_all` flag (0 or 1). The write side stays in the SPA today.\r\n\r\n## Agent best practices\r\n\r\n- **Always run `vpn acl get <app>` before mutating** — the RMW semantics mean a wrong delta can silently drop unrelated entries (it shouldn't, but inspecting first catches surprise edge cases).\r\n- **For \"I want the same thing the SPA's 'Add ACL' button does\"** → `vpn acl add olares-app --any-proto '<host>:<port>'`. Don't try to reconstruct it from `--tcp` / `--udp`.\r\n- **Bare port number is the #1 mistake** — when the user says \"allow port 8080\", suggest `'*:8080'`, not `8080`.\r\n- `ssh enable` / `disable` are SAFE to use in interactive sessions (idempotent boolean toggle), but **note that disabling SSH cuts off any ongoing TermiPass SSH session** — confirm intent before invoking.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `invalid port format` (from Headscale) | Bare port number passed instead of `<host>:<port>` | Use `'*:<port>'` (any source) |\r\n| `acl add: --tcp / --udp / --any-proto required` | No destination specs | Provide at least one |\r\n| `device-id '<id>' not found in Headscale` | Wrong device id | `vpn devices list` to enumerate |\r\n| `role required: ... admin` | Normal user trying admin-only verb | Switch profile to an admin / owner |\r\n| ACL changes don't seem to take effect | Read the RMW caveat — sub-policies / acl entries on other protocols you didn't pass DO survive | Re-run with the right flag set |\n\nFile v4.0.1:skill-card.md\n\n## Description:\n\nGuides agents in using `olares-cli settings` to read and change Olares Settings surfaces for users, appearance, apps, integrations, VPN, network, GPU, video, search, backup, restore, advanced settings, and self-service account checks.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[olares](https://clawhub.ai/user/olares)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal Olares operators, administrators, and developers use this skill to inspect and manage Olares Settings through an authenticated `olares-cli` profile. It is intended for settings workflows such as user administration, app post-install configuration, integration accounts, VPN ACLs, search, backup, restore, and account self-service checks.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can guide administrative settings changes for users, apps, VPN, integrations, search, and backups through an authenticated `olares-cli` profile.\n\nMitigation: Review proposed commands before write actions, confirm the active profile and role, and prefer read/list commands before mutation.\n\nRisk: Integration account JSON, backup passwords, generated user passwords, app environment values, and SSO tokens may contain secrets.\n\nMitigation: Use environment variables, stdin, or interactive prompts for secrets; avoid dumping sensitive JSON; keep credentials out of chat, shell history, and logs.\n\nRisk: Some operations are destructive or replace whole vectors, including user deletion, app environment replacement, policy replacement, VPN ACL changes, and backup password rotation.\n\nMitigation: Inspect current state first, surface irreversible effects to the user, require explicit confirmation for destructive operations, and verify results after changes.\n\nRisk: Several mutating verbs are documented as unverified or experimental.\n\nMitigation: Treat experimental command output as cautionary, avoid suppressing CLI warnings, and manually verify the resulting state before relying on it.\n\n## Reference(s):\n\n- [Olares Settings documentation](https://docs.olares.com/manual/olares/settings/)\n- [ClawHub release page](https://clawhub.ai/olares/skills/olares-settings)\n- [Olares Settings apps reference](references/olares-settings-apps.md)\n- [Olares Settings backup reference](references/olares-settings-backup.md)\n- [Olares Settings integration reference](references/olares-settings-integration.md)\n- [Olares Settings users reference](references/olares-settings-users.md)\n- [Olares Settings VPN reference](references/olares-settings-vpn.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands and optional JSON-output recommendations]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Does not produce files by itself; command output may include tables or JSON from `olares-cli` depending on flags.]\n\n## Skill Version(s):\n\n4.0.1 (source: frontmatter and server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v4.0.0: 8 files, 20075 bytes\n\nFiles: references/olares-settings-apps.md (7907b), references/olares-settings-backup.md (4591b), references/olares-settings-integration.md (5568b), references/olares-settings-users.md (5376b), references/olares-settings-vpn.md (6093b), skill-card.md (3451b), SKILL.md (13365b), _meta.json (134b)\n\nFile v4.0.0:SKILL.md\n\n---\r\nname: olares-settings\r\nversion: 4.0.0\r\ndescription: \"Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirror of every section the Olares Settings SPA exposes (https://docs.olares.com/manual/olares/settings/). Read-only coverage: users, appearance, apps (list, get, entrances, env, domain, policy), integration accounts, VPN (devices, ACL, SSH, subroutes, public-domain policy), network (reverse proxy, frp, hosts file), GPU, video, search status + dirs, backup plans + snapshots, restore plans, advanced (containerd registries, images, env system / user), plus a `me` self-service tree (whoami on Olares, version, check-update, SSO list). Verified mutating verbs: appearance language set, search rebuild, integration accounts add awss3|tencent / delete, VPN SSH enable/disable, VPN ACL add/remove, users create/delete (new Olares ID). Use when the user mentions Olares, Olares ID, Olares Settings, olares-cli settings, the Olares Settings UI, role (owner / admin / normal) on Olares, integration accounts, SSO tokens, GPU mode, search index, backup / restore plans, containerd registries, VPN ACLs, language preference, or 'who am I on this Olares instance'.\"\r\nmetadata:\r\n  requires:\r\n    bins: [\"olares-cli\"]\r\n  cliHelp: \"olares-cli settings --help\"\r\n---\r\n\r\n# settings (Olares Settings UI mirror)\r\n\r\n**CRITICAL — before doing anything, MUST use the Read tool to read [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) for profile selection, login, automatic token refresh, and the auth-error recovery table.**\r\n\r\n> **Source of truth for flags is always `olares-cli settings <area> <verb> --help`.** This file only carries what `--help` cannot give: routing, the 13-section index, the role-caching / admin-vs-normal floor, the wire-format cheat sheet, and the common-errors table.\r\n\r\n## Routing\r\n\r\n| User intent | Use this skill? |\r\n|---|---|\r\n| \"Change language / theme / appearance\" | ✅ yes |\r\n| \"Add a user / delete a user\" | ✅ yes |\r\n| \"Edit my app's entrance / domain / policy / env\" | ✅ yes (post-install surface) |\r\n| \"Add an S3 / Tencent integration account\" | ✅ yes |\r\n| \"Manage VPN devices / ACL / SSH toggle\" | ✅ yes |\r\n| \"Browse backup plans / snapshots / restore plans\" | ✅ yes |\r\n| \"Install / uninstall / upgrade / start / stop an Olares app\" | ❌ use [`olares-market`](../olares-market/SKILL.md) (this is post-install) |\r\n| \"Identify / log in / switch profile\" | ❌ use [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) (`profile login`) |\r\n| \"Inspect pods / workloads / nodes\" | ❌ use [`olares-cluster`](../olares-cluster/SKILL.md) |\r\n| \"Show CPU / memory / disk metrics\" | ❌ use [`olares-dashboard`](../olares-dashboard/SKILL.md) |\r\n\r\n> **Mental model:** `settings` covers configuration that the Olares Settings SPA exposes — **post-install per-app config**, mesh / VPN, backup, accounts, system appearance. Lifecycle and runtime live in sibling skills.\r\n\r\n## 13 area sub-trees\r\n\r\nThe umbrella registers the 12 canonical Settings docs sections, plus a 13th non-canonical `me` self-service tree:\r\n\r\n```\r\nusers         appearance   apps          integration   vpn         network\r\ngpu           video        search        backup        restore     advanced\r\n+ me (self-service: whoami / version / check-update / sso list)\r\n```\r\n\r\nShape is always `olares-cli settings <area> <verb>` (or `<area> <noun> <verb>` when the area has multiple sub-resources, e.g. `vpn devices list`, `backup plans list`).\r\n\r\n### Per-area `--help` and references\r\n\r\nFor every area, **start with `olares-cli settings <area> --help`**. References below cover the non-trivial sub-trees:\r\n\r\n| Area | `--help` first, then... |\r\n|---|---|\r\n| `me` | `olares-cli settings me --help` (whoami / version / check-update / sso list) |\r\n| `users` | [references/olares-settings-users.md](references/olares-settings-users.md) |\r\n| `apps` | [references/olares-settings-apps.md](references/olares-settings-apps.md) (entrances / domain / policy / auth-level pipeline) |\r\n| `vpn` | [references/olares-settings-vpn.md](references/olares-settings-vpn.md) (ACL deltas, SSH / subroutes / public-domain-policy) |\r\n| `integration` | [references/olares-settings-integration.md](references/olares-settings-integration.md) (`accounts add awss3|tencent`) |\r\n| `backup` | [references/olares-settings-backup.md](references/olares-settings-backup.md) (plans / snapshots / password) |\r\n| `appearance` | `olares-cli settings appearance --help` (`get`, `language set`) |\r\n| `network` | `olares-cli settings network --help` (read-only reverse-proxy / frp / hosts-file; writes blocked by JWS gap — see below) |\r\n| `gpu` | `olares-cli settings gpu --help` (read-only `list`) |\r\n| `video` | `olares-cli settings video --help` (read-only `config get`) |\r\n| `search` | `olares-cli settings search --help` (`status`, `rebuild`, `dirs list`) |\r\n| `restore` | `olares-cli settings restore --help` (read-only `plans list`) |\r\n| `advanced` | `olares-cli settings advanced --help` (read-only `status`, `registries list`, `images list`, `env (system|user) list`) |\r\n\r\n## Role caching + admin/normal floor\r\n\r\nA profile carries the role its user has on the Olares instance — `owner`, `admin`, or `normal` — cached locally so the CLI can short-circuit gated verbs without a round-trip. Populated on `profile login` / `profile import`, refreshed by `olares-cli profile whoami --refresh`.\r\n\r\n### Three whoami aliases, one driver\r\n\r\n```bash\r\nolares-cli profile whoami\r\nolares-cli settings users me\r\nolares-cli settings me whoami\r\n```\r\n\r\nAll three delegate to the same driver — same output, same caching, same `--refresh`. **Never** suggest the user \"should use the other one\" — they are aliases on purpose.\r\n\r\n### Floor table (admin-gated vs normal)\r\n\r\n| Floor | Verbs |\r\n|---|---|\r\n| **Admin (owner / admin)** | `users list / get / create / delete`; `network reverse-proxy get`, `network frp list`, `network hosts-file get`; `gpu list`; `advanced status / registries list / images list`; `vpn ssh status/enable/disable`, `vpn subroutes status`, `vpn acl all/get/add/remove`, `vpn public-domain-policy get` |\r\n| **Normal (any authenticated user)** | `me whoami / version / check-update / sso list`; `apps list/get`, `apps entrances list`, `apps env get`, `apps domain get`, `apps policy get`; `vpn devices list / routes <id>`; `appearance get`, `appearance language set`; `integration accounts list / list-by-type / get / add / delete`; `video config get`; `search status / dirs list / rebuild`; `backup plans list`, `backup snapshots list`; `restore plans list`; `advanced env (system|user) list` |\r\n\r\n### Soft preflight behavior\r\n\r\n- Admin-floor verbs check the cached role and fail fast with `role required: this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\"` **before any HTTP call**.\r\n- Server-side 401 / 403 (e.g. role changed since last cache write) still gets the same refresh-and-retry hint, even on verbs that don't preflight.\r\n- If role isn't cached yet, preflight is **soft**: it lets the call through and lets the server be authoritative.\r\n- **The standard refresh path is `olares-cli profile whoami --refresh`** — recommend it whenever a settings verb returns a permission-shaped error.\r\n\r\n## Output convention\r\n\r\nEvery read verb accepts `-o / --output {table,json}` (default `table`):\r\n\r\n- `table` is tabwriter-formatted; columns differ per verb but always print a clear \"no X\" sentinel when the result set is empty.\r\n- `json` round-trips the upstream's already-unwrapped data verbatim. **Use `-o json` whenever the agent needs to feed the result into another tool** — column ordering, truncation, and human-friendly relabeling only happen in table mode.\r\n- A handful of verbs (`video config get`, `advanced status`) downgrade table output to a one-line summary because the upstream config is large; the hint to switch to JSON is printed inline.\r\n\r\n## Wire-format cheat sheet\r\n\r\nDifferent upstream services return JSON in different envelopes. The CLI normalizes them per-area; this table is the cheat sheet for \"what's the wire format for area X\" when you need to fish out a non-tabled field via `-o json`:\r\n\r\n| Area | Endpoint family | Wire envelope |\r\n|---|---|---|\r\n| `me`, `apps`, `network`, `appearance`, `integration`, `gpu`, `video`, `search`, `advanced` | `/api/*` (user-service / BFL / terminusd) | Unwrapped BFL `{data: ...}` envelope |\r\n| `users` | `/api/users/v2`, `/api/users/:name`, `POST/DELETE /api/users/...` | List-result decoder; mutating returns axios-inner `{name}` |\r\n| `vpn` devices / ACL | `<SettingsURL>/headscale/machine`, `/headscale/machine/:id/routes` | Raw Headscale JSON (NO envelope), `route.id` is a string |\r\n| `vpn` public-domain-policy | `/api/launcher-public-domain-access-policy` | Already-unwrapped `{deny_all: 0|1}` |\r\n| `backup`, `restore` | `<SettingsURL>/apis/backup/v1/*` | BFL envelope; **different ingress prefix** (`/apis/backup/v1`, not `/api`) |\r\n| `video config get` | `/api/files/video/config` | BFL envelope, inner data as `json.RawMessage` (provider-versioned) |\r\n\r\n## Currently-implemented mutating verbs\r\n\r\nVerbs marked **VERIFIED** have been confirmed against a live Olares instance. Verbs flagged **UNVERIFIED** ship in the binary but are tracked as experimental; the CLI emits a one-line \"experimental\" stderr hint when they run.\r\n\r\n| Area | Verb | Status |\r\n|---|---|---|\r\n| `appearance` | `language set <code>` | VERIFIED |\r\n| `users` | `create` / `delete` (with `--watch`) | VERIFIED |\r\n| `search` | `rebuild`, `dirs add / remove` | VERIFIED (rebuild + dirs writes) |\r\n| `vpn ssh` | `enable` / `disable` | VERIFIED |\r\n| `vpn acl` | `add` / `remove` | VERIFIED |\r\n| `integration accounts` | `add awss3` / `add tencent` / `delete` | VERIFIED |\r\n| `apps` | `suspend [--all]` / `resume`, `env set`, `domain set/finish`, `policy set`, `auth-level set` | UNVERIFIED |\r\n| `backup` | `password set` | UNVERIFIED |\r\n\r\n**Not yet implemented** (and the CLI deliberately does NOT register them):\r\n\r\n- App lifecycle (`install` / `uninstall` / `upgrade` / `start` / `stop` / `cancel` / `clone`) → use [`olares-market`](../olares-market/SKILL.md) instead\r\n- Per-app secrets / permissions / providers (Infisical-backed) → admin / chart-side tooling\r\n- Network writes requiring a JWS-signed device-id header (`hosts-file set`, `frp set`, `ssl enable/disable/update`)\r\n- Containerd registry mutations (`registries mirrors put/delete`, `images delete/prune`) — JWS-gated\r\n- Hardware / restart-class (reboot, shutdown, ssh-password, OS upgrade) — JWS-gated via TermiPass QR callback\r\n- Backup plan create / update (needs full `BackupPolicy` + `LocationConfig` vector design)\r\n- Restore plan update / non-cancel delete — backup-server has no routes\r\n\r\n**Don't suggest the deferred verbs today** — they will error with \"command not found\".\r\n\r\n## Security rules\r\n\r\n- **Never** echo `<access_token>` or any field returned by `me sso list` into the terminal beyond what the table view shows. SSO tokens identify a TermiPass-bound device session and should never be logged or pasted into chat.\r\n- For writes that take secrets (`integration accounts add awss3|tencent`, future `backup password set`), **always read the secret from an env var or stdin pipe** — never paste it into chat or expand it inline in a suggested `olares-cli ...` command line.\r\n- `users create` / `users delete` are destructive. `delete` needs the whole word `yes` unless `--yes`. `delete` refuses owner accounts (rejected before DELETE). `create` always prints the initial password once to stdout — treat transcripts accordingly.\r\n- Read-only verbs do NOT carry \"this will change X\" prompts. **Don't fabricate one for read verbs.**\r\n- The `profile whoami --refresh` recovery path is the only authentication-adjacent action this skill recommends. **All** other auth recovery belongs in [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).\r\n\r\n## Common errors → fixes\r\n\r\n| Error | Cause | Fix |\r\n|---|---|---|\r\n| `this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\"` | Cached role below the verb's floor | If your role on the server changed: `olares-cli profile whoami --refresh`. Otherwise ask owner to grant the role |\r\n| `HTTP 403 while attempting to <verb>` (with refresh hint) | Server rejected even though cache said OK — stale role cache | `olares-cli profile whoami --refresh`, retry the verb |\r\n| `refresh token for <id> became invalid at <ts>; please run: olares-cli profile login --olares-id <id>` | The refresh_token itself is dead — see [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) | `olares-cli profile login --olares-id <id>` |\r\n| `no access token for <id>; run: olares-cli profile login --olares-id <id>` | Keychain has no entry for the active profile | `olares-cli profile login` or `profile import` |\r\n| `unsupported --output \"<x>\" (allowed: table, json)` | Typo on `-o` | Use `-o table` or `-o json` |\r\n| `GET <path>: upstream returned code <N>: <msg>` | user-service / BFL / backup-server returned non-success envelope | Read the message verbatim; it almost always carries actionable detail (e.g. \"user not found\") |\r\n\r\nFor the full auth-error matrix see [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).\n\nFile v4.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn7153k9wp5dwxsm6getv104r985vrf5\",\n  \"slug\": \"olares-settings\",\n  \"version\": \"4.0.0\",\n  \"publishedAt\": 1780030432530\n}\n\nFile v4.0.0:references/olares-settings-apps.md\n\n# settings apps (post-install configuration)\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings apps --help` and `olares-cli settings apps <verb> --help`.\r\n\r\nThe **post-install** surface for an Olares app. Inspect the app, list its entrances, edit per-entrance domain / policy / auth-level / env vars, suspend / resume.\r\n\r\n> **NOT for install / uninstall / upgrade / clone / start / stop** — use [`olares-market`](../../olares-market/SKILL.md) for app lifecycle. `settings apps` is for tweaking an app that's already installed.\r\n\r\n## Verbs at a glance\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `list [--all] [--show-system]` | normal | VERIFIED | Installed apps for the current user. Default filter mirrors the SPA |\r\n| `get <app>` | normal | VERIFIED | Detail view (filtered client-side; no per-app endpoint) |\r\n| `entrances list <app>` | normal | VERIFIED | **Live** entrance vector — names, state, auth-level |\r\n| `env get <app>` | normal | VERIFIED | Current per-app env vector |\r\n| `env set <app> KEY=VALUE [KEY=VALUE...]` | normal | UNVERIFIED | Replace the env vector |\r\n| `domain get <app> <entrance>` | normal | VERIFIED | Per-entrance custom-domain setup |\r\n| `domain list <app>` | normal | VERIFIED | Every entrance's domain setup |\r\n| `domain set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `domain finish <app> <entrance>` | normal | UNVERIFIED | Confirm third-party CNAME after DNS propagates |\r\n| `policy get <app> <entrance>` | normal | VERIFIED | Per-entrance auth policy |\r\n| `policy list <app>` | normal | VERIFIED | Every entrance's policy |\r\n| `policy set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `auth-level set <app> <entrance> --level X` | normal | UNVERIFIED | `private` / `public` / `internal` |\r\n| `suspend <app> [--all]` | normal | UNVERIFIED | Suspend running app |\r\n| `resume <app>` | normal | UNVERIFIED | Resume suspended app |\r\n\r\n## The per-entrance editing pipeline\r\n\r\nMost per-entrance edits follow a 4-step pattern:\r\n\r\n```bash\r\n# 1. Discover entrances on the app.\r\nolares-cli settings apps entrances list firefox\r\n# → produces ENTRANCE / STATE / AUTH LEVEL / DOMAIN columns\r\n\r\n# 2. Inspect current setup of the entrance you want to edit.\r\nolares-cli settings apps domain get firefox www\r\nolares-cli settings apps policy get firefox www\r\n\r\n# 3. RMW update (unspecified flags survive).\r\nolares-cli settings apps domain set firefox www --third-level my-firefox\r\nolares-cli settings apps policy set firefox www --default-policy two_factor\r\n\r\n# 4. For third-party domains: confirm CNAME after DNS propagation.\r\nolares-cli settings apps domain set firefox www --third-party firefox.example.com \\\r\n  --cert-file /path/to/cert.pem --key-file /path/to/key.pem\r\nolares-cli settings apps domain finish firefox www\r\n```\r\n\r\n## `domain set` — RMW semantics + cert/key handling\r\n\r\n```bash\r\n# Update third-level only (host under .<terminus>).\r\nolares-cli settings apps domain set firefox www --third-level my-firefox\r\n\r\n# Update third-party domain — REQUIRES --cert-file AND --key-file.\r\nolares-cli settings apps domain set firefox www \\\r\n  --third-party firefox.example.com \\\r\n  --cert-file /etc/letsencrypt/live/firefox.example.com/fullchain.pem \\\r\n  --key-file /etc/letsencrypt/live/firefox.example.com/privkey.pem\r\n\r\n# Explicitly drop a domain dimension (RMW would otherwise preserve it).\r\nolares-cli settings apps domain set firefox www --clear-third-party\r\nolares-cli settings apps domain set firefox www --clear-third-level\r\n```\r\n\r\n- **Unspecified flags survive** — RMW under the hood. Pass `--clear-*` to drop a dimension.\r\n- **Third-party domains REQUIRE both `--cert-file` AND `--key-file`** (unless `--clear-third-party`). The PEM bytes are POSTed verbatim as multi-line strings.\r\n- After `domain set --third-party`, run `domain finish` once the CNAME propagates. Without `finish`, the SPA shows \"pending\" status.\r\n\r\n## `policy set` — replace sub-policies\r\n\r\n```bash\r\n# Update default policy.\r\nolares-cli settings apps policy set firefox www --default-policy two_factor\r\n\r\n# Set one-time-link mode (factor cap).\r\nolares-cli settings apps policy set firefox www --one-time true --valid-duration 3600\r\n\r\n# Replace sub-policies (any --sub-policy flag drops the existing set).\r\nolares-cli settings apps policy set firefox www \\\r\n  --sub-policy \"uri=/admin,policy=two_factor\" \\\r\n  --sub-policy \"uri=/api,policy=public\"\r\n\r\n# Explicitly drop sub-policies.\r\nolares-cli settings apps policy set firefox www --clear-sub-policies\r\n\r\n# Bulk file form.\r\nolares-cli settings apps policy set firefox www --sub-policies-file ./sub-policies.json\r\n```\r\n\r\n- `--default-policy` values: `system` | `one_factor` | `two_factor` | `public`\r\n- Default-policy / one-time / valid-duration flags follow RMW semantics.\r\n- **Sub-policy entries are REPLACED in full whenever any sub-policy flag is passed.** This is intentional — partial sub-policy edits don't compose safely. Pass `--clear-sub-policies` to drop the existing set without adding new ones.\r\n\r\n## `auth-level set` — no GET endpoint upstream\r\n\r\n```bash\r\nolares-cli settings apps auth-level set firefox www --level public\r\n```\r\n\r\n| Level | Reachability |\r\n|---|---|\r\n| `private` | Only the app's owner |\r\n| `public` | Any authenticated user |\r\n| `internal` | Intra-cluster traffic only |\r\n\r\n> **There is no `auth-level get` verb** because no GET endpoint exists upstream. To inspect the current level, run `apps entrances list <app>` and read the `AUTH LEVEL` column.\r\n\r\n## `env get` / `env set`\r\n\r\n```bash\r\nolares-cli settings apps env get gitea\r\nolares-cli settings apps env set gitea GITEA_TOKEN=abc DB_PASS=xyz\r\n```\r\n\r\n- `env set` REPLACES the full env vector. Read current env first if you only want to add a single var.\r\n- For secrets, pipe via env var or stdin redirection. Don't paste the value into chat.\r\n\r\n## `list` filters\r\n\r\n```bash\r\nolares-cli settings apps list                  # SPA-equivalent filtered view (current user, no system apps)\r\nolares-cli settings apps list --show-system    # include system apps\r\nolares-cli settings apps list --all            # every state + every kind (cluster-wide for admins)\r\n```\r\n\r\n`get <app>` filters client-side — there is no per-app endpoint upstream. For multi-instance / cloned apps, pass the per-instance name (e.g. `windowsefe992`), not the source name (`windows`).\r\n\r\n## Agent best practices\r\n\r\n- **Always run `entrances list <app>` before any per-entrance edit.** Don't assume entrance names; the user-facing names (e.g. `www`) often differ from the chart-defined service names.\r\n- **For `policy set`**, surface `policy get` output to the user BEFORE applying — the sub-policy replacement semantics are easy to misuse.\r\n- **For `domain set --third-party`**, remind the user to set up the CNAME at their DNS provider AND run `domain finish` once it propagates.\r\n- **For UNVERIFIED verbs**, the CLI emits a one-line \"experimental\" hint on stderr — don't suppress it.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `entrance '<name>' not found on app '<app>'` | Typo / chart vs user-facing name mismatch | `apps entrances list <app>` to enumerate |\r\n| `--cert-file and --key-file are required when --third-party is set` | Third-party domain without cert | Provide both, or use `--clear-third-party` |\r\n| `--default-policy: invalid value 'X' (allowed: system, one_factor, two_factor, public)` | Typo | Use one of the four valid values |\r\n| `auth-level get is not supported (no upstream endpoint); use 'apps entrances list <app>' to read the AUTH LEVEL column` | Tried to GET auth-level | Read from `entrances list` |\r\n| `experimental: this verb is not yet smoke-verified` (stderr) | UNVERIFIED verb | Informational; proceed with caution |\n\nFile v4.0.0:references/olares-settings-backup.md\n\n# settings backup\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings backup --help` and `olares-cli settings backup <noun> <verb> --help`.\r\n\r\nManage backup plans (BFL backup-server) and the repository encryption password.\r\n\r\n> **Different ingress prefix** — `<SettingsURL>/apis/backup/v1/*` rather than `/api/*`. The CLI handles this transparently, but errors carrying the path will mention `/apis/backup/v1/...`.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `plans list` | normal | VERIFIED | List backup plans (with pagination) |\r\n| `snapshots list <backup-id>` | normal | VERIFIED | List snapshots for one plan |\r\n| `password set <name>` | normal | UNVERIFIED | Set / rotate the repository encryption password |\r\n\r\n## `plans list`\r\n\r\n```bash\r\nolares-cli settings backup plans list                     # default 50\r\nolares-cli settings backup plans list --limit 100\r\nolares-cli settings backup plans list --offset 50 --limit 50\r\nolares-cli settings backup plans list -o json\r\n```\r\n\r\nReturns each plan with name, ID, schedule, target (cloud / local / S3 / ...), status. Fields not surfaced in the table view are available via `-o json` (the SPA's axios interceptor unwraps `data.data`, which is why upstream code reads `{backups: [...]}` directly).\r\n\r\n`--offset` / `--limit` mirror the SPA's pagination behavior. Default `--limit` is 50.\r\n\r\n## `snapshots list <backup-id>`\r\n\r\n```bash\r\nolares-cli settings backup snapshots list <backup-id> --limit 50\r\nolares-cli settings backup snapshots list <backup-id> -o json\r\n```\r\n\r\nRequires the **backup ID** (from `plans list`, NOT the plan name). Returns the snapshot timeline for that plan: snapshot ID, taken-at timestamp, size, status, restic / kopia snapshot identifier.\r\n\r\n## `password set <name>` (UNVERIFIED)\r\n\r\n```bash\r\n# Interactive TTY prompt (default; no echo).\r\nolares-cli settings backup password set my-plan\r\n\r\n# Stdin pipe (scripted).\r\necho -n \"my-secret-password\" | olares-cli settings backup password set my-plan --password-stdin\r\n```\r\n\r\n- Sets / rotates the encryption password for one backup plan's repository.\r\n- **Default reads from a TTY without echo.** `--password-stdin` reads once from stdin (newline-terminated; trim newline if your producer adds one).\r\n- **Losing the password means losing the ability to decrypt existing snapshots.** The upstream cannot recover this password — make sure the user has it stored somewhere safe (password manager) BEFORE the call.\r\n\r\n## Plan create / update — out of scope (today)\r\n\r\n`plans create` and `plans update` are **not implemented yet**. They need either:\r\n\r\n- A `--from-file plan.json` mode (still pending design — the full `BackupPolicy` + `LocationConfig` vector is large), or\r\n- An upstream \"create from defaults\" shortcut that doesn't yet exist.\r\n\r\nUntil then, **create / update backup plans via the SPA** (Settings → Backup). The CLI's read verbs can still inspect plans created via the SPA.\r\n\r\n## Agent best practices\r\n\r\n- **For \"rotate the backup password\"** → always run interactively via TTY prompt unless explicitly scripted. The `--password-stdin` flow is for CI / non-interactive contexts only.\r\n- **For \"show me my backups\"** → `plans list` is the right verb. If the user then asks \"what snapshots are in plan X\", `snapshots list <backup-id>` (use the ID from `plans list -o json`).\r\n- **NEVER paste the backup password into the agent transcript or shell history.** Even in scripted form, prefer reading from a secret manager / env var that doesn't persist in scrollback.\r\n- **Surface the irreversibility warning before any `password set` interactive flow.** The user must understand that the password is the only key to existing encrypted snapshots — there is no recovery path.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `plan '<name>' not found` | Wrong backup-id or name | `plans list` to enumerate |\r\n| `snapshots list: backup-id required` | Missing positional | Provide the backup-id from `plans list` |\r\n| `failed to read password from stdin: EOF` | `--password-stdin` invoked without piped input | Pipe from `echo -n` / a file / a secret manager |\r\n| `experimental: this verb is not yet smoke-verified` (stderr) | UNVERIFIED (`password set`) | Proceed with caution; verify result manually |\r\n| `GET /apis/backup/v1/plans/backup: upstream returned code N` | Backup-server unreachable / 5xx | Check `settings advanced status` for backup-server health |\n\nFile v4.0.0:references/olares-settings-integration.md\n\n# settings integration\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings integration accounts --help` and `olares-cli settings integration accounts <verb> --help`.\r\n\r\nExternal integration accounts (S3 / Tencent COS / Google Drive / Dropbox / Olares Space / NFT cloud binding).\r\n\r\n## What's covered by the CLI\r\n\r\n| Account type | CLI verb | Why |\r\n|---|---|---|\r\n| AWS S3 (or S3-compatible endpoint) | `accounts add awss3` | Direct credentials — no OAuth |\r\n| Tencent COS | `accounts add tencent` | Direct credentials — no OAuth |\r\n| Google Drive | (SPA only) | OAuth-bound browser session |\r\n| Dropbox | (SPA only) | OAuth-bound browser session |\r\n| Olares Space / NFT cloud binding | (SPA only) | Browser- and wallet-bound by design |\r\n\r\n> **OAuth and wallet flows stay in the SPA.** The access tokens they produce are scoped to a browser session and have no useful one-shot CLI capture. If the user asks to add Google Drive / Dropbox / Olares Space / NFT integrations via CLI, direct them to the Settings → Integration page in the SPA.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Notes |\r\n|---|---|---|\r\n| `accounts list` | normal | `accountMini` shape (no `raw_data`) |\r\n| `accounts list-by-type <type>` | normal | Filter by account type |\r\n| `accounts get <type> [name]` | normal | `accountFull` shape (includes `raw_data`); `name` optional for single-tenant types |\r\n| `accounts add awss3 [flags]` | normal | AWS S3 / S3-compatible |\r\n| `accounts add tencent [flags]` | normal | Tencent COS |\r\n| `accounts delete <type> [name]` | normal | `name` optional for single-tenant types |\r\n\r\n## `accounts add awss3`\r\n\r\n```bash\r\nolares-cli settings integration accounts add awss3 \\\r\n  --access-key-id     \"$AWS_ACCESS_KEY_ID\" \\\r\n  --access-key-secret \"$AWS_SECRET_ACCESS_KEY\" \\\r\n  --endpoint          \"https://s3.amazonaws.com\" \\\r\n  --bucket            \"my-bucket\"\r\n```\r\n\r\n- `--bucket` is **optional** — omit for \"any bucket the credentials can reach\"; provide for \"scope to this bucket\".\r\n- `--endpoint` accepts any S3-compatible endpoint (MinIO, Backblaze B2 via S3 API, etc.) — not just AWS.\r\n\r\n## `accounts add tencent`\r\n\r\n```bash\r\nolares-cli settings integration accounts add tencent \\\r\n  --access-key-id     \"$TENCENT_SECRET_ID\" \\\r\n  --access-key-secret \"$TENCENT_SECRET_KEY\" \\\r\n  --endpoint          \"https://cos.ap-shanghai.myqcloud.com\"\r\n```\r\n\r\n- Region is encoded in the endpoint URL — e.g. `cos.ap-beijing.myqcloud.com`, `cos.ap-shanghai.myqcloud.com`.\r\n- Tencent COS is **single-tenant**: no `--bucket` flag, no `<name>` argument on add. There is at most one Tencent account per profile.\r\n\r\n## `accounts get` / `accounts delete` — name handling\r\n\r\n```bash\r\n# Multi-tenant types (S3, Drive, Dropbox) — need a name.\r\nolares-cli settings integration accounts get awss3 my-bucket\r\nolares-cli settings integration accounts delete awss3 my-bucket\r\n\r\n# Single-tenant types (Tencent, Space, NFT) — name omitted.\r\nolares-cli settings integration accounts get tencent\r\nolares-cli settings integration accounts delete tencent\r\n```\r\n\r\nThe store key is composed as `integration-account:<type>:<name>` (or `integration-account:<type>` when no name is supplied), matching the SPA's `getStoreKey`.\r\n\r\n## Secret handling — agent rules\r\n\r\n**The single most important rule in this sub-tree: NEVER paste secret-key values into the agent transcript.**\r\n\r\n- **Always recommend env vars or stdin pipes**: `--access-key-secret \"$AWS_SECRET_ACCESS_KEY\"`.\r\n- Bash history retention is the user's responsibility, but the agent's default phrasing should make it easy to keep secrets out of the transcript / scrollback.\r\n- For the agent's own suggestions: write `--access-key-secret \"$AWS_SECRET_ACCESS_KEY\"` (placeholder), NOT `--access-key-secret \"AKIA...\"` (real-looking).\r\n\r\n## `accounts get` JSON shape\r\n\r\n```bash\r\nolares-cli settings integration accounts get awss3 my-bucket -o json\r\n```\r\n\r\nReturns the `accountFull` shape including the un-redacted `raw_data` field. **The secret-key value WILL appear in the output** — pipe to `jq` and select only the fields you need rather than dumping the whole payload.\r\n\r\n## Agent best practices\r\n\r\n- For \"add my S3 credentials\" → prompt the user to **set the secret in an env var FIRST**, then construct the command using `\"$VAR\"` interpolation.\r\n- For \"show me my integration accounts\" → `accounts list` (no secrets) instead of `accounts get` (with secrets) unless the user specifically needs the credential payload.\r\n- For \"delete my old S3 account\" → `accounts list-by-type awss3` first to confirm the right name, then `accounts delete awss3 <name>`.\r\n- If the user asks for Google Drive / Dropbox / Olares Space / NFT cloud binding, **redirect to the SPA** — explain that OAuth tokens are browser-scoped and can't be captured by one-shot CLI calls.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `account 'X' of type '<type>' not found` | Wrong name / never added | `accounts list-by-type <type>` to enumerate |\r\n| `missing required flag: --access-key-id` (or `--access-key-secret` / `--endpoint`) | Mandatory flag omitted | Provide all three for S3 / Tencent |\r\n| `account already exists` | Single-tenant type (Tencent / Space) already has one | `accounts delete <type>` first, then add |\r\n| Secret value shows up in shell history | The user (or agent) embedded the secret on the command line directly | Re-issue from env var; clear shell history manually |\n\nFile v4.0.0:references/olares-settings-users.md\n\n# settings users\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) (especially \"Role caching + admin/normal floor\") first.\r\n> **Flags & examples:** `olares-cli settings users --help` and `olares-cli settings users <verb> --help`.\r\n\r\nInstance roster — list / get / create / delete users on the active Olares. **Admin floor** (`owner` / `admin` only).\r\n\r\n> **Not the same as `olares-cli user create`** (kube / cluster CR). `settings users` hits Termipass user-service routes; `user` writes a cluster-level CR. Mention this if the user mixes them up.\r\n\r\n## Verbs at a glance\r\n\r\n| Verb | Floor | Notes |\r\n|---|---|---|\r\n| `list` | admin | Server-side role-filtered (normal users see only themselves) |\r\n| `get <username>` | admin | Single user record (email / olaresId / role / quota) |\r\n| `me` | normal | Alias of `profile whoami` (same driver) |\r\n| `create <username>` | admin | Two flag groups: `--defaults` OR explicit `--role` / `--cpu` / `--memory-gb` |\r\n| `delete <username>` | admin | **Destructive**. Owner accounts refused. Whole-word `yes` prompt unless `--yes` |\r\n\r\n## `create` — two mutually-exclusive flag groups\r\n\r\n```bash\r\n# Group A: SPA preset (normal, 1 CPU, 4G memory; auto-generated password; DID precheck)\r\nolares-cli settings users create bob --defaults\r\nolares-cli settings users create bob --defaults --watch\r\n\r\n# Group B: explicit\r\nolares-cli settings users create alice --role admin --cpu 2 --memory-gb 8\r\nolares-cli settings users create alice --role normal --cpu 1 --memory-gb 4 --watch\r\n```\r\n\r\n- `--defaults` is mutually exclusive with `--role` / `--cpu` / `--memory-gb`.\r\n- `--role` may only be `admin` or `normal`. **The SPA account dialog cannot create an owner**, and neither can the CLI.\r\n- The initial password is **always auto-generated** by the CLI — no `--password` flag exists. The password is printed once to stdout on success; treat transcripts as sensitive.\r\n- DID precheck runs before the create POST. A username that conflicts with an existing DID fails fast with a copy-pasteable error.\r\n\r\n## `delete` — destructive, owner-safe\r\n\r\n```bash\r\nolares-cli settings users delete bob                       # whole-word \"yes\" prompt\r\nolares-cli settings users delete bob --yes                 # script mode\r\nolares-cli settings users delete bob --yes --watch         # block until Deleted\r\n```\r\n\r\n- **Owner accounts cannot be deleted** — the CLI rejects via GET before sending DELETE, matching `olares-cli user delete`.\r\n- The prompt expects the **whole word `yes`** (like ssh `yes/no`), not `y`. Reduces accidental confirmation.\r\n- Default is accepted-then-exit — the row may still appear briefly in `users list` while controllers tear it down. Use `--watch` to block until `Deleted`.\r\n\r\n## `--watch` (block until terminal state)\r\n\r\nSame shape as [`olares-cli market --watch`](../../olares-market/SKILL.md): opt-in `-w/--watch`, companion `--watch-timeout` (default 15m), `--watch-interval` (default 2s). Polls user-service's `/status` endpoint. Gives up after 5 consecutive transport errors. SIGINT-graceful.\r\n\r\n| Op | Terminal-success | Terminal-failure | absentMeansSuccess |\r\n|---|---|---|---|\r\n| `create` | `Created` | `Failed` / `Deleted`* | false |\r\n| `delete` | `Deleted` | (timeout only) | true (defensive HTTP 404) |\r\n\r\n\\* `Deleted` during a create watch means the row vanished mid-watch (controller cleanup raced) — reported as failure so JSON consumers see a non-zero exit.\r\n\r\n## JSON output shapes\r\n\r\n```jsonc\r\n// Without --watch\r\n{\"name\":\"alice\",\"original_password\":\"...\",\"status\":\"Accepted\"}\r\n{\"name\":\"bob\",\"status\":\"Accepted\"}\r\n\r\n// With --watch (final_status added)\r\n{\"name\":\"alice\",\"original_password\":\"...\",\"status\":\"Created\",\"final_status\":\"Created\",\"wizard_url\":\"https://wizard-alice.example.com\"}\r\n{\"name\":\"bob\",\"status\":\"Deleted\",\"final_status\":\"Deleted\"}\r\n```\r\n\r\n`wizard_url` appears on a successful create `--watch` — surface it to the user so they can finish setting up the new account.\r\n\r\n## Agent best practices\r\n\r\n- **Always run `users get <name>` before `users delete <name>`** in interactive sessions to confirm role and quota — gives the user a chance to back out if they targeted the wrong account.\r\n- For \"create user and tell me when they can log in\" → `users create <name> --defaults --watch -o json | jq '.wizard_url'`.\r\n- **NEVER paste the auto-generated password into chat.** Recommend the user copy it directly from the CLI output.\r\n- The opt-in `--watch` shape **flipped from a prior default of \"wait by default + `--no-wait`\"** — existing scripts that relied on blocking semantics must add `--watch` explicitly.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `cannot create user: --role required (or use --defaults)` | Group A vs B confusion | Pick one set of flags |\r\n| `cannot delete owner user` | DELETE blocked client-side | Owner accounts are unmanageable; use a different verb / SPA action |\r\n| `confirmation rejected: type the whole word 'yes' to delete` | Y/N-style answer to whole-word prompt | Type `yes`, or pass `--yes` |\r\n| `did precheck failed: <reason>` | Username conflicts with an existing DID | Pick a different username |\r\n| Watcher hangs near `Failed` | Backend create / provisioning failed | Check `users get <name>` for `status`; retry or rollback |\n\nFile v4.0.0:references/olares-settings-vpn.md\n\n# settings vpn (Headscale mesh)\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings vpn --help` and `olares-cli settings vpn <noun> <verb> --help`.\r\n\r\nManage the per-Olares Headscale mesh — devices, routes, per-app ACL, SSH toggle, sub-route toggle, public-domain-policy.\r\n\r\n## Sub-tree summary\r\n\r\n| Sub-tree | Floor | Verbs |\r\n|---|---|---|\r\n| `devices` | normal | `list`, `routes <id>` |\r\n| `ssh` | admin | `status`, `enable`, `disable` |\r\n| `subroutes` | admin | `status` (read-only) |\r\n| `acl` | admin | `all`, `get`, `add`, `remove` (alias `rm`) |\r\n| `public-domain-policy` | admin | `get` (read-only `deny_all` 0/1 flag) |\r\n\r\n## `devices` — Headscale machines\r\n\r\n```bash\r\nolares-cli settings vpn devices list\r\nolares-cli settings vpn devices routes <device-id>\r\n```\r\n\r\n- Hits `<SettingsURL>/headscale/machine` — settings nginx, not desktop.\r\n- **Raw Headscale JSON** (no envelope). `route.id` is a `string`.\r\n- `devices list` is the only normal-floor verb in this sub-tree.\r\n\r\n## `ssh` — boolean toggle\r\n\r\n```bash\r\nolares-cli settings vpn ssh status\r\nolares-cli settings vpn ssh enable\r\nolares-cli settings vpn ssh disable\r\n```\r\n\r\n- `enable` / `disable` send an explicit empty `{}` body to match the SPA's request shape, even though the upstream doesn't read it.\r\n- Run `vpn ssh status` after to confirm the resulting state.\r\n\r\n## `subroutes` — read-only toggle\r\n\r\n```bash\r\nolares-cli settings vpn subroutes status\r\n```\r\n\r\nReturns the `allow_subroutes` flag plus the current sub-route list. `-o json` emits the unwrapped `[]string` the SPA reads.\r\n\r\n## `acl` — per-app ACL (RMW under the hood)\r\n\r\nThe most flag-rich sub-tree here. **The upstream replaces the whole per-app ACL vector on every POST** — there is no add / remove endpoint. `vpn acl add` and `vpn acl remove` are read-modify-write sugar so unrelated entries survive untouched.\r\n\r\n### Read\r\n\r\n```bash\r\nolares-cli settings vpn acl all                # every app that currently has an ACL row\r\nolares-cli settings vpn acl get my-app         # per-app ACL vector\r\nolares-cli settings vpn acl get my-app -o json # full payload\r\n```\r\n\r\n### Add / remove — destination format\r\n\r\nEvery `--tcp` / `--udp` / `--any-proto` value is a **Headscale destination spec `<host>:<port>`**, NOT a bare port number.\r\n\r\n| Spec | Meaning |\r\n|---|---|\r\n| `'*:8080'` | Any source, port 8080 (this is what the Web UI's \"Add ACL\" implicitly sends) |\r\n| `'192.168.1.0/24:22'` | Restrict source CIDR |\r\n| `'tag:api:443'` | Tag-based source |\r\n| `'example-host:*'` | Allow all ports on one host |\r\n| `'*:8000-8100'` | Port range (Headscale accepts; CLI doesn't validate ranges specifically) |\r\n| `'*:*'` | Allow everything (Headscale accepts) |\r\n\r\n**Bare port numbers are rejected** by the Headscale policy parser with `invalid port format`. The CLI now pre-validates the `<host>:<port>` shape and surfaces a copy-pasteable suggestion rather than letting BFL reject the POST.\r\n\r\n### `--any-proto` = SPA \"Add ACL\" parity\r\n\r\nThe Settings page's \"Add ACL\" dialog only collects a port, hardcodes the app to the system `olares-app`, sets the source host to `*`, and posts with `proto=\"\"` so Tailscale expands to ICMPv4 / ICMPv6 / TCP / UDP. To mirror that one-for-one:\r\n\r\n```bash\r\n# SPA \"Add ACL\" port 8080 equivalent:\r\nolares-cli settings vpn acl add olares-app --any-proto '*:8080'\r\n```\r\n\r\n`--tcp` / `--udp` are strictly more expressive (per-protocol slots, named app, custom hosts/CIDRs/tags) but always emit a typed proto. `add` / `remove` use case-insensitive proto matching on the merge / subtract paths, so empty-proto entries created via `--any-proto` round-trip cleanly alongside `--tcp` / `--udp` ones.\r\n\r\n### Examples\r\n\r\n```bash\r\n# Merge a single TCP destination.\r\nolares-cli settings vpn acl add my-app --tcp '*:8080'\r\n\r\n# Merge multiple destinations (repeated flag OR comma-separated; both work, both de-dupe).\r\nolares-cli settings vpn acl add my-app --tcp '*:80' --tcp '*:443' --udp '*:53'\r\nolares-cli settings vpn acl add my-app --tcp '*:80,*:443'\r\n\r\n# Restrict source CIDR.\r\nolares-cli settings vpn acl add my-app --tcp '192.168.1.0/24:22'\r\n\r\n# Remove a destination.\r\nolares-cli settings vpn acl remove my-app --tcp '*:80'\r\nolares-cli settings vpn acl rm     my-app --udp '*:53'   # alias\r\n\r\n# SPA Web parity (all protocols).\r\nolares-cli settings vpn acl add olares-app --any-proto '*:8080'\r\n```\r\n\r\n## `public-domain-policy` — read-only switch\r\n\r\n```bash\r\nolares-cli settings vpn public-domain-policy get\r\n```\r\n\r\nReturns the `deny_all` flag (0 or 1). The write side stays in the SPA today.\r\n\r\n## Agent best practices\r\n\r\n- **Always run `vpn acl get <app>` before mutating** — the RMW semantics mean a wrong delta can silently drop unrelated entries (it shouldn't, but inspecting first catches surprise edge cases).\r\n- **For \"I want the same thing the SPA's 'Add ACL' button does\"** → `vpn acl add olares-app --any-proto '<host>:<port>'`. Don't try to reconstruct it from `--tcp` / `--udp`.\r\n- **Bare port number is the #1 mistake** — when the user says \"allow port 8080\", suggest `'*:8080'`, not `8080`.\r\n- `ssh enable` / `disable` are SAFE to use in interactive sessions (idempotent boolean toggle), but **note that disabling SSH cuts off any ongoing TermiPass SSH session** — confirm intent before invoking.\r\n\r\n## Common errors\r\n\r\n| Symptom | Cause | Fix |\r\n|---|---|---|\r\n| `invalid port format` (from Headscale) | Bare port number passed instead of `<host>:<port>` | Use `'*:<port>'` (any source) |\r\n| `acl add: --tcp / --udp / --any-proto required` | No destination specs | Provide at least one |\r\n| `device-id '<id>' not found in Headscale` | Wrong device id | `vpn devices list` to enumerate |\r\n| `role required: ... admin` | Normal user trying admin-only verb | Switch profile to an admin / owner |\r\n| ACL changes don't seem to take effect | Read the RMW caveat — sub-policies / acl entries on other protocols you didn't pass DO survive | Re-run with the right flag set |\n\nFile v4.0.0:skill-card.md\n\n## Description: <br>\nHelps agents read and manage Olares Settings through `olares-cli settings`, including users, appearance, installed app settings, integration accounts, VPN, network, GPU, video, search, backup, restore, advanced settings, and self-service profile checks. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[olares](https://clawhub.ai/user/olares) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers, operators, and Olares administrators use this skill to choose the correct `olares-cli settings` commands, inspect per-Olares-ID configuration, and apply supported settings changes while respecting role and credential handling constraints. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Some supported settings changes are destructive or security-sensitive, including deleting users, exposing app entrances, changing VPN ACLs, rotating backup passwords, and handling cloud credentials. <br>\nMitigation: Review proposed commands before execution, confirm destructive actions explicitly, and use environment variables or interactive prompts for secrets instead of pasting credentials into chat or command text. <br>\nRisk: Broad VPN ACLs such as `*:*` can expose more access than intended. <br>\nMitigation: Prefer narrowly scoped ACL rules and use broad rules only when the operator explicitly requests that exposure. <br>\nRisk: The skill acts against the active Olares profile, so commands may affect the wrong Olares ID if the profile is stale or mis-selected. <br>\nMitigation: Check the active profile and role before changes, and refresh identity with `olares-cli profile whoami --refresh` when permission or role errors appear. <br>\nRisk: Losing or mishandling backup encryption passwords can make existing snapshots unrecoverable. <br>\nMitigation: Store backup passwords in a password manager before rotation and avoid logging or displaying them in transcripts. <br>\n\n\n## Reference(s): <br>\n- [Olares Settings documentation](https://docs.olares.com/manual/olares/settings/) <br>\n- [ClawHub release page](https://clawhub.ai/olares/olares-settings) <br>\n- [Olares publisher profile](https://clawhub.ai/user/olares) <br>\n- [Olares Settings users reference](references/olares-settings-users.md) <br>\n- [Olares Settings apps reference](references/olares-settings-apps.md) <br>\n- [Olares Settings VPN reference](references/olares-settings-vpn.md) <br>\n- [Olares Settings integration reference](references/olares-settings-integration.md) <br>\n- [Olares Settings backup reference](references/olares-settings-backup.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with inline shell commands and JSON-oriented command recommendations] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May recommend table or JSON output modes for `olares-cli settings` commands depending on whether humans or tools consume the result.] <br>\n\n## Skill Version(s): <br>\n4.0.0 (source: frontmatter and server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.2.0: 3 files, 15619 bytes\n\nFiles: skill-card.md (2472b), SKILL.md (38087b), _meta.json (134b)\n\nFile v1.2.0:SKILL.md\n\n---\r\nname: olares-settings\r\nversion: 1.2.0\r\ndescription: \"Read and mutate Olares Settings UI surfaces via olares-cli settings — the per-profile command-line mirror of every section the Olares Settings SPA exposes (https://docs.olares.com/manual/olares/settings/). Read-only coverage: users, appearance, apps (list, get, entrances, env, domain, policy), integration accounts, VPN (devices, ACL, SSH, subroutes, public-domain policy), network (reverse proxy, frp, hosts file), GPU, video, search status + dirs, backup plans + snapshots, restore plans, advanced (containerd registries, images, env system / user), plus a `me` self-service tree (whoami, version, check-update, SSO list). Verified mutating verbs: appearance language set, search rebuild, integration accounts add awss3|tencent / delete, VPN SSH enable/disable, VPN ACL add/remove. Use when the user mentions Olares Settings, olares-cli settings, the Olares Settings UI, role (owner / admin / normal), integration accounts, SSO tokens, GPU mode, search index, backup / restore plans, containerd registries, VPN ACLs, language preference, or 'who am I on this Olares instance'.\"\r\nmetadata:\r\n  requires:\r\n    bins: [\"olares-cli\"]\r\n  cliHelp: \"olares-cli settings --help\"\r\n---\r\n\r\n# settings (Olares Settings UI mirror)\r\n\r\n**CRITICAL — before doing anything, MUST use the Read tool to read [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) for the profile selection, login, and HTTP 401/403 recovery rules that every command here depends on.**\r\n\r\n## What this command tree is\r\n\r\n`olares-cli settings ...` is the CLI mirror of the Olares desktop SPA's Settings page (the same surface documented at <https://docs.olares.com/manual/olares/settings/>). Identity and transport come from the active profile — same profile model, same access token, same edge-auth chain (Authelia + l4-bfl-proxy) the SPA uses.\r\n\r\nThe umbrella registers **13 area sub-trees** (see [`cli/cmd/ctl/settings/root.go`](cli/cmd/ctl/settings/root.go)):\r\n\r\n```\r\nusers         appearance   apps          integration   vpn         network\r\ngpu           video        search        backup        restore     advanced\r\n```\r\n\r\n…plus a 13th non-canonical tree, `me`, that hosts the SPA's avatar / Person dropdown self-service items. **`me` is intentionally outside the 12 canonical Settings docs sections**; it lives under `settings` for CLI discoverability, not because it's a docs section.\r\n\r\n> The shape is always `olares-cli settings <area> <verb>` (or `<area> <noun> <verb>` when the area has multiple sub-resources, e.g. `settings vpn devices list`, `settings backup plans list`). Every verb runs against the currently-selected profile; switch with `olares-cli profile use <name>` ahead of time (there is no per-invocation override flag).\r\n\r\n## Authentication transport\r\n\r\nEvery request goes through the factory-injected `*http.Client` and the resolved profile from `cmdutil.Factory`. There is no kubeconfig dependency.\r\n\r\n- Base URL: **per-area split** between `rp.DesktopURL` (default) and `rp.SettingsURL`. The two SPAs serve from different per-user origins — desktop launcher SPA at `https://desktop.<terminus>` (nginx: [`apps/docker/system-frontend/nginx/desktop.conf`](apps/docker/system-frontend/nginx/desktop.conf)), Settings SPA at `https://settings.<terminus>` (nginx: [`apps/docker/system-frontend/nginx/settings.conf`](apps/docker/system-frontend/nginx/settings.conf), the origin Settings SPA itself uses via `tokenStore.setUrl(window.location.origin)` in [`settings/src/application/settings.ts`](settings/src/application/settings.ts)). The two nginx configs share `/api/*` (both forward to user-service:3010) but diverge elsewhere:\r\n  - **`rp.SettingsURL`** is required for areas that hit settings-only locations: `vpn` (`/headscale/*`), `backup` / `restore` (`/apis/backup/v1/*`). Settings nginx also exclusively exposes `/admin/*` (Infisical), `/drive`, `/vault`, `/images`, `/api/cloud/sign`.\r\n  - **`rp.DesktopURL`** is the default for every other area. Desktop nginx has dedicated reverse proxies that settings nginx does NOT: `/api/device → settings-service`, `/api/logout → authelia-svc`, `/api/refresh → authelia-backend-svc`. The `me` area's SSO list (`/api/device/sso`) and any future code reading `/api/device/*` is therefore wired through DesktopURL on purpose — moving it would silently swap backends. Same goes for the three `whoami` aliases (`profile whoami`, `settings users me`, `settings me whoami`), which read cached identity served from desktop ingress.\r\n  Refer to `olares.ID.DesktopURL` / `olares.ID.SettingsURL` doc comments for the canonical location-set tables.\r\n- Auth header: `X-Authorization: <access_token>` (NOT `Authorization: Bearer …`). Injected by the factory's `refreshingTransport` (see [`cli/pkg/cmdutil/factory.go`](cli/pkg/cmdutil/factory.go)); the settings area `prepare()` helpers never call `req.Header.Set(\"X-Authorization\", …)` themselves.\r\n- **Expired access_tokens are auto-rotated.** When the server returns 401/403, the transport hits `/api/refresh`, persists the new token, and retries the original request once — transparently to the caller. Users do NOT need to run `profile login` just because their access_token aged out; only when the *refresh_token* itself is invalidated. Full mechanics — concurrency, cross-process flock, typed `*credential.ErrTokenInvalidated` / `*credential.ErrNotLoggedIn` errors — are documented in [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) under \"Automatic token refresh\". **Do not write retry loops on top of these typed errors** — once you see one, only `profile login` / `profile import` will help.\r\n- Two ingress prefixes show up in this subtree:\r\n  - `/api/*` (the bulk of the surface) — terminates at user-service, which proxies BFL / app-service / Headscale / terminusd / search3 / HAMI etc.\r\n  - `/apis/backup/v1/*` (`settings backup`, `settings restore`) — terminates at BFL's backup-server directly.\r\n- 401 / 403 that survive auto-refresh (i.e. the server still says no after the new token was issued) are translated into a CLI-friendly hint via the `WrapPermissionErr` + `PreflightRole` helpers in [`cli/pkg/whoami/preflight.go`](cli/pkg/whoami/preflight.go), wrapped per-area through [`cli/cmd/ctl/settings/internal/preflight`](cli/cmd/ctl/settings/internal/preflight). See \"Soft preflight\" below for which verbs have been retrofitted. **Token recovery is not handled here — defer to [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).**\r\n\r\n## Role caching + soft preflight\r\n\r\nA profile carries the role its user has on the Olares instance (`owner`, `admin`, or `normal`), cached locally so the CLI can short-circuit gated verbs without a round-trip. The cache lives in `ProfileConfig.OwnerRole` + `WhoamiRefreshedAt` (see [`cli/pkg/cliconfig`](cli/pkg/cliconfig)) and is populated three ways:\r\n\r\n| Trigger | Behavior |\r\n|---|---|\r\n| `olares-cli profile login` succeeds | Eager whoami fetch, best-effort, 5-second timeout (see [`cli/cmd/ctl/profile/whoami_eager.go`](cli/cmd/ctl/profile/whoami_eager.go)). Failure does **not** abort the login. |\r\n| `olares-cli profile import` succeeds | Same eager fetch as login. |\r\n| User runs `olares-cli profile whoami --refresh` | Forced re-read of `/api/backend/v1/user-info`; cache rewritten in place. Plain `profile whoami` (no flag) prints the cached value if fresh. |\r\n\r\n### Three aliases, one driver\r\n\r\nThese three commands all delegate to the same `pkg/whoami.Run` driver — same output, same caching, same `--refresh`:\r\n\r\n```bash\r\nolares-cli profile whoami\r\nolares-cli settings users me\r\nolares-cli settings me whoami\r\n```\r\n\r\nUse whichever path makes the surrounding workflow read better; **never** suggest the user \"should use the other one\" — they are aliases on purpose. All three accept `-o table` (default) and `-o json`.\r\n\r\n### Soft preflight (wired per SPA UI gating)\r\n\r\n`whoami.PreflightRole(...)` + `whoami.WrapPermissionErr(...)` (in [`cli/pkg/whoami/preflight.go`](cli/pkg/whoami/preflight.go)) are wrapped per-area by `preflight.Gate(...)` / `preflight.Wrap(...)` (in [`cli/cmd/ctl/settings/internal/preflight`](cli/cmd/ctl/settings/internal/preflight)) and called at the top of every admin-gated `RunE`.\r\n\r\nFloor assignment mirrors the SPA's `apps/.../stores/settings/admin.ts:menus` + per-page `v-if=\"adminStore.isAdmin\"` guards 1:1:\r\n\r\n| Floor | Verbs |\r\n|---|---|\r\n| **Admin (owner / admin)** | `users list`, `users get`, `users create`, `users delete`; `network reverse-proxy get`, `network frp list`, `network hosts-file get`; `gpu list`; `advanced status`, `advanced registries list`, `advanced images list`; `vpn ssh status/enable/disable`, `vpn subroutes status`, `vpn acl all/get/add/remove`, `vpn public-domain-policy get` |\r\n| **Normal (any authenticated user)** | `me whoami / version / check-update / sso list`; `apps list/get`, `apps entrances list`, `apps env get`, `apps domain get`, `apps policy get`; `vpn devices list`, `vpn devices routes <id>`; `appearance get`, `appearance language set`; `integration accounts list/list-by-type/get/add/delete`; `video config get`; `search status`, `search dirs list`, `search rebuild`; `backup plans list`, `backup snapshots list`; `restore plans list`; `advanced env system list`, `advanced env user list` |\r\n\r\nPractical implications for the agent:\r\n\r\n- Admin-floor verbs run an upfront check against the cached role on the active profile and fail fast with **`role required: this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\" — run \\`olares-cli profile whoami --refresh\\` if your role on the server changed`** before issuing any HTTP call.\r\n- Both floors run their result through `WrapPermissionErr`, so a server-side 401 / 403 (e.g. role changed since last cache write) still gets the same refresh-and-retry hint suffix — even on verbs that don't preflight.\r\n- If `OwnerRole` isn't cached yet (very fresh `profile import`, or the `whoami_eager` fetch failed), preflight is **soft**: it lets the call through and lets the server be authoritative. Recommend `olares-cli profile whoami --refresh` whenever a settings verb returns a permission-shaped error.\r\n\r\n## Output convention\r\n\r\nEvery read verb accepts `-o / --output {table,json}` (default `table`):\r\n\r\n- `table` is wrapped in [`text/tabwriter`](https://pkg.go.dev/text/tabwriter); columns differ per verb but always print a clear \"no X\" sentinel when the result set is empty.\r\n- `json` round-trips the upstream's already-unwrapped data verbatim. **Use `-o json` whenever the agent needs to feed the result into another tool** (jq, downstream scripts, etc.) — column ordering, truncation, and human-friendly relabeling only happen in table mode.\r\n- A handful of verbs (e.g. `settings video config get`, `settings advanced status`) deliberately downgrade the table output to a one-line summary because the upstream config is large + provider-versioned. The hint to switch to JSON is printed inline.\r\n\r\n## Per-area wire format normalization\r\n\r\nDifferent upstreams return JSON in different envelopes. Each area has its own `common.go` that picks the matching decoder; **the table below is the cheat sheet for \"what's the wire format for area X\"**.\r\n\r\n| Area | Endpoint family | Decoder | Notes |\r\n|---|---|---|---|\r\n| `me` | `/api/olares-info`, `/api/checkLastOsVersion`, `/api/device/sso` | BFL envelope (`doGetEnvelope`) | self-service identity + version + SSO sessions on the active profile |\r\n| `users` | `/api/users/v2` (list), `/api/users/:name` (single), `POST /api/users`, `DELETE /api/users/:name` | list: `decodeListResult`; get: envelope-aware `decodeObjectResult`; create/delete: `doMutateUsersAPI` (`decodeUsersMutateBody`) because Nest returns axios inner `{name}` | list: normal users see only themselves; mutating routes lack extra RBAC in user-service today |\r\n| `apps` | `/api/myapps` | BFL envelope, `appInfo.ports` decoded as `[]servicePort` (5-field object array: name / host / port / exposePort / protocol) | `apps get <name>` filters the list client-side because there's no per-app endpoint; honours `--all` / `--show-system` to mirror the SPA's filters |\r\n| `vpn` | `/headscale/machine`, `/headscale/machine/:id/routes` | Raw Headscale JSON (no envelope), `route.id` is `string` | SPA hits `<SettingsURL>/headscale/...` (settings nginx, not desktop) without `/api` prefix |\r\n| `vpn` | `/api/launcher-public-domain-access-policy` | Already-unwrapped BFL inner data (`{deny_all: 0|1}`) | user-service strips the envelope |\r\n| `network` | `/api/reverse-proxy`, `/api/frp-servers`, `/api/ssl/task-state`, `/api/system/hosts-file` | BFL envelope (`doGetEnvelope`) | hosts-file goes through terminusd → olaresd; user-service falls back to `X-Authorization` since the CLI doesn't yet JWS-sign reads |\r\n| `appearance` | `/api/wallpaper/config/system` | BFL envelope | language + locale only; theme + wallpaper upload stay in the SPA |\r\n| `integration` | `/api/account/all`, `/api/account/:type/:name` | BFL envelope | `accounts list` returns `accountMini`; `accounts get` returns `accountFull` (includes `raw_data`) |\r\n| `gpu` | `/api/gpu/list` | BFL envelope (HAMI behind it) | distinct from the top-level `olares-cli gpu` (kubeconfig-driven, cluster-wide) |\r\n| `video` | `/api/files/video/config` | BFL envelope, but inner data is decoded as `json.RawMessage` (`doGetEnvelopeRaw`) | Schema is provider-versioned; `--output table` collapses to a one-line summary |\r\n| `search` | `/api/search/task/stats/merged`, `/api/search/monitorsetting/include-directory/full_content` | BFL envelope | `status` returns a string, `dirs list` returns `[]string` |\r\n| `advanced` | `/api/system/status`, `/api/containerd/registries`, `/api/containerd/images?registry=<n>`, `POST /api/command/collectLogs` | BFL envelope (terminusd → olaresd `returnSucceed`) | `status` table view is a summary; `--output json` for the full struct. `POST /api/command/collectLogs` is for the **Terminus SPA Developer UI** (polls `/api/system/status`); it is **not** a `settings advanced` CLI verb — use top-level **`olares-cli logs`** for CLI log collection |\r\n| `backup` | `/apis/backup/v1/plans/backup`, `/apis/backup/v1/plans/backup/:id/snapshots` | BFL envelope; **different ingress prefix** (`/apis/backup/v1`, not `/api`) | The SPA's axios global interceptor unwraps `data.data`, which is why upstream code reads `{backups: [...]}` directly |\r\n| `restore` | `/apis/backup/v1/plans/restore` | BFL envelope; same `/apis/backup/v1` prefix | mirrors `settings backup plans list` shape |\r\n\r\nIf a future verb is missing from this table, look at the area's `common.go` to confirm which decoder it uses — every `prepare(...)` helper instantiates a `*whoami.HTTPClient` against `<DesktopURL>` so the path is the only thing that varies.\r\n\r\n## Currently available — read-only commands\r\n\r\nRead-only verbs across every area. Mutating verbs are listed in the next section. Anything not appearing in either list is either deferred to the next iteration or out of scope (see the \"Deferred to next iteration\" section near the bottom).\r\n\r\n### `me` — self-service (any authenticated user)\r\n\r\n```bash\r\nolares-cli settings me whoami                     # cached role + olaresId\r\nolares-cli settings me whoami --refresh           # force a re-read of /api/backend/v1/user-info\r\nolares-cli settings me whoami -o json\r\nolares-cli settings me version                    # Olares OS version + osBuild + arch\r\nolares-cli settings me check-update               # current_version, new_version, is_new\r\nolares-cli settings me sso list                   # SSO tokens currently bound to this profile (with ID column)\r\n```\r\n\r\n### `users` — instance roster\r\n\r\n```bash\r\nolares-cli settings users list                    # roster, server-side role-filtered\r\nolares-cli settings users get alice               # single user record\r\nolares-cli settings users create bob --defaults                                  # SPA preset: normal, 1 CPU, 4G memory; auto password; DID precheck; accepted-then-exit\r\nolares-cli settings users create bob --defaults --watch                          # synchronous: block until provisioning reaches Created and the Wizard URL is materialized\r\nolares-cli settings users create alice --role admin --cpu 2 --memory-gb 8        # explicit quota; default accepted-then-exit (use --watch to wait)\r\nolares-cli settings users delete bob              # accepted-then-exit (the row may still appear briefly in `users list`); type yes or use --yes\r\nolares-cli settings users delete bob --yes --watch   # synchronous: block until status is Deleted (same opt-in shape as `olares-cli market <verb> --watch`)\r\n# owner accounts cannot be deleted (CLI rejects before DELETE, same as `olares-cli user delete`)\r\nolares-cli settings users me                      # alias of `me whoami`\r\n```\r\n\r\n`create`/`delete` are accepted-then-exit by default; pass `-w/--watch` (with `--watch-timeout` / `--watch-interval`) to block until terminal state — the flag triple mirrors [`olares-cli market --watch`](../olares-market/SKILL.md#watch-flag) so both surfaces feel identical to operators. **Note**: this flips the prior default from \"wait by default + `--no-wait`\" — scripts that relied on blocking semantics must add `--watch` explicitly.\r\n\r\n`create`/`delete` hit the Termipass user-service routes, not `olares-cli user create` (kube CR).\r\n\r\n<a id=\"users-watch-flag\"></a>\r\n#### `users --watch` (block until terminal state)\r\n\r\nSame shape as the market verb's [`--watch`](../olares-market/SKILL.md#watch-flag) — opt-in `-w/--watch`, with companion `--watch-timeout` (15m) and `--watch-interval` (2s). Implementation lives in [`cli/cmd/ctl/settings/users/watch.go`](cli/cmd/ctl/settings/users/watch.go) (`waitForUserState`, `newUserWatchTarget`, `userWatchTimeoutError`, `userWatchFailureError`); the loop wraps `signal.NotifyContext` for Ctrl-C and gives up after 5 consecutive transport errors.\r\n\r\nPer-op terminal sets (from [`cli/cmd/ctl/settings/users/watch.go`](cli/cmd/ctl/settings/users/watch.go)):\r\n\r\n| Op       | Success    | Failure                  | absentMeansSuccess        |\r\n|----------|------------|--------------------------|---------------------------|\r\n| `create` | `Created`  | `Failed` / `Deleted`*    | false                     |\r\n| `delete` | `Deleted`  | (timeout only)           | true (defensive HTTP 404) |\r\n\r\n\\* `Deleted` during a create watch means the row vanished mid-watch (controller cleanup raced), reported back as a failure so JSON consumers get a non-zero exit.\r\n\r\nJSON output adds `final_status` when `--watch` is set:\r\n\r\n```json\r\n{\"name\":\"alice\",\"original_password\":\"...\",\"status\":\"Created\",\"final_status\":\"Created\",\"wizard_url\":\"https://wizard-alice.example.com\"}\r\n{\"name\":\"bob\",\"status\":\"Deleted\",\"final_status\":\"Deleted\"}\r\n```\r\n\r\nWithout `--watch`, JSON is `{\"name\":\"…\",\"status\":\"Accepted\"}` (create additionally echoes `original_password`).\r\n\r\n\r\n### `apps` — installed app inventory (mirror of Settings -> Apps)\r\n\r\n```bash\r\nolares-cli settings apps list                     # SPA-equivalent filtered view\r\nolares-cli settings apps list --show-system       # include system apps\r\nolares-cli settings apps list --all               # every state + every kind\r\nolares-cli settings apps get firefox              # detail view (entrances, shared entrances, …)\r\nolares-cli settings apps entrances list firefox   # live entrance vector (fresher than `apps get`)\r\nolares-cli settings apps env get firefox          # current env vector for the app\r\nolares-cli settings apps domain get firefox www   # custom domain on a single entrance\r\nolares-cli settings apps policy get firefox www   # two-factor / one-time-link policy on a single entrance\r\n```\r\n\r\nThe `entrances list` / `domain get` / `policy get` reads target the BFL-style `/api/applications/<app>/<entrance>/setup/{domain,policy}` routes; pair them with `apps get` when you need both the lifecycle status and the per-entrance config.\r\n\r\n### `vpn` — Headscale mesh\r\n\r\n```bash\r\nolares-cli settings vpn devices list              # raw Headscale machines\r\nolares-cli settings vpn devices routes <device-id>\r\nolares-cli settings vpn ssh status                # GET /api/acl/ssh/status\r\nolares-cli settings vpn subroutes status          # allow_subroutes flag + sub-route list (-o json: unwrapped []string the SPA reads)\r\nolares-cli settings vpn acl all                   # every app that currently has an ACL row\r\nolares-cli settings vpn acl get my-app            # per-app ACL vector; -o json for the full payload\r\nolares-cli settings vpn public-domain-policy get  # deny_all flag (0/1)\r\n```\r\n\r\n### `network`\r\n\r\n```bash\r\nolares-cli settings network reverse-proxy get     # mode collapsed into public-ip / frp / cloudflare / off\r\nolares-cli settings network frp list              # registry of FRP servers\r\nolares-cli settings network hosts-file get        # entries from /system/hosts-file (terminusd)\r\n```\r\n\r\n### `appearance` / `integration` / `gpu` / `video` / `search` / `advanced`\r\n\r\n```bash\r\nolares-cli settings appearance get\r\nolares-cli settings integration accounts list\r\nolares-cli settings integration accounts list-by-type google\r\nolares-cli settings integration accounts get awss3 my-bucket\r\nolares-cli settings gpu list\r\nolares-cli settings video config get              # raw config; -o json recommended\r\nolares-cli settings search status\r\nolares-cli settings search dirs list\r\nolares-cli settings advanced status               # large struct; -o json for the full payload\r\nolares-cli settings advanced registries list\r\nolares-cli settings advanced images list\r\nolares-cli settings advanced images list --registry docker.io\r\n```\r\n\r\n### `backup` / `restore`\r\n\r\n```bash\r\nolares-cli settings backup plans list             # --offset / --limit (default 50, mirrors SPA)\r\nolares-cli settings backup snapshots list <backup-id> --limit 50\r\nolares-cli settings restore plans list\r\n```\r\n\r\n## Currently available — mutating commands (smoke-verified)\r\n\r\nEvery mutating verb in this section has been confirmed against a live Olares instance in the latest smoke run (see [`cli/cmd/ctl/settings/scripts/local_report_phase15a.md`](cli/cmd/ctl/settings/scripts/local_report_phase15a.md)). All of them hit the `<DesktopURL>` ingress over `X-Authorization` and none require a JWS-signed body. Verbs that ship in the binary but were not exercised (or did not pass) live in [`cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md`](cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md) — treat them as experimental until they show up here.\r\n\r\n**Also ships (awaiting smoke):** `users create` / `users delete` — **admin-floor** preflight; `create` uses `--defaults` (normal / 1 / 4G) or explicit `--role`, `--cpu`, `--memory-gb`; DID precheck; no `--password`; **both verbs default to accepted-then-exit**; pass **`-w/--watch`** (with `--watch-timeout` 15m, `--watch-interval` 2s — same triple as [`olares-cli market --watch`](../olares-market/SKILL.md#watch-flag)) to block until `Created` / `Deleted`; **`delete`** needs the whole word `yes` unless **`--yes`**; **`delete` refuses owner** (pre-check via GET, before confirmation). Smoke pairing: `INCLUDE_USERS_MUTATE=1`. Backend gap: user-service does not role-gate POST/DELETE beyond authentication.\r\n\r\n### `appearance` — language\r\n\r\n```bash\r\nolares-cli settings appearance language set en-US           # POST /api/wallpaper/update/language\r\nolares-cli settings appearance language set --value zh-CN\r\nolares-cli settings appearance language set ja-JP --force   # bypass whitelist (use sparingly)\r\n```\r\n\r\nThe CLI mirrors the SPA's `supportLanguages` whitelist client-side ([`apps/packages/app/src/i18n/index.ts:12`](apps/packages/app/src/i18n/index.ts) — currently `en-US`, `zh-CN`) because **neither user-service nor BFL validate the value today**: an unknown locale would land in the config-system CRD verbatim and the SPA would silently fall back to `defaultLanguage` on the next session. Pass `--force` only when the SPA has shipped a new locale ahead of this CLI build; the upstream still accepts arbitrary strings, so a typo with `--force` will appear to succeed but produce no visible change.\r\n\r\n### `search` — index rebuild\r\n\r\n```bash\r\nolares-cli settings search rebuild                          # POST /api/search/task/rebuild\r\n```\r\n\r\n`rebuild` is async + heavy: the call returns as soon as search3 accepts the task; verify completion with `olares-cli settings search status` rather than waiting on the POST itself. `dirs` writes ship in the binary but are tracked in [`UNVERIFIED_COMMANDS.md`](cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md) until a smoke report greens them.\r\n\r\n### `vpn ssh` — boolean ACL toggle\r\n\r\n```bash\r\nolares-cli settings vpn ssh enable                  # POST /api/acl/ssh/enable\r\nolares-cli settings vpn ssh disable                 # POST /api/acl/ssh/disable\r\n```\r\n\r\nBoth toggles send an explicit empty `{}` body to match the SPA's request shape, even though the upstream doesn't read the body. Use `vpn ssh status` (read section above) to confirm the resulting state.\r\n\r\n### `vpn acl` — per-app ACL add / remove (read-modify-write)\r\n\r\n```bash\r\nolares-cli settings vpn acl add    my-app --tcp '*:8080'              # merge a TCP dst (any source, port 8080)\r\nolares-cli settings vpn acl add    my-app --tcp '192.168.1.0/24:22'   # restrict source CIDR\r\nolares-cli settings vpn acl remove my-app --tcp '*:80'                # drop a TCP dst\r\nolares-cli settings vpn acl rm     my-app --udp '*:53'                # alias of `remove`\r\nolares-cli settings vpn acl add    olares-app --any-proto '*:8080'    # Web 'Add ACL' parity (proto=\"\")\r\n```\r\n\r\n**Destination spec (important).** Every `--tcp` / `--udp` / `--any-proto` value is a Headscale destination spec `<host>:<port>`, **not** a bare port number. The upstream policy parser (Headscale, via BFL `parseDestination`) splits on the last `:` and rejects single-token values with `invalid port format`. Use `'*:8080'` for \"any source, port 8080\" (this is what the Web UI implicitly sends), `'192.168.1.0/24:22'` to restrict the source, `'tag:api:443'` for tag-based sources, or `'example-host:*'` to allow all ports on one host. The CLI now pre-validates this shape and surfaces a copy-pasteable suggestion rather than letting the BFL reject the POST. Both repeated flags (`--tcp '*:80' --tcp '*:443'`) and comma-separated values (`--tcp '*:80,*:443'`) work and are deduped client-side. The upstream still accepts ranges (`*:8000-8100`) and `*:*`; the CLI only checks that a `:` separates two non-empty halves.\r\n\r\n**Web parity via `--any-proto`.** The Settings page's \"Add ACL\" dialog only collects a port, hardcodes the app to the system `olares-app`, sets the source host to `*`, and posts the entry with `proto=\"\"` so Tailscale expands it to ICMPv4 / ICMPv6 / TCP / UDP. The CLI's `--tcp` / `--udp` flags are strictly more expressive (per-protocol slots, named app, custom hosts/CIDRs/tags) but they always emit a typed proto. To mirror the Web shape one-for-one — including the empty proto so the rule applies to all protocols — pass `--any-proto '<host>:<port>'`; e.g. `vpn acl add olares-app --any-proto '*:8080'` is the exact payload the \"Add ACL\" dialog would send for port 8080. `add` / `remove` use case-insensitive proto matching on the merge/subtract paths, so empty-proto entries created via `--any-proto` round-trip cleanly alongside `--tcp` / `--udp` ones.\r\n\r\nThe upstream replaces the **whole** per-app ACL vector on every POST; there is no add / remove endpoint. `vpn acl add` and `vpn acl remove` are read-modify-write sugar over the same POST so unrelated entries survive untouched (matching how the SPA's add / remove buttons work). Use `vpn acl get <app>` (read section) to inspect the current vector before mutating; `vpn acl all` (also read) lists every app that currently has an ACL row.\r\n\r\n### `integration` — connected accounts\r\n\r\n```bash\r\nolares-cli settings integration accounts add awss3 \\\r\n  --access-key-id     \"$AWS_ACCESS_KEY_ID\" \\\r\n  --access-key-secret \"$AWS_SECRET_ACCESS_KEY\" \\\r\n  --endpoint          \"https://s3.amazonaws.com\" \\\r\n  --bucket            \"my-bucket\"            # optional\r\n\r\nolares-cli settings integration accounts add tencent \\\r\n  --access-key-id     \"$TENCENT_SECRET_ID\" \\\r\n  --access-key-secret \"$TENCENT_SECRET_KEY\" \\\r\n  --endpoint          \"https://cos.ap-shanghai.myqcloud.com\"\r\n\r\nolares-cli settings integration accounts delete awss3 my-bucket\r\nolares-cli settings integration accounts delete tencent          # name-less, single-tenant\r\n```\r\n\r\nThe store key is composed as `integration-account:<type>:<name>` (or `integration-account:<type>` when no name is supplied), matching the SPA's `getStoreKey` in [`apps/packages/app/src/stores/settings/integration.ts`](apps/packages/app/src/stores/settings/integration.ts). **Do not paste secret-key values into the agent transcript — pipe them via env vars or shell redirection.**\r\n\r\n## Deferred to next iteration\r\n\r\nThe verbs below are **not shipped** in this release. They either need more design work or require JWS-signed bodies the CLI can't produce yet. Don't suggest them today; reach for the listed alternatives when an alternative exists.\r\n\r\n- **App lifecycle: install / uninstall / upgrade / start / stop / cancel / clone** — these route through the market service rather than user-service. Use `olares-cli market install|uninstall|upgrade|start|stop|cancel|clone` instead of `settings apps`. (Per-app `suspend [--all]` / `resume` + `env set` + per-entrance `domain set` / `finish` / `policy set` / `auth-level set` ship in the settings binary but are not yet smoke-verified — see [`UNVERIFIED_COMMANDS.md`](cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md).)\r\n- **Per-app secrets / permissions / providers** — Infisical-backed per-app secrets, declared permissions, and provider registries were not included in this release. If you need to inspect or write them, use the platform's admin / chart-side tooling instead.\r\n- **Network writes that require a JWS-signed device-id header** — hosts-file write, FRP server register / delete, SSL enable / disable / update (the SPA carries these with `X-Signature` headers the CLI doesn't yet produce).\r\n- **External-network master switch (read + write)** — BFL exposes `/api/external-network` and a Go implementation lives in [`cli/cmd/ctl/settings/network/external_network.go`](cli/cmd/ctl/settings/network/external_network.go), but neither the desktop SPA nor TermiPass has surfaced a UI for it yet, and the matching write still needs a JWS-signed device-id header. The verb is intentionally NOT registered on the command tree right now — shipping a read-only verb in isolation only confuses operators. Re-add `cmd.AddCommand(NewExternalNetworkCommand(f))` in [`cli/cmd/ctl/settings/network/root.go`](cli/cmd/ctl/settings/network/root.go) once the UI lands or the JWS key sourcing path is wired.\r\n- **Containerd registry mutations** — `registries mirrors put / delete`, `images delete / prune` (also `X-Signature`-gated).\r\n- **Hardware / restart-class** — reboot, shutdown, ssh-password, OS upgrade — these go through TermiPass-issued JWS over a QR callback URL; CLI support arrives once a JWS key sourcing path lands.\r\n- **Backup plan create / update** — full `BackupPolicy` + `LocationConfig` vector; needs either a `--from-file plan.json` mode or an upstream \"create from defaults\" shortcut before shipping.\r\n- **Restore plan update / non-cancel delete** — backup-server has no routes for these.\r\n\r\nEvery area's `--help` is the source of truth for what's currently implemented; if a verb isn't there, treat it as deferred.\r\n\r\nVerbs implemented in this CLI but **not yet smoke-verified on this release** are catalogued in [`cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md`](cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md). Treat them as experimental until they appear in a green smoke report; the file lists per-verb status (FAIL / SKIP-destructive / SKIP-fixture-missing) and links back to the phase report row.\r\n\r\n## Common errors → fixes\r\n\r\n| Error message | Cause | Fix |\r\n|---|---|---|\r\n| `refresh token for <id> became invalid at <ts>; please run: olares-cli profile login --olares-id <id>` | `/api/refresh` itself returned 401/403 — the grant is dead (typed `*credential.ErrTokenInvalidated`) | `olares-cli profile login --olares-id <id>`. Defer the full recovery flow to [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md). |\r\n| `no access token for <id>; run: olares-cli profile login --olares-id <id>` | Profile selected but keychain has no entry (typed `*credential.ErrNotLoggedIn`) | `olares-cli profile login` or `profile import`. |\r\n| `server rejected the access token (HTTP 401/403)` | Server still rejects after auto-refresh — rare, usually server-side state drift | Defer to [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) (login + profile rules). |\r\n| `this command needs role \"<R>\" or higher to <verb>, but profile \"<id>\" is cached as \"<r>\"` | Cached role below the verb's requirement (emitted by admin-floor verbs — see the floor table in \"Soft preflight\"). | If your role on the server changed, run `olares-cli profile whoami --refresh`. Otherwise ask the owner to grant you the right role. |\r\n| `HTTP 403 while attempting to <verb>` (with the same refresh hint appended) | Server rejected even though cache said OK — usually a stale **role** cache (NOT a stale token; the transport already handled that). Wrapped on every settings verb. | Run `olares-cli profile whoami --refresh`, then retry the verb. |\r\n| `unsupported --output \"<x>\" (allowed: table, json)` | Typo on `-o` | Use `-o table` or `-o json`. |\r\n| `GET <path>: upstream returned code <N>: <msg>` | The user-service / BFL / backup-server returned a non-success envelope | Read the message verbatim; it almost always carries actionable detail (e.g. \"user not found\"). |\r\n| `internal error: settings <area> not wired with cmdutil.Factory` | Unexpected — would only happen if the umbrella was wired without the factory | This is a CLI bug; gather the command line and file an issue. |\r\n\r\n## Typical workflows\r\n\r\nConfirm who the active profile is, then enumerate what the user can see:\r\n\r\n```bash\r\nolares-cli profile whoami                         # cached role\r\nolares-cli settings users list                    # only owners/admins see everyone\r\nolares-cli settings apps list                     # everyone sees their own apps\r\n```\r\n\r\nRefresh the cache after a role change on the server:\r\n\r\n```bash\r\nolares-cli profile whoami --refresh\r\nolares-cli settings advanced status               # retry the gated verb\r\n```\r\n\r\nHand a downstream tool the raw data:\r\n\r\n```bash\r\nolares-cli settings vpn devices list -o json | jq '.[] | {name, ip: .IPAddresses[0]}'\r\nolares-cli settings backup plans list -o json | jq '.backups[] | select(.status==\"failed\")'\r\n```\r\n\r\nInspect a single account's full payload (incl. `raw_data`):\r\n\r\n```bash\r\nolares-cli settings integration accounts get awss3 my-bucket -o json\r\n```\r\n\r\n## Security rules\r\n\r\n- **Never** echo `<access_token>` or any field returned by `me sso list` into the terminal beyond what the table view already shows. SSO tokens identify a TermiPass-bound device session and should never be logged or pasted into chat.\r\n- `settings users create` / `settings users delete` are destructive (`delete` needs the whole word `yes` unless **`--yes`**). **Both default to accepted-then-exit**; pass **`--watch`** to block until `Created` / `Deleted` (with `--watch-timeout` / `--watch-interval`, same as [`olares-cli market --watch`](../olares-market/SKILL.md#watch-flag)). **`delete` cannot remove the owner account** (fails before DELETE). `create` always generates the initial password once to stdout; treat transcripts accordingly.\r\n- `settings users get <username>` returns the same record the SPA shows on the user detail page; treat its email / olaresId as PII and avoid forwarding it outside the requesting workflow.\r\n- For writes that take secrets (`integration accounts add awss3|tencent` is the verified one in this surface), **always** read the secret from an env var or stdin pipe — never paste it into the chat or expand it inline in an `olares-cli ...` command line you suggest. Bash history retention is the user's responsibility; the agent should default to env-var / pipe style invocations (`--access-key-secret \"$AWS_SECRET_ACCESS_KEY\"`, `printf '%s\\n' \"$VAR\" | ... --password-stdin`) whenever the verb supports it.\r\n- Other secret-bearing verbs (e.g. `backup password set`, `restore plans check-url / create-from-url`) live in [`UNVERIFIED_COMMANDS.md`](cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md) until they're smoke-greened; the same env-var / stdin-pipe rule applies whenever you exercise them by hand.\r\n- Read-only verbs do **not** carry \"this will change X\" prompts — only mutating verbs do, and the prompts they do carry come from the upstream server's own response messages. Don't fabricate one for read verbs.\r\n- The `me whoami --refresh` recovery path is the only authentication-adjacent action this skill should ever recommend. **All** other auth recovery (login expiry, profile import, 2FA) belongs in [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md).\r\n\r\n## See also\r\n\r\n- [`olares-shared`](../olares-shared/SKILL.md) — profile model, login, automatic token refresh, full auth-error recovery table. **Read this one first.**\r\n- [`olares-files`](../olares-files/SKILL.md) — drive / sync / cache file browser, upload / download / share / chown.\r\n- [`olares-market`](../olares-market/SKILL.md) — Olares app lifecycle (install / uninstall / upgrade / start / stop / cancel / clone).\r\n- [`olares-dashboard`](../olares-dashboard/SKILL.md) — Olares Dashboard SPA proxy (overview, applications, GPU, fan, ranking).\r\n- [`olares-cluster`](../olares-cluster/SKILL.md) — per-user Kubernetes view (pods / workloads / namespaces / jobs / cronjobs / nodes / middleware).\n\nFile v1.2.0:_meta.json\n\n{\n  \"ownerId\": \"kn7153k9wp5dwxsm6getv104r985vrf5\",\n  \"slug\": \"olares-settings\",\n  \"version\": \"1.2.0\",\n  \"publishedAt\": 1779960490830\n}\n\nFile v1.2.0:skill-card.md\n\n## Description: <br>\nHelps an agent read and mutate Olares Settings surfaces through olares-cli settings, including users, apps, VPN, integration accounts, search, backup, restore, advanced settings, and self-service profile checks. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[pengpeng](https://clawhub.ai/user/pengpeng) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and operators use this skill when they need an agent to inspect Olares Settings, choose appropriate olares-cli settings commands, and handle settings changes involving users, VPN, integrations, search, backup, restore, and profile identity. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can guide an agent through sensitive Olares Settings operations, including user create/delete, VPN ACL or SSH changes, search rebuilds, and integration account commands that handle cloud credentials. <br>\nMitigation: Review mutating commands before execution, prefer read-only inspection first, and pass secrets through environment variables or stdin rather than chat text. <br>\nRisk: Some commands expose profile, SSO, user, or integration-account data that may include credentials or personal information. <br>\nMitigation: Limit transcript sharing of command output, avoid echoing access tokens or SSO token fields, and use JSON output only when a downstream tool needs structured data. <br>\n\n\n## Reference(s): <br>\n- [Olares Settings documentation](https://docs.olares.com/manual/olares/settings/) <br>\n- [ClawHub release page](https://clawhub.ai/pengpeng/olares-settings) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [guidance, markdown, shell commands, configuration] <br>\n**Output Format:** [Markdown with inline shell commands and optional JSON-output recommendations] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Requires olares-cli and an authenticated Olares profile; read commands may return table or JSON output depending on the selected CLI flag.] <br>\n\n## Skill Version(s): <br>\n1.2.0 (source: SKILL.md frontmatter and server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.1.0: 2 files, 11857 bytes\n\nFiles: SKILL.md (31745b), _meta.json (134b)\n\nFile v1.1.0:SKILL.md\n\n---\r\nname: olares-settings\r\nversion: 1.1.0\r\ndescription: \"olares-cli settings command tree: profile-based reads of every section the SPA's Settings page exposes (https://docs.olares.com/manual/olares/settings/) plus a small set of mutating verbs that have been smoke-verified on this release. Read-only surface: users / appearance / apps (list/get/entrances list/env get/domain get/policy get) / integration / vpn (devices list / devices routes / acl all / acl get / ssh status / subroutes status / public-domain-policy get) / network (reverse-proxy get / frp list / external-network get / hosts-file get) / gpu / video / search (status / excludes list / dirs list) / backup (plans list / snapshots list) / restore (plans list) / advanced (status / registries list / images list / env system list / env user list) + a non-canonical `me` self-service tree (whoami / version / check-update / sso list). Verified mutating surface: appearance language set (with --force escape hatch); search rebuild; integration accounts add awss3|tencent + accounts delete; vpn ssh enable/disable; vpn acl add/remove. Covers role caching (owner / admin / normal) on the active profile, the wired soft-preflight helpers, the `-o table | json` output convention, and the upstream wire formats the CLI normalizes (BFL envelope on /api/*, app-service ListResult on /api/users-v2 + /api/myapps with `[]servicePort` ports, raw Headscale JSON on /headscale/* with string `route.id`, BFL envelope on /apis/backup/v1/*, terminusd-proxied envelopes for advanced status / containerd registries / images). Verbs that ship in the binary but did NOT pass (or were not exercised by) the latest smoke run are catalogued in cli/cmd/ctl/settings/scripts/UNVERIFIED_COMMANDS.md — treat them as experimental until they appear in a green smoke report. Use whenever the user mentions Olares Settings, Settings UI, the SPA Settings page, role / owner / admin / normal, integration accounts, SSO tokens, GPU mode, search index, backup plans, restore plans, containerd registries, VPN ACLs, language preference, or wants to know what `olares-cli settings me whoami` / `settings users me` / `profile whoami` actually print.\"\r\nmetadata:\r\n  requires:\r\n    bins: [\"olares-cli\"]\r\n  cliHelp: \"olares-cli settings --help\"\r\n---\r\n\r\n# settings (Olares Settings UI mirror)\r\n\r\n**CRITICAL — before doing anything, MUST use the Read tool to read [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) for the profile selection, login, and HTTP 401/403 recovery rules that every command here depends on.**\r\n\r\n## What this command tree is\r\n\r\n`olares-cli settings ...` is the CLI mirror of the Olares desktop SPA's Settings page (the same surface documented at <https://docs.olares.com/manual/olares/settings/>). Identity and transport come from the active profile — same profile model, same access token, same edge-auth chain (Authelia + l4-bfl-proxy) the SPA uses.\r\n\r\nThe umbrella registers **13 area sub-trees** (see [`cli/cmd/ctl/settings/root.go`](cli/cmd/ctl/settings/root.go)):\r\n\r\n```\r\nusers         appearance   apps          integration   vpn         network\r\ngpu           video        search        backup        restore     advanced\r\n```\r\n\r\n…plus a 13th non-canonical tree, `me`, that hosts the SPA's avatar / Person dropdown self-service items. **`me` is intentionally outside the 12 canonical Settings docs sections**; it lives under `settings` for CLI discoverability, not because it's a docs section.\r\n\r\n> The shape is always `olares-cli settings <area> <verb>` (or `<area> <noun> <verb>` when the area has multiple sub-resources, e.g. `settings vpn devices list`, `settings backup plans list`). Every verb honours the global `--profile` flag inherited from the umbrella.\r\n\r\n## Authentication transport\r\n\r\nEvery request goes through the factory-injected `*http.Client` and the resolved profile from `cmdutil.Factory`. There is no kubeconfig dependency.\r\n\r\n- Base URL: **per-area split** between `rp.DesktopURL` (default) and `rp.SettingsURL`. The two SPAs serve from different per-user origins — desktop launcher SPA at `https://desktop.<terminus>` (nginx: [`apps/docker/system-frontend/nginx/desktop.conf`](apps/docker/system-frontend/nginx/desktop.conf)), Settings SPA at `https://settings.<terminus>` (nginx: [`apps/docker/system-frontend/nginx/settings.conf`](apps/docker/system-frontend/nginx/settings.conf), the origin Settings SPA itself uses via `tokenStore.setUrl(window.location.origin)` in [`settings/src/application/settings.ts`](settings/src/application/settings.ts)). The two nginx configs share `/api/*` (both forward to user-service:3010) but diverge elsewhere:\r\n  - **`rp.SettingsURL`** is required for areas that hit settings-only locations: `vpn` (`/headscale/*`), `backup` / `restore` (`/apis/backup/v1/*`). Settings nginx also exclusively exposes `/admin/*` (Infisical), `/drive`, `/vault`, `/images`, `/api/cloud/sign`.\r\n  - **`rp.DesktopURL`** is the default for every other area. Desktop nginx has dedicated reverse proxies that settings nginx does NOT: `/api/device → settings-service`, `/api/logout → authelia-svc`, `/api/refresh → authelia-backend-svc`. The `me` area's SSO list (`/api/device/sso`) and any future code reading `/api/device/*` is therefore wired through DesktopURL on purpose — moving it would silently swap backends. Same goes for the three `whoami` aliases (`profile whoami`, `settings users me`, `settings me whoami`), which read cached identity served from desktop ingress.\r\n  Refer to `olares.ID.DesktopURL` / `olares.ID.SettingsURL` doc comments for the canonical location-set tables.\r\n- Auth header: `X-Authorization: <access_token>` (NOT `Authorization: Bearer …`). Injected by the factory's `refreshingTransport` (see [`cli/pkg/cmdutil/factory.go`](cli/pkg/cmdutil/factory.go)); the settings area `prepare()` helpers never call `req.Header.Set(\"X-Authorization\", …)` themselves.\r\n- **Expired access_tokens are auto-rotated.** When the server returns 401/403, the transport hits `/api/refresh`, persists the new token, and retries the original request once — transparently to the caller. Users do NOT need to run `profile login` just because their access_token aged out; only when the *refresh_token* itself is invalidated. Full mechanics — concurrency, cross-process flock, typed `*credential.ErrTokenInvalidated` / `*credential.ErrNotLoggedIn` errors — are documented in [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) under \"Automatic token refresh\". **Do not write retry loops on top of these typed errors** — once you see one, only `profile login` / `profile import` will help.\r\n- Two ingress prefixes show up in this subtree:\r\n  - `/api/*` (the bulk of the surface) — terminates at user-service, which proxies BFL / app-service / Headscale / terminusd / search3 / HAMI etc.\r\n  - `/apis/backup/v1/*` (`settings backup`, `settings restore`) — terminates at BFL's backup-server directly.\r\n- 401 / 403 that survive auto-refresh (i.e. the server still says no after the new token wa","readmeExcerpt":"Skill: Olares Settings (olares-cli settings) Owner: olares Summary: Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirr... Tags: latest:4.0.1 Version history: v4.0.1 | 2026-05-29T05:54:47.556Z | user Migrate ownership from @pengpeng to @olares (no content change vs 4.0.0) v4.0.0 | 2026-05-29T04:53:52.530Z | user ","codeSnippets":[],"executableExamples":[],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: olares-settings\r\nversion: 4.0.1\r\ndescription: \"Olares Settings (olares-cli settings) — read and mutate Olares Settings UI surfaces from the command line, scoped to the active Olares ID. Per-Olares-ID mirror of every section the Olares Settings SPA exposes (https://docs.olares.com/manual/olares/settings/). Read-only coverage: users, appearance, apps (list, get, entrances, env, domain, policy), integration accounts, VPN (devices, ACL, SSH, subroutes, public-domain policy), network (reverse proxy, frp, hosts file), GPU, video, search status + dirs, backup plans + snapshots, restore plans, advanced (containerd registries, images, env system / user), plus a `me` self-service tree (whoami on Olares, version, check-update, SSO list). Verified mutating verbs: appearance language set, search rebuild, integration accounts add awss3|tencent / delete, VPN SSH enable/disable, VPN ACL add/remove, users create/delete (new Olares ID). Use when the user mentions Olares, Olares ID, Olares Settings, olares-cli settings, the Olares Settings UI, role (owner / admin / normal) on Olares, integration accounts, SSO tokens, GPU mode, search index, backup / restore plans, containerd registries, VPN ACLs, language preference, or 'who am I on this Olares instance'.\"\r\nmetadata:\r\n  requires:\r\n    bins: [\"olares-cli\"]\r\n  cliHelp: \"olares-cli settings --help\"\r\n---\r\n\r\n# settings (Olares Settings UI mirror)\r\n\r\n**CRITICAL — before doing anything, MUST use the Read tool to read [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) for profile selection, login, automatic token refresh, and the auth-error recovery table.**\r\n\r\n> **Source of truth for flags is always `olares-cli settings <area> <verb> --help`.** This file only carries what `--help` cannot give: routing, the 13-section index, the role-caching / admin-vs-normal floor, the wire-format cheat sheet, and the common-errors table.\r\n\r\n## Routing\r\n\r\n| User intent | Use this skill? |\r\n|---|---|\r\n| \"Change language / theme / appearance\" | ✅ yes |\r\n| \"Add a user / delete a user\" | ✅ yes |\r\n| \"Edit my app's entrance / domain / policy / env\" | ✅ yes (post-install surface) |\r\n| \"Add an S3 / Tencent integration account\" | ✅ yes |\r\n| \"Manage VPN devices / ACL / SSH toggle\" | ✅ yes |\r\n| \"Browse backup plans / snapshots / restore plans\" | ✅ yes |\r\n| \"Install / uninstall / upgrade / start / stop an Olares app\" | ❌ use [`olares-market`](../olares-market/SKILL.md) (this is post-install) |\r\n| \"Identify / log in / switch profile\" | ❌ use [`../olares-shared/SKILL.md`](../olares-shared/SKILL.md) (`profile login`) |\r\n| \"Inspect pods / workloads / nodes\" | ❌ use [`olares-cluster`](../olares-cluster/SKILL.md) |\r\n| \"Show CPU / memory / disk metrics\" | ❌ use [`olares-dashboard`](../olares-dashboard/SKILL.md) |\r\n\r\n> **Mental model:** `settings` covers configuration that the Olares Settings SPA exposes — **post-install per-app config**, mesh / VPN, backup, accounts, system appearance. Lifecycle and runtime live in sibling skills.\r\n\r\n## 13 "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7153k9wp5dwxsm6getv104r985vrf5\",\n  \"slug\": \"olares-settings\",\n  \"version\": \"4.0.1\",\n  \"publishedAt\": 1780034087556\n}"},{"path":"references/olares-settings-apps.md","content":"# settings apps (post-install configuration)\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings apps --help` and `olares-cli settings apps <verb> --help`.\r\n\r\nThe **post-install** surface for an Olares app. Inspect the app, list its entrances, edit per-entrance domain / policy / auth-level / env vars, suspend / resume.\r\n\r\n> **NOT for install / uninstall / upgrade / clone / start / stop** — use [`olares-market`](../../olares-market/SKILL.md) for app lifecycle. `settings apps` is for tweaking an app that's already installed.\r\n\r\n## Verbs at a glance\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `list [--all] [--show-system]` | normal | VERIFIED | Installed apps for the current user. Default filter mirrors the SPA |\r\n| `get <app>` | normal | VERIFIED | Detail view (filtered client-side; no per-app endpoint) |\r\n| `entrances list <app>` | normal | VERIFIED | **Live** entrance vector — names, state, auth-level |\r\n| `env get <app>` | normal | VERIFIED | Current per-app env vector |\r\n| `env set <app> KEY=VALUE [KEY=VALUE...]` | normal | UNVERIFIED | Replace the env vector |\r\n| `domain get <app> <entrance>` | normal | VERIFIED | Per-entrance custom-domain setup |\r\n| `domain list <app>` | normal | VERIFIED | Every entrance's domain setup |\r\n| `domain set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `domain finish <app> <entrance>` | normal | UNVERIFIED | Confirm third-party CNAME after DNS propagates |\r\n| `policy get <app> <entrance>` | normal | VERIFIED | Per-entrance auth policy |\r\n| `policy list <app>` | normal | VERIFIED | Every entrance's policy |\r\n| `policy set <app> <entrance> [flags]` | normal | UNVERIFIED | RMW update |\r\n| `auth-level set <app> <entrance> --level X` | normal | UNVERIFIED | `private` / `public` / `internal` |\r\n| `suspend <app> [--all]` | normal | UNVERIFIED | Suspend running app |\r\n| `resume <app>` | normal | UNVERIFIED | Resume suspended app |\r\n\r\n## The per-entrance editing pipeline\r\n\r\nMost per-entrance edits follow a 4-step pattern:\r\n\r\n```bash\r\n# 1. Discover entrances on the app.\r\nolares-cli settings apps entrances list firefox\r\n# → produces ENTRANCE / STATE / AUTH LEVEL / DOMAIN columns\r\n\r\n# 2. Inspect current setup of the entrance you want to edit.\r\nolares-cli settings apps domain get firefox www\r\nolares-cli settings apps policy get firefox www\r\n\r\n# 3. RMW update (unspecified flags survive).\r\nolares-cli settings apps domain set firefox www --third-level my-firefox\r\nolares-cli settings apps policy set firefox www --default-policy two_factor\r\n\r\n# 4. For third-party domains: confirm CNAME after DNS propagation.\r\nolares-cli settings apps domain set firefox www --third-party firefox.example.com \\\r\n  --cert-file /path/to/cert.pem --key-file /path/to/key.pem\r\nolares-cli settings apps domain finish firefox www\r\n```\r\n\r\n## `domain set` — RMW semantics + cert/key handlin"},{"path":"references/olares-settings-backup.md","content":"# settings backup\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings backup --help` and `olares-cli settings backup <noun> <verb> --help`.\r\n\r\nManage backup plans (BFL backup-server) and the repository encryption password.\r\n\r\n> **Different ingress prefix** — `<SettingsURL>/apis/backup/v1/*` rather than `/api/*`. The CLI handles this transparently, but errors carrying the path will mention `/apis/backup/v1/...`.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Status | Purpose |\r\n|---|---|---|---|\r\n| `plans list` | normal | VERIFIED | List backup plans (with pagination) |\r\n| `snapshots list <backup-id>` | normal | VERIFIED | List snapshots for one plan |\r\n| `password set <name>` | normal | UNVERIFIED | Set / rotate the repository encryption password |\r\n\r\n## `plans list`\r\n\r\n```bash\r\nolares-cli settings backup plans list                     # default 50\r\nolares-cli settings backup plans list --limit 100\r\nolares-cli settings backup plans list --offset 50 --limit 50\r\nolares-cli settings backup plans list -o json\r\n```\r\n\r\nReturns each plan with name, ID, schedule, target (cloud / local / S3 / ...), status. Fields not surfaced in the table view are available via `-o json` (the SPA's axios interceptor unwraps `data.data`, which is why upstream code reads `{backups: [...]}` directly).\r\n\r\n`--offset` / `--limit` mirror the SPA's pagination behavior. Default `--limit` is 50.\r\n\r\n## `snapshots list <backup-id>`\r\n\r\n```bash\r\nolares-cli settings backup snapshots list <backup-id> --limit 50\r\nolares-cli settings backup snapshots list <backup-id> -o json\r\n```\r\n\r\nRequires the **backup ID** (from `plans list`, NOT the plan name). Returns the snapshot timeline for that plan: snapshot ID, taken-at timestamp, size, status, restic / kopia snapshot identifier.\r\n\r\n## `password set <name>` (UNVERIFIED)\r\n\r\n```bash\r\n# Interactive TTY prompt (default; no echo).\r\nolares-cli settings backup password set my-plan\r\n\r\n# Stdin pipe (scripted).\r\necho -n \"my-secret-password\" | olares-cli settings backup password set my-plan --password-stdin\r\n```\r\n\r\n- Sets / rotates the encryption password for one backup plan's repository.\r\n- **Default reads from a TTY without echo.** `--password-stdin` reads once from stdin (newline-terminated; trim newline if your producer adds one).\r\n- **Losing the password means losing the ability to decrypt existing snapshots.** The upstream cannot recover this password — make sure the user has it stored somewhere safe (password manager) BEFORE the call.\r\n\r\n## Plan create / update — out of scope (today)\r\n\r\n`plans create` and `plans update` are **not implemented yet**. They need either:\r\n\r\n- A `--from-file plan.json` mode (still pending design — the full `BackupPolicy` + `LocationConfig` vector is large), or\r\n- An upstream \"create from defaults\" shortcut that doesn't yet exist.\r\n\r\nUntil then, **create / update backup plans via the SPA** (Settings →"},{"path":"references/olares-settings-integration.md","content":"# settings integration\r\n\r\n> **Prerequisite:** Read [`../../olares-shared/SKILL.md`](../../olares-shared/SKILL.md) and the parent [`../SKILL.md`](../SKILL.md) first.\r\n> **Flags & examples:** `olares-cli settings integration accounts --help` and `olares-cli settings integration accounts <verb> --help`.\r\n\r\nExternal integration accounts (S3 / Tencent COS / Google Drive / Dropbox / Olares Space / NFT cloud binding).\r\n\r\n## What's covered by the CLI\r\n\r\n| Account type | CLI verb | Why |\r\n|---|---|---|\r\n| AWS S3 (or S3-compatible endpoint) | `accounts add awss3` | Direct credentials — no OAuth |\r\n| Tencent COS | `accounts add tencent` | Direct credentials — no OAuth |\r\n| Google Drive | (SPA only) | OAuth-bound browser session |\r\n| Dropbox | (SPA only) | OAuth-bound browser session |\r\n| Olares Space / NFT cloud binding | (SPA only) | Browser- and wallet-bound by design |\r\n\r\n> **OAuth and wallet flows stay in the SPA.** The access tokens they produce are scoped to a browser session and have no useful one-shot CLI capture. If the user asks to add Google Drive / Dropbox / Olares Space / NFT integrations via CLI, direct them to the Settings → Integration page in the SPA.\r\n\r\n## Sub-tree\r\n\r\n| Verb | Floor | Notes |\r\n|---|---|---|\r\n| `accounts list` | normal | `accountMini` shape (no `raw_data`) |\r\n| `accounts list-by-type <type>` | normal | Filter by account type |\r\n| `accounts get <type> [name]` | normal | `accountFull` shape (includes `raw_data`); `name` optional for single-tenant types |\r\n| `accounts add awss3 [flags]` | normal | AWS S3 / S3-compatible |\r\n| `accounts add tencent [flags]` | normal | Tencent COS |\r\n| `accounts delete <type> [name]` | normal | `name` optional for single-tenant types |\r\n\r\n## `accounts add awss3`\r\n\r\n```bash\r\nolares-cli settings integration accounts add awss3 \\\r\n  --access-key-id     \"$AWS_ACCESS_KEY_ID\" \\\r\n  --access-key-secret \"$AWS_SECRET_ACCESS_KEY\" \\\r\n  --endpoint          \"https://s3.amazonaws.com\" \\\r\n  --bucket            \"my-bucket\"\r\n```\r\n\r\n- `--bucket` is **optional** — omit for \"any bucket the credentials can reach\"; provide for \"scope to this bucket\".\r\n- `--endpoint` accepts any S3-compatible endpoint (MinIO, Backblaze B2 via S3 API, etc.) — not just AWS.\r\n\r\n## `accounts add tencent`\r\n\r\n```bash\r\nolares-cli settings integration accounts add tencent \\\r\n  --access-key-id     \"$TENCENT_SECRET_ID\" \\\r\n  --access-key-secret \"$TENCENT_SECRET_KEY\" \\\r\n  --endpoint          \"https://cos.ap-shanghai.myqcloud.com\"\r\n```\r\n\r\n- Region is encoded in the endpoint URL — e.g. `cos.ap-beijing.myqcloud.com`, `cos.ap-shanghai.myqcloud.com`.\r\n- Tencent COS is **single-tenant**: no `--bucket` flag, no `<name>` argument on add. There is at most one Tencent account per profile.\r\n\r\n## `accounts get` / `accounts delete` — name handling\r\n\r\n```bash\r\n# Multi-tenant types (S3, Drive, Dropbox) — need a name.\r\nolares-cli settings integration accounts get awss3 my-bucket\r\nolares-cli settings integration accounts delete awss3 my-bucket\r\n\r\n# Single-tenant typ"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1760,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T23:08:15.435Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-14T14:07:29.399Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}