{
  "schema_version": 1,
  "type": "skill",
  "slug": "carbon-preferences",
  "title": "Carbon Preferences API",
  "brief": "Read and write per-user key-value settings via the Carbon API. Store theme, feature flags, timestamps, and tool config that persists across sessions and carries between adom-desktop, Hydrogen Desktop,",
  "version": "1.0.0",
  "tags": [],
  "license": "MIT",
  "sample_prompts": [
    {
      "label": "Read my settings",
      "prompt": "adom-cli carbon user get | jq '.hydrogen_preferences.settings'"
    },
    {
      "label": "Set a preference",
      "prompt": "adom-cli carbon user hydrogen-settings '{\"key\":\"desktop.enabled\",\"value\":true}'"
    },
    {
      "label": "Delete a key",
      "prompt": "adom-cli carbon user hydrogen-settings '{\"key\":\"desktop.enabled\",\"value\":null}'"
    }
  ],
  "source_path": "SKILL.md",
  "readme": "# Carbon Preferences API\n\nStore and retrieve per-user key-value pairs via the Carbon `hydrogen_preferences` object.\nAdrian built this for Hydrogen's theme/UI settings, but it works for any lightweight per-user config (adom-desktop flags, feature toggles, timestamps, etc.).\n\n## Hard limit\n\n**10 MB total per user.** Keep individual values small. Don't dump logs, blobs, or large JSON objects into preferences.\n\n## Data model\n\n`GET /user` returns the authenticated user. The `hydrogen_preferences` field contains three sections:\n\n```typescript\nhydrogen_preferences: {\n  settings:    Record<string, string | number | boolean>\n  keybindings: Record<string, string>\n  extensions:  Record<string, { version: string, enabled: boolean }>\n}\n```\n\n## Reading preferences\n\nRead via `GET /user` and extract the `hydrogen_preferences` field.\n\n### CLI\n```bash\n# Full user profile (hydrogen_preferences is a top-level field)\nadom-cli carbon user get\n\n# Extract just settings with jq\nadom-cli carbon user get | jq '.hydrogen_preferences.settings'\n\n# Get a single setting\nadom-cli carbon user get | jq -r '.hydrogen_preferences.settings[\"general.appearance.theme\"]'\n```\n\n### curl (from container)\n```bash\nAPI_KEY=$(cat /var/run/adom/api-key)\ncurl -s -H \"Cookie: session_token=$API_KEY\" https://carbon.adom.inc/user \\\n  | jq '.hydrogen_preferences'\n```\n\n### JavaScript (Hydrogen web)\n```javascript\nconst user = await get(`${API_BASE_URL}/user`);\nconst theme = user.hydrogen_preferences.settings['general.appearance.theme'];\n```\n\n### Tauri (Hydrogen Desktop)\n```javascript\nconst { invoke } = await import('@tauri-apps/api/core');\nconst result = await invoke('auth_proxy', { path: '/user', method: 'GET' });\nconst settings = result.data.hydrogen_preferences.settings;\n```\n\n## Writing settings\n\n### Endpoint\n```\nPATCH /user/hydrogen/settings\nContent-Type: application/json\n```\n\n### Request body\n```json\n{ \"key\": \"dotted.key.name\", \"value\": \"<string | number | boolean | null>\" }\n```\n\n- **key** -- dotted lowercase string matching `^(?:[a-z0-9_]+)(?:\\.[a-z0-9_]+)*$`\n- **value** -- `string`, `number` (f64), `boolean`, or `null` to delete\n\nOne key per request. Returns `{ \"status\": 200 }` on success.\n\n### CLI\n```bash\n# Set a boolean\nadom-cli carbon user hydrogen-settings '{\"key\":\"desktop.enabled\",\"value\":true}'\n\n# Set a string\nadom-cli carbon user hydrogen-settings '{\"key\":\"desktop.last_slug\",\"value\":\"john-myproject-abc123\"}'\n\n# Set a number\nadom-cli carbon user hydrogen-settings '{\"key\":\"desktop.last_connect_epoch\",\"value\":1747612800}'\n\n# Delete a key (set value to null)\nadom-cli carbon user hydrogen-settings '{\"key\":\"desktop.enabled\",\"value\":null}'\n```\n\n### curl (from container)\n```bash\nAPI_KEY=$(cat /var/run/adom/api-key)\ncurl -s -X PATCH https://carbon.adom.inc/user/hydrogen/settings \\\n  -H \"Cookie: session_token=$API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"key\":\"desktop.enabled\",\"value\":true}'\n```\n\n### JavaScript (Hydrogen web)\n```javascript\nawait patch(`${API_BASE_URL}/user/hydrogen/settings`, {\n  key: 'general.appearance.theme',\n  value: 'adom-light'\n});\n```\n\n### Tauri (Hydrogen Desktop)\n```javascript\nawait invoke('auth_proxy', {\n  path: '/user/hydrogen/settings',\n  method: 'PATCH',\n  body: { key: 'desktop.enabled', value: true }\n});\n```\n\n## Writing keybindings\n\n### Endpoint\n```\nPATCH /user/hydrogen/keybindings\nContent-Type: application/json\n```\n\n### CLI\n```bash\nadom-cli carbon user hydrogen-keybindings '{\"key\":\"editor.save\",\"value\":\"Ctrl+S\"}'\n```\n\n## Key naming conventions\n\nUse dotted namespaces to avoid collisions. Third-party tools (adom-desktop, CLI tools, etc.) MUST use their own namespace prefix so they never clobber keys the Hydrogen frontend uses.\n\n| Namespace | Owner | Examples |\n|-----------|-------|---------|\n| `general.*` | Hydrogen frontend | `general.appearance.theme`, `general.developer_mode` |\n| `schematic.*` | Hydrogen schematic editor | `schematic.nudge_amount.small` |\n| `3d.*` | Hydrogen 3D viewer | `3d.control_style` |\n| `code.*` | Hydrogen code editor | `code.vim_emulation_mode` |\n| `simulator.*` | Hydrogen simulator | `simulator.code_editor_position` |\n| `desktop.*` | adom-desktop / HD | `desktop.enabled`, `desktop.last_connect_epoch`, `desktop.last_slug` |\n\n**Rule:** Never write to `general.*`, `schematic.*`, `3d.*`, `code.*`, `simulator.*`, or `extensions.*` -- those belong to the Hydrogen frontend. Pick a unique prefix for your tool (e.g., `desktop.*`, `chipfit.*`, `tsci.*`).\n\n## Known Hydrogen settings (defined in settings tree)\n\nThese have schema definitions with types, defaults, and validation:\n\n| Key | Type | Default | Description |\n|-----|------|---------|-------------|\n| `general.developer_mode` | boolean | false | Developer mode |\n| `general.pane_focus_mode` | boolean | true | Only focused pane is active |\n| `general.appearance.theme` | string | adom-dark | Theme |\n| `general.appearance.user_interface_style` | string | standard | UI density (standard, compact) |\n| `schematic.nudge_amount.small` | number | 1 | Arrow key nudge (px) |\n| `schematic.nudge_amount.large` | number | 8 | Shift+arrow nudge (px) |\n| `schematic.invert_zoom_direction` | boolean | false | Invert scroll zoom |\n| `schematic.default_cursor` | string | crosshair | Default cursor |\n| `3d.control_style` | string | fusion | 3D controls (fusion, solidworks, blender) |\n| `3d.invert_zoom_direction` | boolean | false | Invert 3D scroll zoom |\n| `code.appearance.font.family` | string | DM Mono | Code font |\n| `code.line_numbers.enabled` | boolean | true | Show line numbers |\n| `code.line_numbers.style` | string | absolute | Line number style |\n| `code.vim_emulation_mode` | boolean | false | Vim mode |\n| `simulator.code_editor_position` | string | right | Code panel position |\n\nCustom keys (like `desktop.*`) are not in this schema -- they are stored and returned as-is with no server-side validation.\n\n## Behavior notes\n\n- Setting a value to `null` deletes the key entirely (not stored as null)\n- Setting a value equal to the schema default in the Hydrogen frontend also deletes it (clean storage)\n- Keys not in the schema are accepted and stored -- no server-side key validation\n- One key per PATCH request; batch by issuing multiple requests\n- Auth: same as all Carbon endpoints -- session token cookie or X-Api-Key header\n- The full preferences object is returned inline with every `GET /user` call, so there's no separate GET endpoint for just preferences\n",
  "author": {
    "id": "695820315b5f1e4db2fcf602",
    "name": "Kyle Bergstedt",
    "email": "[email protected]"
  },
  "visibility": {
    "public": true
  },
  "hero": null,
  "discovery_triggers": [],
  "discovery_pitch": null,
  "metadata": {},
  "created_at": "2026-05-28T05:29:28.603Z",
  "updated_at": "2026-05-28T05:29:28.603Z",
  "sub_skills": [],
  "parent_app": null
}