{"openapi":"3.1.0","info":{"title":"Hermes Agent","version":"0.19.0"},"paths":{"/api/memory/providers/{provider}/oauth/start":{"post":{"summary":"Start Memory Oauth","description":"Begin a provider's zero-CLI OAuth flow — opens the browser and captures\nthe grant via the loopback listener. Returns immediately; poll status.","operationId":"start_memory_oauth_api_memory_providers__provider__oauth_start_post","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/memory/providers/{provider}/oauth/status":{"get":{"summary":"Memory Oauth Status","description":"Poll a provider's OAuth flow: idle | pending | connected | error.","operationId":"memory_oauth_status_api_memory_providers__provider__oauth_status_get","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/media":{"get":{"summary":"Get Media","description":"Return a gateway-local image file as a base64 data URL.\n\nLets remote clients (the desktop app over the network, or the web dashboard\nin a browser) display images the agent wrote to *this* machine's filesystem\n— they can't read the gateway's local disk directly.\n\nAuth-gated by the session token like every other /api route. Restricted to\nan image-extension allowlist, a size cap, AND the gateway's own media roots\n(resolved, symlink-safe) so it can't be used to read arbitrary files.","operationId":"get_media_api_media_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chat/image-upload":{"post":{"summary":"Upload Chat Image","description":"Persist a browser-provided chat image where the embedded TUI can read it.\n\nThe dashboard /chat page runs Hermes inside an xterm.js PTY. Browser\nclipboard image bytes are not visible to the server-side clipboard, so the\npage uploads them here, then drives the TUI's ``/image <path>`` command\nwith the returned gateway-visible path. Files land under\n``HERMES_HOME/images/`` — the same directory ``clipboard.paste`` /\n``image.attach`` already use.","operationId":"upload_chat_image_api_chat_image_upload_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatImageUpload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files":{"get":{"summary":"List Managed Files","operationId":"list_managed_files_api_files_get","parameters":[{"name":"path","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Managed File","operationId":"delete_managed_file_api_files_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedFileDelete"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files/read":{"get":{"summary":"Read Managed File","operationId":"read_managed_file_api_files_read_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files/download":{"get":{"summary":"Download Managed File","description":"Stream a managed file as an attachment download.\n\nRemote clients (desktop app, browser dashboard) open agent-written files\nthat live on *this* gateway's disk, not theirs. Auth-gated like every other\nmanaged-files route — ``auth_middleware`` additionally accepts the session\ntoken as a ``?token=`` query param here so a shell/browser-opened download\n(which can't set the session header) still authenticates. See ``/api/pty``\nfor the same query-token precedent.","operationId":"download_managed_file_api_files_download_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files/upload":{"post":{"summary":"Upload Managed File","operationId":"upload_managed_file_api_files_upload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedFileUpload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files/upload-stream":{"post":{"summary":"Upload Managed File Stream","operationId":"upload_managed_file_stream_api_files_upload_stream_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_managed_file_stream_api_files_upload_stream_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/files/mkdir":{"post":{"summary":"Create Managed Directory","operationId":"create_managed_directory_api_files_mkdir_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDirectoryCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/list":{"get":{"summary":"Fs List","operationId":"fs_list_api_fs_list_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/read-text":{"get":{"summary":"Fs Read Text","operationId":"fs_read_text_api_fs_read_text_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/write-text":{"post":{"summary":"Fs Write Text","description":"Overwrite (or create) a UTF-8 text file for the in-app spot editor.\n\nMirrors the local Electron ``hermes:fs:writeText`` hardening: the path is\nresolved + validated by ``_fs_path``, the parent directory must already\nexist (we never build directory trees), only regular files may be replaced,\nand the payload is size-capped. The write is staged to a sibling temp file\nand ``os.replace``-d into place so a crash mid-write can't truncate the\noriginal. Stale-on-disk detection is the client's job (re-read before save),\nso both transports behave identically.","operationId":"fs_write_text_api_fs_write_text_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FsWriteText"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/read-data-url":{"get":{"summary":"Fs Read Data Url","operationId":"fs_read_data_url_api_fs_read_data_url_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/git-root":{"get":{"summary":"Fs Git Root","operationId":"fs_git_root_api_fs_git_root_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/fs/default-cwd":{"get":{"summary":"Fs Default Cwd","operationId":"fs_default_cwd_api_fs_default_cwd_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/git/status":{"get":{"summary":"Git Status Route","operationId":"git_status_route_api_git_status_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/worktrees":{"get":{"summary":"Git Worktrees Route","operationId":"git_worktrees_route_api_git_worktrees_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/branches":{"get":{"summary":"Git Branches Route","operationId":"git_branches_route_api_git_branches_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/base-branches":{"get":{"summary":"Git Base Branches Route","operationId":"git_base_branches_route_api_git_base_branches_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/list":{"get":{"summary":"Git Review List Route","operationId":"git_review_list_route_api_git_review_list_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"uncommitted","title":"Scope"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/diff":{"get":{"summary":"Git Review Diff Route","operationId":"git_review_diff_route_api_git_review_diff_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}},{"name":"file","in":"query","required":true,"schema":{"type":"string","title":"File"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"uncommitted","title":"Scope"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"staged","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Staged"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/file-diff":{"get":{"summary":"Git File Diff Route","operationId":"git_file_diff_route_api_git_file_diff_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}},{"name":"file","in":"query","required":true,"schema":{"type":"string","title":"File"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/commit-context":{"get":{"summary":"Git Commit Context Route","operationId":"git_commit_context_route_api_git_review_commit_context_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/rev-parse":{"get":{"summary":"Git Rev Parse Route","operationId":"git_rev_parse_route_api_git_review_rev_parse_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}},{"name":"ref","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/ship-info":{"get":{"summary":"Git Ship Info Route","operationId":"git_ship_info_route_api_git_review_ship_info_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/stage":{"post":{"summary":"Git Stage Route","operationId":"git_stage_route_api_git_review_stage_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitFileBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/unstage":{"post":{"summary":"Git Unstage Route","operationId":"git_unstage_route_api_git_review_unstage_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitFileBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/revert":{"post":{"summary":"Git Revert Route","operationId":"git_revert_route_api_git_review_revert_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitFileBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/commit":{"post":{"summary":"Git Commit Route","operationId":"git_commit_route_api_git_review_commit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitCommitBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/push":{"post":{"summary":"Git Push Route","operationId":"git_push_route_api_git_review_push_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitPathBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/review/create-pr":{"post":{"summary":"Git Create Pr Route","operationId":"git_create_pr_route_api_git_review_create_pr_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitPathBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/worktree/add":{"post":{"summary":"Git Worktree Add Route","operationId":"git_worktree_add_route_api_git_worktree_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitWorktreeAddBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/worktree/remove":{"post":{"summary":"Git Worktree Remove Route","operationId":"git_worktree_remove_route_api_git_worktree_remove_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitWorktreeRemoveBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/branch/switch":{"post":{"summary":"Git Branch Switch Route","operationId":"git_branch_switch_route_api_git_branch_switch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitBranchSwitchBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/status":{"get":{"summary":"Get Status","operationId":"get_status_api_status_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/system/stats":{"get":{"summary":"Get System Stats","description":"Host + process system stats for the System page.\n\nOS / Python / host identity from stdlib; CPU / memory / disk / uptime from\npsutil when available, with graceful degradation when it isn't.  Read-only\nand non-sensitive (no env values, no paths beyond the hermes home root).","operationId":"get_system_stats_api_system_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/curator":{"get":{"summary":"Get Curator Status","operationId":"get_curator_status_api_curator_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/curator/paused":{"put":{"summary":"Set Curator Paused","operationId":"set_curator_paused_api_curator_paused_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CuratorPause"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/curator/run":{"post":{"summary":"Run Curator","description":"Trigger a curator review now (backgrounded; tail via action status).","operationId":"run_curator_api_curator_run_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/learning/graph":{"get":{"summary":"Get Learning Graph","description":"Learning graph payload for the desktop panel.\n\nProfile-scoped view of learned, non-base skills plus memory chunks, with\ngraph links derived from skill relations and memory-skill overlap.","operationId":"get_learning_graph_api_learning_graph_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/learning/node":{"get":{"summary":"Get Learning Node","description":"Current content of a journey node (skill SKILL.md or memory chunk), for an edit prefill.","operationId":"get_learning_node_api_learning_node_get","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","title":"Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Learning Node","description":"Delete a journey node — skills are archived (restorable), memories removed.","operationId":"delete_learning_node_api_learning_node_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearningNodeRef"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Learning Node","description":"Rewrite a journey node's content (SKILL.md or memory chunk).","operationId":"update_learning_node_api_learning_node_put","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearningNodeEdit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/portal":{"get":{"summary":"Get Portal Status","operationId":"get_portal_status_api_portal_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/prompt-size":{"post":{"summary":"Run Prompt Size","operationId":"run_prompt_size_api_ops_prompt_size_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/dump":{"post":{"summary":"Run Dump","operationId":"run_dump_api_ops_dump_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/config-migrate":{"post":{"summary":"Run Config Migrate","operationId":"run_config_migrate_api_ops_config_migrate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/debug-share":{"post":{"summary":"Run Debug Share Endpoint","description":"Upload a redacted debug report + full logs and return the paste URLs.\n\nUnlike the other diagnostics actions (doctor, dump, prompt-size) this is\n*synchronous*: the whole point of ``debug share`` is the set of shareable\nURLs it produces, so we run the upload in a worker thread and return the\nstructured ``{urls, failures, redacted, ...}`` payload directly. The\ndashboard renders those as real, copyable links instead of scraping a log\ntail. Pastes auto-delete after 6 hours (handled inside the share core).","operationId":"run_debug_share_endpoint_api_ops_debug_share_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DebugShareRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gateway/restart":{"post":{"summary":"Restart Gateway","description":"Kick off a ``hermes gateway restart`` in the background.","operationId":"restart_gateway_api_gateway_restart_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gateway/drain":{"post":{"summary":"Gateway Drain","description":"Begin or cancel an external (NAS-driven) gateway drain.\n\nAuthenticated by the non-interactive token-auth seam: the\n``dashboard_auth/drain`` plugin registers this exact path as a token route\nand verifies the ``Authorization`` bearer secret. If that plugin isn't\nactive (no ``HERMES_DASHBOARD_DRAIN_SECRET``), the route is NOT a token\nroute, so on a gated bind the cookie gate handles it (a browser session can\nstill drive it from the dashboard) and on a loopback bind the legacy\nsession-token gate applies — either way it is never unauthenticated on a\nnetwork-exposed bind.\n\nBody: ``{\"action\": \"drain\"}`` (begin) or ``{\"action\": \"cancel\"}`` (cancel).\nBegin writes the ``.drain_request.json`` marker the gateway's\n``_drain_control_watcher`` observes (flip to ``draining`` + refuse new\nturns); cancel removes it (revert to ``running`` + re-accept). Idempotent\non both sides. This endpoint only writes/removes the marker — the gateway\nprocess owns the actual state transition (there is no HTTP control channel\ninto the running gateway; the marker IS the channel, decisions.md Q-B).\n\nThe force-override (D6: \"unless a user commands it\") is NOT here — an\nimmediate, drain-skipping action maps onto the existing\n``POST /api/gateway/restart`` force path, which supersedes a drain.","operationId":"gateway_drain_api_gateway_drain_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/hermes/update":{"post":{"summary":"Update Hermes","description":"Kick off ``hermes update`` in the background.","operationId":"update_hermes_api_hermes_update_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/hermes/update/check":{"get":{"summary":"Check Hermes Update","description":"Report whether a Hermes update is available, without applying it.\n\nPowers the dashboard's \"check before you update\" flow: the System page\nshows the commit-behind count and asks the user to confirm before\n``POST /api/hermes/update`` actually runs ``hermes update``.\n\nReturns:\n    install_method: 'git' | 'pip' | 'docker' | 'nixos' | 'homebrew' | ...\n    current_version: installed Hermes version string\n    behind: commits behind upstream (>=1), 0 if up to date,\n            -1 if behind by an unknown count (nix/pypi), or null if the\n            check could not run (offline, no remote, etc.)\n    update_available: convenience bool (behind is non-zero and not null)\n    can_apply: True when the dashboard's update button can apply it\n               in place (git/pip); False for docker/nix/homebrew where the\n               user must update out-of-band\n    update_command: the recommended command for this install method\n    message: human-readable guidance for non-applyable methods\n    commits: for git/pip installs that are behind, a list of the commits\n             the local checkout is behind upstream by — each\n             {sha, summary, author, at}. Absent/empty otherwise. The\n             desktop's remote update overlay renders this as \"what's\n             changed\". Additive: existing consumers ignore it.","operationId":"check_hermes_update_api_hermes_update_check_get","parameters":[{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/audio/transcribe":{"post":{"summary":"Transcribe Audio Upload","operationId":"transcribe_audio_upload_api_audio_transcribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioTranscriptionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/audio/elevenlabs/voices":{"get":{"summary":"Get Elevenlabs Voices","description":"Return ElevenLabs voices when an API key is configured.\n\nThe desktop UI uses this for the ``tts.elevenlabs.voice_id`` dropdown.\nOnly non-secret voice metadata is returned; the API key stays server-side.","operationId":"get_elevenlabs_voices_api_audio_elevenlabs_voices_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/audio/speak":{"post":{"summary":"Speak Text","description":"Synthesize speech and return audio as base64 data URL.\n\nUsed by the desktop voice-conversation mode to play back assistant\nresponses without exposing the on-disk file path. Reuses the\nexisting TTS provider chain (Edge / OpenAI / ElevenLabs / etc.)\nconfigured in ``~/.hermes/config.yaml`` under ``tts.``.","operationId":"speak_text_api_audio_speak_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TTSSpeakRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/actions/{name}/status":{"get":{"summary":"Get Action Status","description":"Tail an action log and report whether the process is still running.","operationId":"get_action_status_api_actions__name__status_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"lines","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Lines"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions":{"get":{"summary":"Get Sessions","description":"List sessions.\n\n``archived`` controls how soft-archived sessions are treated:\n``exclude`` (default) hides them, ``only`` returns just the archived ones\n(used by the desktop \"Archived sessions\" settings panel), and ``include``\nreturns both.\n\n``order`` controls pagination order: ``created`` (default, by original\nstart time) or ``recent`` (by latest activity across the compression\nchain). ``recent`` keeps a long-running conversation on the first page\nafter it auto-compresses into a fresh continuation id.\n\nRows omit ``system_prompt``/``model_config`` (the payload-dominating\nfields no list UI reads) unless ``full=1`` is passed.","operationId":"get_sessions_api_sessions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"min_messages","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Min Messages"}},{"name":"archived","in":"query","required":false,"schema":{"type":"string","default":"exclude","title":"Archived"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"created","title":"Order"}},{"name":"source","in":"query","required":false,"schema":{"type":"string","title":"Source"}},{"name":"exclude_sources","in":"query","required":false,"schema":{"type":"string","title":"Exclude Sources"}},{"name":"cwd_prefix","in":"query","required":false,"schema":{"type":"string","title":"Cwd Prefix"}},{"name":"full","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Full"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/sessions":{"get":{"summary":"Get Profiles Sessions","description":"Unified, read-only session list aggregated across ALL profiles.\n\nIntentionally process-light: this opens each profile's ``state.db`` directly\nfrom disk — it does NOT spawn a dashboard backend per profile. Each returned\nsession is tagged with its owning ``profile`` so the desktop renders one\nbrowsable list and only spins up a profile's backend when the user actually\ninteracts (sends a message). A user with a single (default) profile gets the\nsame rows as ``/api/sessions``, just tagged ``profile=\"default\"``.\n\nRows omit ``system_prompt``/``model_config`` unless ``full=1`` — same\nlist projection as ``/api/sessions``.","operationId":"get_profiles_sessions_api_profiles_sessions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"min_messages","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Min Messages"}},{"name":"archived","in":"query","required":false,"schema":{"type":"string","default":"exclude","title":"Archived"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"recent","title":"Order"}},{"name":"profile","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Profile"}},{"name":"source","in":"query","required":false,"schema":{"type":"string","title":"Source"}},{"name":"exclude_sources","in":"query","required":false,"schema":{"type":"string","title":"Exclude Sources"}},{"name":"full","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Full"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/sessions/sidebar":{"get":{"summary":"Get Profiles Sessions Sidebar","description":"Batched sidebar session slices — one profile-DB open per refresh.\n\nThe desktop sidebar needs three source-scoped windows per refresh: recents\n(local chats, scoped to the active profile), cron sessions (all profiles),\nand messaging-platform sessions (all profiles). Served as three separate\n``/api/profiles/sessions`` calls they reopened every profile's ``state.db``\nthree times and re-counted each refresh. This opens each DB once and runs\nthe three filtered queries together, returning the three windows in one\npayload. Read-only and process-light, same row projection and 300s active\nheuristic as ``/api/profiles/sessions``.\n\nThe caller passes the source taxonomy (``recents_exclude`` /\n``messaging_exclude`` CSV, ``source=cron`` is implicit) so this stays\ntaxonomy-agnostic like the per-slice endpoint. All three slices use\n``min_messages=1`` / ``archived=exclude`` / recency order, matching the\ndesktop's per-slice calls.","operationId":"get_profiles_sessions_sidebar_api_profiles_sessions_sidebar_get","parameters":[{"name":"recents_profile","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Recents Profile"}},{"name":"recents_limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Recents Limit"}},{"name":"recents_exclude","in":"query","required":false,"schema":{"type":"string","title":"Recents Exclude"}},{"name":"cron_limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Cron Limit"}},{"name":"messaging_limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Messaging Limit"}},{"name":"messaging_exclude","in":"query","required":false,"schema":{"type":"string","title":"Messaging Exclude"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/search":{"get":{"summary":"Search Sessions","description":"Search sessions by ID plus full-text message content using FTS5.\n\nDirect session-id matches are surfaced first, then FTS message-content\nmatches. Results are deduped by compression lineage, not by raw\n``session_id``. Auto-compression rotates a conversation onto a fresh\nsession id (and leaves the old segment's messages in the FTS index), so one\nlogical chat can own many ``sessions`` rows that all match the same query.\nBranches also use ``parent_session_id``, but they are real alternate\nconversations; don't collapse branch-specific hits back into the parent.","operationId":"search_sessions_api_sessions_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/memory/providers/{name}/config":{"get":{"summary":"Get Memory Provider Config","operationId":"get_memory_provider_config_api_memory_providers__name__config_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"surface","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Surface"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Memory Provider Config","operationId":"update_memory_provider_config_api_memory_providers__name__config_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"surface","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Surface"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryProviderConfigUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/memory/providers/{name}/setup":{"post":{"summary":"Setup Memory Provider","operationId":"setup_memory_provider_api_memory_providers__name__setup_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryProviderSetupRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config":{"get":{"summary":"Get Config","operationId":"get_config_api_config_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Config","operationId":"update_config_api_config_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config/defaults":{"get":{"summary":"Get Defaults","operationId":"get_defaults_api_config_defaults_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/config/schema":{"get":{"summary":"Get Schema","operationId":"get_schema_api_config_schema_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/info":{"get":{"summary":"Get Model Info","description":"Return resolved model metadata for the currently configured model.\n\nCalls the same context-length resolution chain the agent uses, so the\nfrontend can display \"Auto-detected: 200K\" alongside the override field.\nAlso returns model capabilities (vision, reasoning, tools) when available.","operationId":"get_model_info_api_model_info_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/options":{"get":{"summary":"Get Model Options","description":"Return authenticated providers + their curated model lists.\n\nREST equivalent of the ``model.options`` JSON-RPC on tui_gateway, so the\ndashboard Models page can render the picker without a live chat session.\nThe response shape matches ``model.options`` 1:1 so ``ModelPickerDialog``\ncan share the same types.\n\n``profile`` scopes the picker context (current model/provider, custom\nproviders from config, per-profile .env auth state) so the Models page\nreads the SAME profile /api/model/set writes.\n\n``refresh`` busts the per-provider model-id disk cache so every row\nre-fetches its live catalog — used by the picker's explicit \"Refresh\nModels\" control. Normal opens leave it false to stay on the 1h cache.","operationId":"get_model_options_api_model_options_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},{"name":"refresh","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Refresh"}},{"name":"include_unconfigured","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Unconfigured"}},{"name":"explicit_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Explicit Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/recommended-default":{"get":{"summary":"Get Recommended Default Model","description":"Return the recommended default model for a freshly-authenticated provider.\n\nMirrors the model-curation `hermes model` does so GUI onboarding lands on a\nsensible default instead of blindly taking the first curated entry. For\nNous this honors the user's free/paid tier: free users get a free model,\npaid users get the full curated default. For any other provider it falls\nback to the first curated model (same as before).\n\nResponse: {\"provider\": str, \"model\": str, \"free_tier\": bool | None}\nwhere free_tier is True/False for Nous and None otherwise. `model` may be\nempty if nothing could be resolved (caller degrades gracefully).","operationId":"get_recommended_default_model_api_model_recommended_default_get","parameters":[{"name":"provider","in":"query","required":false,"schema":{"type":"string","default":"","title":"Provider"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/auxiliary":{"get":{"summary":"Get Auxiliary Models","description":"Return current auxiliary task assignments.\n\nShape:\n  {\n    \"tasks\": [\n      {\"task\": \"vision\", \"provider\": \"auto\", \"model\": \"\", \"base_url\": \"\"},\n      ...\n    ],\n    \"main\": {\"provider\": \"openrouter\", \"model\": \"anthropic/claude-opus-4.7\"},\n  }\n\n``profile`` scopes the read — without it, the Models page would show\nthe dashboard profile's auxiliary pins while /api/model/set wrote the\nselected profile's (read/write asymmetry).","operationId":"get_auxiliary_models_api_model_auxiliary_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/moa":{"get":{"summary":"Get Moa Models","description":"Return the configured Mixture-of-Agents provider/model slots.","operationId":"get_moa_models_api_model_moa_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Set Moa Models","description":"Persist the Mixture-of-Agents provider/model slots.","operationId":"set_moa_models_api_model_moa_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoaConfigPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/model/set":{"post":{"summary":"Set Model Assignment","description":"Assign a model to the main slot or an auxiliary task slot.\n\nWrites to ``~/.hermes/config.yaml`` — applies to **new** sessions only.\nThe currently running chat PTY (if any) is not affected; use the\n``/model`` slash command inside a chat to hot-swap that specific session.","operationId":"set_model_assignment_api_model_set_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAssignment"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/env":{"get":{"summary":"Get Env Vars","operationId":"get_env_vars_api_env_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Set Env Var","operationId":"set_env_var_api_env_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvVarUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Remove Env Var","operationId":"remove_env_var_api_env_delete","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvVarDelete"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/custom-endpoints":{"get":{"summary":"List Custom Endpoints","description":"Return configured OpenAI-compatible custom endpoints for Desktop.","operationId":"list_custom_endpoints_api_providers_custom_endpoints_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Upsert Custom Endpoint","description":"Create or update a v12+ ``providers`` custom endpoint entry.","operationId":"upsert_custom_endpoint_api_providers_custom_endpoints_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/custom-endpoints/{endpoint_id}/activate":{"post":{"summary":"Activate Custom Endpoint","description":"Set a configured custom endpoint as the default model provider.","operationId":"activate_custom_endpoint_api_providers_custom_endpoints__endpoint_id__activate_post","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/custom-endpoints/{endpoint_id}":{"delete":{"summary":"Delete Custom Endpoint","description":"Remove a configured custom endpoint from ``providers``.","operationId":"delete_custom_endpoint_api_providers_custom_endpoints__endpoint_id__delete","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/custom-endpoints/validate":{"post":{"summary":"Validate Custom Endpoint","description":"Probe a custom endpoint by calling its OpenAI-compatible /models URL.","operationId":"validate_custom_endpoint_api_providers_custom_endpoints_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/validate":{"post":{"summary":"Validate Provider Credential","description":"Live-probe a provider credential before it's saved.\n\nReturns {ok, reachable, message}. ok=True means the provider accepted the\nkey; ok=False + reachable=True means the key is bad (caller should block);\nreachable=False means the network probe couldn't run (caller may save with\na warning rather than hard-blocking offline users).","operationId":"validate_provider_credential_api_providers_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvVarUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/env/reveal":{"post":{"summary":"Reveal Env Var","description":"Return the real (unredacted) value of a single env var.\n\nProtected by:\n- Ephemeral session token (generated per server start, injected into SPA)\n- Rate limiting (max 5 reveals per 30s window)\n- Audit logging","operationId":"reveal_env_var_api_env_reveal_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvVarReveal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/whatsapp/onboarding/start":{"post":{"summary":"Start Whatsapp Onboarding","operationId":"start_whatsapp_onboarding_api_messaging_whatsapp_onboarding_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppOnboardingStart"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/whatsapp/onboarding/{pairing_id}":{"get":{"summary":"Get Whatsapp Onboarding Status","operationId":"get_whatsapp_onboarding_status_api_messaging_whatsapp_onboarding__pairing_id__get","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Cancel Whatsapp Onboarding","operationId":"cancel_whatsapp_onboarding_api_messaging_whatsapp_onboarding__pairing_id__delete","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/whatsapp/onboarding/{pairing_id}/apply":{"post":{"summary":"Apply Whatsapp Onboarding","operationId":"apply_whatsapp_onboarding_api_messaging_whatsapp_onboarding__pairing_id__apply_post","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppOnboardingApply"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/telegram/onboarding/start":{"post":{"summary":"Start Telegram Onboarding","operationId":"start_telegram_onboarding_api_messaging_telegram_onboarding_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramOnboardingStart"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/telegram/onboarding/{pairing_id}":{"get":{"summary":"Get Telegram Onboarding Status","operationId":"get_telegram_onboarding_status_api_messaging_telegram_onboarding__pairing_id__get","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Cancel Telegram Onboarding","operationId":"cancel_telegram_onboarding_api_messaging_telegram_onboarding__pairing_id__delete","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/telegram/onboarding/{pairing_id}/apply":{"post":{"summary":"Apply Telegram Onboarding","operationId":"apply_telegram_onboarding_api_messaging_telegram_onboarding__pairing_id__apply_post","parameters":[{"name":"pairing_id","in":"path","required":true,"schema":{"type":"string","title":"Pairing Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramOnboardingApply"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/platforms":{"get":{"summary":"Get Messaging Platforms","operationId":"get_messaging_platforms_api_messaging_platforms_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/platforms/{platform_id}":{"put":{"summary":"Update Messaging Platform","operationId":"update_messaging_platform_api_messaging_platforms__platform_id__put","parameters":[{"name":"platform_id","in":"path","required":true,"schema":{"type":"string","title":"Platform Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingPlatformUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/messaging/platforms/{platform_id}/test":{"post":{"summary":"Test Messaging Platform","operationId":"test_messaging_platform_api_messaging_platforms__platform_id__test_post","parameters":[{"name":"platform_id","in":"path","required":true,"schema":{"type":"string","title":"Platform Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth":{"get":{"summary":"List Oauth Providers","description":"Enumerate every OAuth-capable LLM provider with current status.\n\nResponse shape (per provider):\n    id              stable identifier (used in DELETE path)\n    name            human label\n    flow            \"pkce\" | \"device_code\" | \"external\"\n    cli_command     fallback CLI command for users to run manually\n    disconnect_command  shell command that clears an external provider's\n                        creds (run in the embedded terminal), else null\n    docs_url        external docs/portal link for the \"Learn more\" link\n    status:\n      logged_in        bool — currently has usable creds\n      source           short slug (\"hermes_pkce\", \"claude_code\", ...)\n      source_label     human-readable origin (file path, env var name)\n      token_preview    last N chars of the token, never the full token\n      expires_at       ISO timestamp string or null\n      has_refresh_token bool\n\nMembership is derived from the unified provider_catalog() so this stays in\nsync with the `hermes model` picker; _OAUTH_OVERRIDES supplies per-provider\nflow/status/cli metadata.","operationId":"list_oauth_providers_api_providers_oauth_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth/{provider_id}":{"delete":{"summary":"Disconnect Oauth Provider","description":"Disconnect an OAuth provider. Token-protected (matches /env/reveal).","operationId":"disconnect_oauth_provider_api_providers_oauth__provider_id__delete","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth/{provider_id}/start":{"post":{"summary":"Start Oauth Login","description":"Initiate an OAuth login flow. Token-protected.","operationId":"start_oauth_login_api_providers_oauth__provider_id__start_post","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth/{provider_id}/submit":{"post":{"summary":"Submit Oauth Code","description":"Submit the auth code for PKCE flows. Token-protected.","operationId":"submit_oauth_code_api_providers_oauth__provider_id__submit_post","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthSubmitBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth/{provider_id}/poll/{session_id}":{"get":{"summary":"Poll Oauth Session","description":"Poll a session's status (no auth — read-only state).\n\nShared by the device-code flows (Nous, OpenAI Codex, MiniMax, xAI).\nEach surfaces progress through the same background-worker-updated\n``status`` field, so a single poll endpoint serves them all.","operationId":"poll_oauth_session_api_providers_oauth__provider_id__poll__session_id__get","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers/oauth/sessions/{session_id}":{"delete":{"summary":"Cancel Oauth Session","description":"Cancel a pending OAuth session. Token-protected.","operationId":"cancel_oauth_session_api_providers_oauth_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/bulk-delete":{"post":{"summary":"Bulk Delete Sessions Endpoint","description":"Delete every session in ``body.ids`` in a single DB transaction.\n\nBacks the dashboard's bulk-select-and-delete flow on the sessions\npage. POST (not DELETE) because most HTTP clients refuse to send a\nrequest body on DELETE and a body is the natural shape for a list\nof IDs — Starlette accepts both, but POSTing a list keeps proxies,\ncurl, and the browser ``fetch`` API consistent.\n\nPer-row contract matches :meth:`SessionDB.delete_sessions`:\n\n* Unknown IDs are silently skipped (the response ``deleted`` count\n  reflects what really happened, not the input length). This is\n  deliberate — UI selection state can race against another tab's\n  delete, and we'd rather succeed-on-the-rest than fail-the-whole-\n  batch.\n* Children of every deleted parent are orphaned, not cascade-\n  deleted.\n* Active and archived sessions ARE deleted when explicitly\n  selected — unlike ``DELETE /api/sessions/empty``, the user\n  hand-picked the rows so we trust the selection.\n* Like the other session-delete endpoints, this does NOT pass a\n  ``sessions_dir`` through; on-disk transcript / request-dump\n  cleanup runs at the CLI/agent layer on the next prune pass.\n\nThe response carries the actual deleted count, so the dashboard\ncan surface it in a toast. The IDs that were removed are not\nechoed back because the client already knows what it asked to\ndelete (unknown IDs are silently skipped — see contract above)\nand can prune its in-memory list directly from the request.","operationId":"bulk_delete_sessions_endpoint_api_sessions_bulk_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteSessions"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/import":{"post":{"summary":"Import Sessions Endpoint","description":"Import one or more sessions exported from the dashboard or CLI.\n\nThis is intentionally separate from ``/api/ops/import``: that endpoint\nrestores a whole Hermes backup archive, while this endpoint is scoped to\nsession rows/messages and is safe to use from the Sessions page.","operationId":"import_sessions_endpoint_api_sessions_import_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/sessions/empty/count":{"get":{"summary":"Count Empty Sessions Endpoint","description":"Return the number of empty, ended, non-archived sessions.\n\nDrives the dashboard's \"Delete empty (N)\" button — when N is 0 the\nUI hides the affordance so users aren't presented with a button\nthat does nothing. Cheap, single-COUNT query.","operationId":"count_empty_sessions_endpoint_api_sessions_empty_count_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/empty":{"delete":{"summary":"Delete Empty Sessions Endpoint","description":"Delete every empty (``message_count == 0``), ended,\nnon-archived session in a single transaction.\n\nSafety contract mirrors :meth:`SessionDB.delete_empty_sessions`:\n\n* Active sessions are skipped (``ended_at IS NULL``) so a live\n  agent isn't yanked mid-handshake.\n* Archived sessions are skipped — the user explicitly chose to\n  keep those rows.\n* Children of deleted parents are orphaned, not cascade-deleted.\n\nLike the single-session ``DELETE /api/sessions/{id}`` endpoint\nbelow, this doesn't pass a ``sessions_dir`` through — the on-disk\ntranscript / request-dump cleanup is wired at the CLI/agent layer\nbut the web server historically leaves file cleanup to the next\nprune-on-startup pass. Matching that pre-existing trade-off keeps\nthe two delete endpoints' DB-vs-disk behaviour consistent.","operationId":"delete_empty_sessions_endpoint_api_sessions_empty_delete","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/stats":{"get":{"summary":"Get Session Stats","description":"Session-store statistics for the Sessions page (mirrors `hermes sessions stats`).\n\nRegistered before ``/api/sessions/{session_id}`` so the literal ``stats``\npath isn't captured as a session id by the parameterized route.","operationId":"get_session_stats_api_sessions_stats_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/{session_id}":{"get":{"summary":"Get Session Detail","operationId":"get_session_detail_api_sessions__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Session Endpoint","operationId":"delete_session_endpoint_api_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Rename Session Endpoint","description":"Update a session: rename (or clear its title) and/or archive it.\n\n``title`` renames (empty/null clears the title); ``archived`` soft-hides or\nrestores the session. Either field may be omitted. ``profile`` targets\nanother profile's session.","operationId":"rename_session_endpoint_api_sessions__session_id__patch","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionRename"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/{session_id}/latest-descendant":{"get":{"summary":"Get Session Latest Descendant","operationId":"get_session_latest_descendant_api_sessions__session_id__latest_descendant_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/{session_id}/messages":{"get":{"summary":"Get Session Messages","operationId":"get_session_messages_api_sessions__session_id__messages_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/{session_id}/export":{"get":{"summary":"Export Session Endpoint","description":"Export a single session (metadata + messages) as JSON.","operationId":"export_session_endpoint_api_sessions__session_id__export_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sessions/prune":{"post":{"summary":"Prune Sessions Endpoint","description":"Delete ended sessions matching filters without blocking the event loop.","operationId":"prune_sessions_endpoint_api_sessions_prune_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionPrune"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/logs":{"get":{"summary":"Get Logs","operationId":"get_logs_api_logs_get","parameters":[{"name":"file","in":"query","required":false,"schema":{"type":"string","default":"agent","title":"File"}},{"name":"lines","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Lines"}},{"name":"level","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Level"}},{"name":"component","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/jobs":{"get":{"summary":"List Cron Jobs","operationId":"list_cron_jobs_api_cron_jobs_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Cron Job","operationId":"create_cron_job_api_cron_jobs_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronJobCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/jobs/{job_id}":{"get":{"summary":"Get Cron Job","operationId":"get_cron_job_api_cron_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Cron Job","operationId":"update_cron_job_api_cron_jobs__job_id__put","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronJobUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Cron Job","operationId":"delete_cron_job_api_cron_jobs__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/jobs/{job_id}/runs":{"get":{"summary":"List Cron Job Runs","operationId":"list_cron_job_runs_api_cron_jobs__job_id__runs_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/delivery-targets":{"get":{"summary":"Get Cron Delivery Targets","description":"Delivery targets the cron dropdown should offer.\n\nAlways includes the implicit ``local`` option. Beyond that, the list is\nderived dynamically from the configured gateway platforms via\n``cron.scheduler.cron_delivery_targets()`` — no hardcoded platform list. A\nconfigured platform that hasn't set its cron home channel is still returned\nwith ``home_target_set: false`` so the UI can surface it as \"configure a\nhome channel first\" rather than hiding it.","operationId":"get_cron_delivery_targets_api_cron_delivery_targets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/cron/jobs/{job_id}/pause":{"post":{"summary":"Pause Cron Job","operationId":"pause_cron_job_api_cron_jobs__job_id__pause_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/jobs/{job_id}/resume":{"post":{"summary":"Resume Cron Job","operationId":"resume_cron_job_api_cron_jobs__job_id__resume_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/jobs/{job_id}/trigger":{"post":{"summary":"Trigger Cron Job","operationId":"trigger_cron_job_api_cron_jobs__job_id__trigger_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cron/fire":{"post":{"summary":"Cron Fire Webhook","description":"Chronos managed-cron fire webhook (NAS -> agent).\n\nAuthenticated by a short-lived NAS-minted JWT (verified by the pluggable\nChronos fire-verifier), NOT the dashboard session cookie — so this path is\nin ``PUBLIC_API_PATHS`` to bypass the dashboard auth gate, and the JWT is\nthe real gate. This is the inbound half of scale-to-zero managed cron: NAS\nPOSTs here at fire time, the agent verifies, claims the job (store CAS, so\nat-most-once across replicas / on a NAS retry), runs it, and re-arms the\nnext one-shot.\n\nLives on the dashboard app (not the api_server adapter) because the\ndashboard is the agent's always-reachable public HTTP surface on hosted\ndeployments; the gateway may be idle/scaled down.\n\nReturns 202 immediately and runs the job in the background so a long agent\nturn never trips NAS's HTTP timeout.","operationId":"cron_fire_webhook_api_cron_fire_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/cron/blueprints":{"get":{"summary":"List Cron Blueprints","description":"Return the blueprint catalog as form schemas for the dashboard gallery.\n\nThe ``deliver`` slot's options are rewritten from the user's actually\nconfigured gateway platforms (plus the universal origin/local/all), so the\nform never offers a platform that isn't connected.","operationId":"list_cron_blueprints_api_cron_blueprints_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/cron/blueprints/instantiate":{"post":{"summary":"Instantiate Blueprint","description":"Fill a blueprint's slots and create the cron job (form-submit path).","operationId":"instantiate_blueprint_api_cron_blueprints_instantiate_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"type":"string","default":"default","title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationBlueprintInstantiate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/servers":{"get":{"summary":"List Mcp Servers","operationId":"list_mcp_servers_api_mcp_servers_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Add Mcp Server","operationId":"add_mcp_server_api_mcp_servers_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServerCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Replace Mcp Servers","description":"Replace the entire ``mcp_servers`` map (the GUI mcp.json editor's save).\n\nThe generic ``/api/config`` endpoint deep-merges maps, so it can never\ndelete a server key, drop an ``enabled: false`` flag, or remove a nested\nfield — edits looked saved but the stale entry survived on disk.  This\nendpoint sets the whole map so removals actually persist.  Storage stays\nthe config.yaml ``mcp_servers`` key the CLI/TUI already read.","operationId":"replace_mcp_servers_api_mcp_servers_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServersReplace"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/servers/{name}":{"delete":{"summary":"Remove Mcp Server","operationId":"remove_mcp_server_api_mcp_servers__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/servers/{name}/test":{"post":{"summary":"Test Mcp Server","description":"Connect to the server, list its tools, disconnect.  Returns tool list.","operationId":"test_mcp_server_api_mcp_servers__name__test_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/servers/{name}/auth":{"post":{"summary":"Auth Mcp Server","description":"Start MCP OAuth and hand the authorization URL to the dashboard browser.","operationId":"auth_mcp_server_api_mcp_servers__name__auth_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/oauth/flows/{flow_id}":{"get":{"summary":"Mcp Oauth Flow Status","operationId":"mcp_oauth_flow_status_api_mcp_oauth_flows__flow_id__get","parameters":[{"name":"flow_id","in":"path","required":true,"schema":{"type":"string","title":"Flow Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/oauth/callback/{server_name}":{"get":{"summary":"Mcp Oauth Callback","operationId":"mcp_oauth_callback_api_mcp_oauth_callback__server_name__get","parameters":[{"name":"server_name","in":"path","required":true,"schema":{"type":"string","title":"Server Name"}},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/servers/{name}/enabled":{"put":{"summary":"Set Mcp Server Enabled","description":"Enable or disable an MCP server (takes effect on next session/gateway).\n\nToggles the ``enabled`` key on the server's config.yaml entry — the same\nflag the agent reads at startup.  Disabled servers stay in config so they\ncan be re-enabled without re-entering their settings.","operationId":"set_mcp_server_enabled_api_mcp_servers__name__enabled_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPEnabledToggle"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/catalog":{"get":{"summary":"List Mcp Catalog","description":"Browse the Nous-approved MCP catalog (the optional-mcps/ manifests).\n\nEach entry reports whether it's already installed and enabled so the UI\ncan show install / enabled state inline.  This is the same catalog\n`hermes mcp catalog` / `hermes mcp install` read.  ``profile`` scopes\nthe installed/enabled annotations (the catalog itself is repo-shipped\nand identical for every profile).","operationId":"list_mcp_catalog_api_mcp_catalog_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp/catalog/install":{"post":{"summary":"Install Mcp Catalog Entry","description":"Install a catalog MCP into config.yaml.\n\nFor HTTP/stdio entries with required env vars, those are written to .env\nvia the standard env path so the agent can read them at session start.\nEntries that need a git bootstrap (``needs_install``) are installed via\nthe CLI action path because the clone can take time.","operationId":"install_mcp_catalog_entry_api_mcp_catalog_install_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPCatalogInstall"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pairing":{"get":{"summary":"List Pairing","operationId":"list_pairing_api_pairing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/pairing/approve":{"post":{"summary":"Approve Pairing","operationId":"approve_pairing_api_pairing_approve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairingApprove"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pairing/revoke":{"post":{"summary":"Revoke Pairing","operationId":"revoke_pairing_api_pairing_revoke_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairingRevoke"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pairing/clear-pending":{"post":{"summary":"Clear Pending Pairing","operationId":"clear_pending_pairing_api_pairing_clear_pending_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/webhooks":{"get":{"summary":"List Webhooks","operationId":"list_webhooks_api_webhooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Create Webhook","operationId":"create_webhook_api_webhooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/webhooks/enable":{"post":{"summary":"Enable Webhooks","operationId":"enable_webhooks_api_webhooks_enable_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/webhooks/{name}":{"delete":{"summary":"Delete Webhook","operationId":"delete_webhook_api_webhooks__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/webhooks/{name}/enabled":{"put":{"summary":"Set Webhook Enabled","description":"Enable or disable a webhook route.\n\nDisabled routes stay in the subscriptions file (so they can be\nre-enabled) but the gateway rejects incoming events with 403.  The\ngateway hot-reloads the subscriptions file, so this takes effect on the\nnext event without a restart.","operationId":"set_webhook_enabled_api_webhooks__name__enabled_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnabledToggle"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gateway/start":{"post":{"summary":"Start Gateway","operationId":"start_gateway_api_gateway_start_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gateway/stop":{"post":{"summary":"Stop Gateway","operationId":"stop_gateway_api_gateway_stop_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/credentials/pool":{"get":{"summary":"List Credential Pool","operationId":"list_credential_pool_api_credentials_pool_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Add Credential Pool Entry","operationId":"add_credential_pool_entry_api_credentials_pool_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPoolAdd"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/credentials/pool/{provider}/{index}":{"delete":{"summary":"Remove Credential Pool Entry","description":"Remove a pool entry.  ``index`` is 1-based (matches the list response).\n\nRemoval must be sticky (#55217): ``load_pool()`` re-seeds entries from\ntheir backing source (.env var, OAuth singleton file, custom-provider\nconfig) on every call, so deleting only the pool row silently reverts on\nthe next dashboard refresh.  We dispatch through the same RemovalStep\nregistry the CLI ``hermes auth remove`` uses: each source cleans up its\nexternal state and suppresses ``(provider, source)`` so the seeders skip\nit.  Manual entries have no registered step — nothing external to clean,\nno suppression needed (they aren't re-seeded).","operationId":"remove_credential_pool_entry_api_credentials_pool__provider___index__delete","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","title":"Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/memory":{"get":{"summary":"Get Memory Status","operationId":"get_memory_status_api_memory_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/memory/provider":{"put":{"summary":"Set Memory Provider","operationId":"set_memory_provider_api_memory_provider_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryProviderSelect"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/memory/reset":{"post":{"summary":"Reset Memory","operationId":"reset_memory_api_memory_reset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryReset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/doctor":{"post":{"summary":"Run Doctor","operationId":"run_doctor_api_ops_doctor_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/security-audit":{"post":{"summary":"Run Security Audit","operationId":"run_security_audit_api_ops_security_audit_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/backup":{"post":{"summary":"Run Backup","operationId":"run_backup_api_ops_backup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/backup/download":{"get":{"summary":"Download Dashboard Backup","operationId":"download_dashboard_backup_api_ops_backup_download_get","parameters":[{"name":"archive","in":"query","required":true,"schema":{"type":"string","title":"Archive"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/import":{"post":{"summary":"Run Import","operationId":"run_import_api_ops_import_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/import-upload":{"post":{"summary":"Run Import Upload","operationId":"run_import_upload_api_ops_import_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_run_import_upload_api_ops_import_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/hooks":{"get":{"summary":"List Hooks","description":"List configured shell hooks from config.yaml with consent + health.\n\nReports each hook's allowlist (consent) status and whether the script is\ncurrently executable, plus the set of valid hook events so the create\nform can offer them.","operationId":"list_hooks_api_ops_hooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Create Hook","description":"Add a shell hook to config.yaml (and optionally approve it).\n\nShell hooks run arbitrary commands, so this is a privileged action: it\nwrites to the ``hooks:`` config block and, when ``approve`` is set, records\nconsent in the allowlist so the hook actually fires.  Takes effect on the\nnext session / gateway restart.","operationId":"create_hook_api_ops_hooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Hook","description":"Remove a hook from config.yaml and revoke its consent allowlist entry.","operationId":"delete_hook_api_ops_hooks_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookDelete"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ops/checkpoints":{"get":{"summary":"List Checkpoints","description":"List the /rollback shadow store checkpoints (read-only).","operationId":"list_checkpoints_api_ops_checkpoints_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ops/checkpoints/prune":{"post":{"summary":"Prune Checkpoints","operationId":"prune_checkpoints_api_ops_checkpoints_prune_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/skills/hub/install":{"post":{"summary":"Install Skill Hub","operationId":"install_skill_hub_api_skills_hub_install_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillInstallRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/uninstall":{"post":{"summary":"Uninstall Skill Hub","operationId":"uninstall_skill_hub_api_skills_hub_uninstall_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillUninstallRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/update":{"post":{"summary":"Update Skills Hub","operationId":"update_skills_hub_api_skills_hub_update_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SkillsUpdateRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/sources":{"get":{"summary":"List Skills Hub Sources","description":"List the configured skill-hub sources and installed-skill provenance.\n\nGives the dashboard something to show BEFORE a search runs — which hubs\nare wired up, their trust tier, and a set of featured skills pulled from\nthe centralized index (zero extra API calls).  Without this the Browse-hub\ntab is a blank page with no indication it's even connected to anything.\n``profile`` scopes the installed-skill provenance to that profile.","operationId":"list_skills_hub_sources_api_skills_hub_sources_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/search":{"get":{"summary":"Search Skills Hub","description":"Search the skill hub across all configured sources.\n\nNetwork-bound (parallel source search); runs in a thread so the FastAPI\nloop isn't blocked.  Returns structured results the UI installs by\nidentifier via POST /api/skills/hub/install, previews via\n/api/skills/hub/preview, and scans via /api/skills/hub/scan.","operationId":"search_skills_hub_api_skills_hub_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"source","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Source"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/preview":{"get":{"summary":"Preview Skill Hub","description":"Fetch a hub skill's SKILL.md content + metadata for in-dashboard reading.\n\nResolves the identifier across configured sources (same path the CLI\ninstaller uses), then returns the rendered SKILL.md text and the file\nmanifest WITHOUT installing anything.  This is the 'read the actual skill\nbefore installing' affordance the Browse-hub tab was missing.\n\nScoped to ``profile`` so a non-default profile with different hub taps\nresolves against ITS source router, not the default profile's.","operationId":"preview_skill_hub_api_skills_hub_preview_get","parameters":[{"name":"identifier","in":"query","required":false,"schema":{"type":"string","default":"","title":"Identifier"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/hub/scan":{"get":{"summary":"Scan Skill Hub","description":"Run the install-time security scan on a hub skill WITHOUT installing it.\n\nFetches the bundle, quarantines it, and runs the same `scan_skill` /\n`should_allow_install` pipeline the CLI installer uses — then cleans up the\nquarantine.  Returns the verdict, per-finding detail, trust tier, and the\ninstall-policy decision so the dashboard can show a visual safety result\non demand (the 'scan' button the Browse-hub tab was missing).\n\nScoped to ``profile`` so the bundle resolves against that profile's hub\nsource router, matching where an install would pull it from.","operationId":"scan_skill_hub_api_skills_hub_scan_get","parameters":[{"name":"identifier","in":"query","required":false,"schema":{"type":"string","default":"","title":"Identifier"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles":{"get":{"summary":"List Profiles Endpoint","operationId":"list_profiles_endpoint_api_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Create Profile Endpoint","operationId":"create_profile_endpoint_api_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/active":{"get":{"summary":"Get Active Profile Endpoint","description":"Return the sticky active profile and the profile this dashboard\nprocess is currently running as.\n\n``active`` is the sticky default written by ``hermes profile use`` —\nthe profile new CLI invocations pick up. ``current`` is the profile\nthe running dashboard/gateway is scoped to (derived from HERMES_HOME).","operationId":"get_active_profile_endpoint_api_profiles_active_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Set Active Profile Endpoint","description":"Set the sticky active profile (mirrors ``hermes profile use``).\n\nNote: this does not retarget the already-running dashboard process —\nit changes which profile subsequent CLI commands and gateways use.","operationId":"set_active_profile_endpoint_api_profiles_active_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileActiveUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/setup-command":{"get":{"summary":"Get Profile Setup Command","operationId":"get_profile_setup_command_api_profiles__name__setup_command_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/open-terminal":{"post":{"summary":"Open Profile Terminal Endpoint","operationId":"open_profile_terminal_endpoint_api_profiles__name__open_terminal_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}":{"patch":{"summary":"Rename Profile Endpoint","operationId":"rename_profile_endpoint_api_profiles__name__patch","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileRename"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Profile Endpoint","description":"Delete a profile. The dashboard collects the user's confirmation in\nits own dialog before this request, so we always pass ``yes=True`` to\nskip the CLI's interactive prompt.","operationId":"delete_profile_endpoint_api_profiles__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/soul":{"get":{"summary":"Get Profile Soul","operationId":"get_profile_soul_api_profiles__name__soul_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Profile Soul","operationId":"update_profile_soul_api_profiles__name__soul_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileSoulUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/description":{"put":{"summary":"Update Profile Description Endpoint","description":"Set or clear a profile's role description (kanban routing signal).\n\nEmpty string clears the description. Non-empty stores it as a\nuser-authored description (``description_auto: false``) so the\nauto-describer won't overwrite it on a sweep.","operationId":"update_profile_description_endpoint_api_profiles__name__description_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileDescriptionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/model":{"put":{"summary":"Update Profile Model Endpoint","description":"Set the main model (``model.default`` + ``model.provider``) for a\nspecific profile's config.yaml, without touching the dashboard's own\nactive profile. Mirrors ``POST /api/model/set`` (main scope) but scoped\nto the named profile via the HERMES_HOME override.","operationId":"update_profile_model_endpoint_api_profiles__name__model_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileModelUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/describe-auto":{"post":{"summary":"Describe Profile Auto Endpoint","description":"Auto-generate a profile's description via the auxiliary LLM\n(``auxiliary.profile_describer``). Mirrors ``hermes profile describe\n<name> --auto``.\n\nA failed generation (no aux client, LLM error, …) is returned as\n``ok: false`` with a reason rather than an HTTP error so the UI can\nsurface it inline and let the operator fix config and retry.","operationId":"describe_profile_auto_endpoint_api_profiles__name__describe_auto_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileDescribeAuto"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills":{"get":{"summary":"Get Skills","operationId":"get_skills_api_skills_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Skill","description":"Create a new custom skill (SKILL.md) from the dashboard editor.\n\nCalls the same validated write path as the agent's ``skill_manage``\ntool (frontmatter validation, name/category validation, size limit,\noptional security scan) — but bypasses the agent write-approval gate:\na write from the authenticated dashboard IS the user acting directly.","operationId":"create_skill_api_skills_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/toggle":{"put":{"summary":"Toggle Skill","operationId":"toggle_skill_api_skills_toggle_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillToggle"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/content":{"get":{"summary":"Get Skill Content","description":"Return the raw SKILL.md text for a skill, for the dashboard editor.","operationId":"get_skill_content_api_skills_content_get","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Skill Content","description":"Replace the SKILL.md of an existing skill (full rewrite) from the editor.","operationId":"update_skill_content_api_skills_content_put","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillContentUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets":{"get":{"summary":"Get Toolsets","operationId":"get_toolsets_api_tools_toolsets_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}":{"put":{"summary":"Toggle Toolset","description":"Enable/disable a configurable toolset for its configuration platform.\n\nMost toolsets persist to ``platform_toolsets.cli``. Platform-restricted\ntoolsets instead target their supported platform (for example, Discord's\nnative toolsets persist to ``platform_toolsets.discord``). The shared\n``_save_platform_tools`` helper keeps the GUI and CLI in lockstep. Scoped\nto ``body.profile`` when provided. Returns 400 for unknown toolset keys.","operationId":"toggle_toolset_api_tools_toolsets__name__put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsetToggle"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/config":{"get":{"summary":"Get Toolset Config","description":"Return the provider matrix + key status for a toolset's config panel.\n\nSurfaces the same provider rows the CLI ``hermes tools`` picker shows\n(via ``_visible_providers``), each with its ``env_vars`` annotated with\ncurrent ``is_set`` state so the GUI can render provider selection + key\nentry. Toolsets without a ``TOOL_CATEGORIES`` entry return an empty\nprovider list and ``has_category: false``. Returns 400 for unknown keys.","operationId":"get_toolset_config_api_tools_toolsets__name__config_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/models":{"get":{"summary":"Get Toolset Models","description":"Return the model catalog for a toolset backend (image/video gen).\n\nThe GUI counterpart of the model picker `hermes tools` runs after a\nbackend is selected — e.g. FAL's multi-model catalog (speed / strengths /\nprice per model). ``provider`` names a picker row; omitted, the currently\nactive provider is used. Toolsets without model catalogs return\n``has_models: false``.","operationId":"get_toolset_models_api_tools_toolsets__name__models_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"provider","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/model":{"put":{"summary":"Select Toolset Model","description":"Persist a backend model selection (``image_gen.model`` / ``video_gen.model``).\n\nValidates the model against the resolved backend's catalog — the same\nwrite the CLI's post-selection model picker performs. Returns 400 for\ntoolsets without model catalogs or unknown model ids.","operationId":"select_toolset_model_api_tools_toolsets__name__model_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsetModelSelect"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/provider":{"put":{"summary":"Select Toolset Provider","description":"Persist a provider selection for a toolset (no key prompting).\n\nDelegates to ``apply_provider_selection`` — the shared, non-interactive\ncore extracted from the CLI configurator — so the GUI and ``hermes tools``\nwrite identical config keys (``web.backend``, ``tts.provider``, etc.).\nAPI keys and post-setup flows are handled by separate endpoints. Returns\n400 for unknown toolset or provider names.\n\nFor the ``web`` toolset only, an optional ``capability`` ('search' |\n'extract') scopes the selection to ``web.search_backend`` /\n``web.extract_backend`` — the same per-capability overrides the runtime\ndispatchers (``tools.web_tools._get_search_backend`` /\n``_get_extract_backend``) resolve first. The provider must actually\nsupport the requested capability (a search-only backend can't be the\nextract backend). Omitting ``capability`` keeps the legacy whole-provider\nbehavior (writes ``web.backend``).\n\nManaged Nous rows (``managed_nous_feature``) additionally report the\nPortal entitlement state: the CLI flow gates these selections on\n``ensure_nous_portal_access`` (inline login), but the GUI has no inline\nprompt, so selecting one while logged out / unentitled used to write the\nconfig keys and then never activate (``_is_provider_active`` requires\n``managed_by_nous``). The response now carries an additive\n``needs_nous_auth: true`` + ``feature`` so the client can drive the\nexisting Nous Portal OAuth flow (``POST /api/providers/oauth/nous/start``)\nand refetch.","operationId":"select_toolset_provider_api_tools_toolsets__name__provider_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsetProviderSelect"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/env":{"put":{"summary":"Save Toolset Env","description":"Persist API keys for a toolset's provider env vars.\n\nWrites each ``key: value`` to ``~/.hermes/.env`` via ``save_env_value`` —\nthe same store ``hermes tools`` writes when it prompts for keys. Keys are\nvalidated against the env-var allowlist for the toolset's category (the\nunion of every visible provider's ``env_vars``), so the GUI can't write an\narbitrary env var through this endpoint. A blank value is treated as\n\"leave unchanged\" and skipped. Returns the saved/skipped key lists and the\nrefreshed ``is_set`` status. Returns 400 for unknown toolset or env keys.","operationId":"save_toolset_env_api_tools_toolsets__name__env_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsetEnvUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/toolsets/{name}/post-setup":{"post":{"summary":"Run Toolset Post Setup","description":"Spawn a provider's post-setup install hook as a background action.\n\nPost-setup hooks (npm install for browser/Camofox, pip install for\nKittenTTS/Piper/ddgs, cua-driver fetch, etc.) are long-running and\ntext-output, so this follows the spawn-action pattern: it launches\n``hermes tools post-setup <key>`` and the frontend tails the log via\n``GET /api/actions/tools-post-setup/status``. The ``key`` is validated\nagainst the declared post-setup allowlist before spawning. Returns 400\nfor unknown toolset or post-setup key.\n\n``profile`` spawns the hook as ``hermes -p <profile> tools post-setup``.\nMost hooks install machine-level artifacts (repo node_modules, shared\npip packages) where the scope is inert, but hooks that read config or\nwrite per-profile state must see the same HERMES_HOME the rest of the\ndrawer's writes targeted — so the scope is threaded for consistency.","operationId":"run_toolset_post_setup_api_tools_toolsets__name__post_setup_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsetPostSetup"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/terminal/backends":{"get":{"summary":"Get Terminal Backends","description":"Terminal execution backend rows with health probes for the picker panel.\n\nReturns ``{active, backends: [{name, label, description, active, status,\ndetail}]}`` where ``status`` is ``ready`` / ``needs_setup`` /\n``unavailable`` and ``detail`` carries setup guidance for non-ready rows.\nProbes are fast (<~2s each) and defensive — a probe failure surfaces as a\nstatus, never an error response.","operationId":"get_terminal_backends_api_tools_terminal_backends_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/terminal/backend":{"put":{"summary":"Select Terminal Backend","description":"Persist ``terminal.backend`` in config.yaml.\n\nValidates against the known backend set (the same enum the raw-config\nsettings row exposes). Selecting a backend that still needs setup is\nallowed — the picker shows guidance instead of blocking, matching the CLI.","operationId":"select_terminal_backend_api_tools_terminal_backend_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerminalBackendSelect"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/computer-use/status":{"get":{"summary":"Get Computer Use Status","description":"Cross-platform Computer Use readiness for the desktop card.\n\nSee ``tools.computer_use.permissions.computer_use_status`` for the payload\nshape. Read-only and fast (shells ``cua-driver doctor`` + macOS\n``permissions status``).","operationId":"get_computer_use_status_api_tools_computer_use_status_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/computer-use/permissions/grant":{"post":{"summary":"Grant Computer Use Permissions","description":"Spawn ``hermes computer-use permissions grant`` as a background action.\n\nmacOS-only: ``cua-driver permissions grant`` launches CuaDriver via\nLaunchServices so the TCC dialog is attributed to com.trycua.driver, then\nwaits for approval. The frontend polls ``GET /api/actions/computer-use-\ngrant/status`` and re-reads ``/status`` once it exits. Windows/Linux have\nno TCC toggles to grant, so this returns 400 there.","operationId":"grant_computer_use_permissions_api_tools_computer_use_permissions_grant_post","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config/raw":{"get":{"summary":"Get Config Raw","description":"Raw config.yaml text plus its resolved path.\n\n``path`` is resolved inside ``_profile_scope`` so the Config page header\nshows the file the switched profile actually reads/writes — /api/status's\n``config_path`` is machine-global and always reports the dashboard\nprocess's own profile, which is wrong under the global profile switcher.","operationId":"get_config_raw_api_config_raw_get","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Config Raw","operationId":"update_config_raw_api_config_raw_put","parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawConfigUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/usage":{"get":{"summary":"Get Usage Analytics","operationId":"get_usage_analytics_api_analytics_usage_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/models":{"get":{"summary":"Get Models Analytics","description":"Return model analytics without blocking the serving event loop.","operationId":"get_models_analytics_api_analytics_models_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/themes":{"get":{"summary":"Get Dashboard Themes","description":"Return available themes and the currently active one.\n\nBuilt-in entries ship name/label/description only (the frontend owns\ntheir full definitions in `web/src/themes/presets.ts`).  User themes\nfrom `~/.hermes/dashboard-themes/*.yaml` ship with their full\nnormalised definition under `definition`, so the client can apply\nthem without a stub.","operationId":"get_dashboard_themes_api_dashboard_themes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/dashboard/theme":{"put":{"summary":"Set Dashboard Theme","description":"Set the active dashboard theme (persists to config.yaml).","operationId":"set_dashboard_theme_api_dashboard_theme_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThemeSetBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/font":{"get":{"summary":"Get Dashboard Font","description":"Return the active font override (``\"theme\"`` = use the theme's font).","operationId":"get_dashboard_font_api_dashboard_font_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"put":{"summary":"Set Dashboard Font","description":"Set the dashboard font override (persists to config.yaml).\n\nAccepts any id in the curated catalog, or ``\"theme\"`` to clear the\noverride and fall back to the active theme's own font. Unknown ids are\ncoerced to ``\"theme\"`` rather than 400'd so a stale client can't wedge\nthe picker.","operationId":"set_dashboard_font_api_dashboard_font_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FontSetBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/plugins":{"get":{"summary":"Get Dashboard Plugins","description":"Return discovered dashboard plugins (excludes user-hidden and non-enabled ones).","operationId":"get_dashboard_plugins_api_dashboard_plugins_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/dashboard/plugins/rescan":{"get":{"summary":"Rescan Dashboard Plugins","description":"Force re-scan of dashboard plugins.","operationId":"rescan_dashboard_plugins_api_dashboard_plugins_rescan_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/dashboard/plugins/hub":{"get":{"summary":"Get Plugins Hub","description":"Unified agent plugins + dashboard extension metadata (session protected).","operationId":"get_plugins_hub_api_dashboard_plugins_hub_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/dashboard/agent-plugins/install":{"post":{"summary":"Post Agent Plugin Install","operationId":"post_agent_plugin_install_api_dashboard_agent_plugins_install_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_AgentPluginInstallBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/agent-plugins/{name}/enable":{"post":{"summary":"Post Agent Plugin Enable","operationId":"post_agent_plugin_enable_api_dashboard_agent_plugins__name__enable_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/agent-plugins/{name}/disable":{"post":{"summary":"Post Agent Plugin Disable","operationId":"post_agent_plugin_disable_api_dashboard_agent_plugins__name__disable_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/agent-plugins/{name}/update":{"post":{"summary":"Post Agent Plugin Update","operationId":"post_agent_plugin_update_api_dashboard_agent_plugins__name__update_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/agent-plugins/{name}":{"delete":{"summary":"Delete Agent Plugin","operationId":"delete_agent_plugin_api_dashboard_agent_plugins__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/plugin-providers":{"put":{"summary":"Put Plugin Providers","description":"Persist memory provider / context engine selection (writes config.yaml).","operationId":"put_plugin_providers_api_dashboard_plugin_providers_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_PluginProvidersPutBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/dashboard/plugins/{name}/visibility":{"post":{"summary":"Post Plugin Visibility","description":"Toggle a plugin's sidebar visibility (persists to config.yaml dashboard.hidden_plugins).","operationId":"post_plugin_visibility_api_dashboard_plugins__name__visibility_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_PluginVisibilityBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard-plugins/{plugin_name}/{file_path}":{"get":{"summary":"Serve Plugin Asset","description":"Serve static assets from a dashboard plugin directory.\n\nOnly serves files from the plugin's ``dashboard/`` subdirectory.\nPath traversal is blocked by checking ``resolve().is_relative_to()``.\n\nRestricted to a browser-fetchable suffix allowlist (JS/CSS/JSON/HTML/\nSVG/PNG/JPG/WOFF). The dashboard loads plugin JS via ``<script src>``\nand CSS via ``<link href>``, neither of which can attach a custom\nauth header — so this route stays unauthenticated to keep the SPA\nworking. But user-installed plugins ship a ``plugin_api.py``\nbackend module that the browser never fetches; it's only imported\nby :func:`_mount_plugin_api_routes` at startup. Without a suffix\nallowlist, anyone on the loopback port can curl the ``.py`` source\nof a private third-party plugin. Reject everything outside the\nbrowser-asset set.\n\nUser plugins must be in plugins.enabled before their assets are\nserved. (#46435, GHSA-mcfc-hp25-cjv7)","operationId":"serve_plugin_asset_dashboard_plugins__plugin_name___file_path__get","parameters":[{"name":"plugin_name","in":"path","required":true,"schema":{"type":"string","title":"Plugin Name"}},{"name":"file_path","in":"path","required":true,"schema":{"type":"string","title":"File Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/hermes-achievements/achievements":{"get":{"summary":"Achievements","operationId":"achievements_api_plugins_hermes_achievements_achievements_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/hermes-achievements/scan-status":{"get":{"summary":"Scan Status","operationId":"scan_status_api_plugins_hermes_achievements_scan_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/hermes-achievements/recent-unlocks":{"get":{"summary":"Recent Unlocks","operationId":"recent_unlocks_api_plugins_hermes_achievements_recent_unlocks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/hermes-achievements/sessions/{session_id}/badges":{"get":{"summary":"Session Badges","operationId":"session_badges_api_plugins_hermes_achievements_sessions__session_id__badges_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/hermes-achievements/rescan":{"post":{"summary":"Rescan","operationId":"rescan_api_plugins_hermes_achievements_rescan_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/hermes-achievements/reset-state":{"post":{"summary":"Reset State","operationId":"reset_state_api_plugins_hermes_achievements_reset_state_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/kanban/board":{"get":{"summary":"Get Board","description":"Return the full board grouped by status column.\n\n``_conn()`` auto-initializes ``kanban.db`` on first call so a fresh\ninstall doesn't surface a \"failed to load\" error on the plugin tab.\n\n``board`` selects which board to read from. Omitting it falls\nthrough to the active board (``HERMES_KANBAN_BOARD`` env → on-disk\n``current`` pointer → ``default``).","operationId":"get_board_api_plugins_kanban_board_get","parameters":[{"name":"tenant","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single tenant","title":"Tenant"},"description":"Filter to a single tenant"},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"},{"name":"workflow_template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Restrict to tasks using this workflow template id","title":"Workflow Template Id"},"description":"Restrict to tasks using this workflow template id"},{"name":"current_step_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Restrict to tasks at this workflow step key","title":"Current Step Key"},"description":"Restrict to tasks at this workflow step key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}":{"get":{"summary":"Get Task","operationId":"get_task_api_plugins_kanban_tasks__task_id__get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}},{"name":"run_state_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"With run_state_name: filter runs by column 'status' or 'outcome'","title":"Run State Type"},"description":"With run_state_name: filter runs by column 'status' or 'outcome'"},{"name":"run_state_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"With run_state_type: exact value for that run column","title":"Run State Name"},"description":"With run_state_type: exact value for that run column"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Update Task","operationId":"update_task_api_plugins_kanban_tasks__task_id__patch","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Task","operationId":"delete_task_api_plugins_kanban_tasks__task_id__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks":{"post":{"summary":"Create Task","operationId":"create_task_api_plugins_kanban_tasks_post","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/attachments":{"get":{"summary":"List Task Attachments","operationId":"list_task_attachments_api_plugins_kanban_tasks__task_id__attachments_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Upload Task Attachment","description":"Store an uploaded file for a task and record its metadata.\n\nThe blob lands under ``attachments_root(board)/<task_id>/`` with a\nsanitised, collision-resolved name. The worker reads it via the\nabsolute path surfaced in ``build_worker_context``.","operationId":"upload_task_attachment_api_plugins_kanban_tasks__task_id__attachments_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_task_attachment_api_plugins_kanban_tasks__task_id__attachments_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/attachments/{attachment_id}":{"get":{"summary":"Download Attachment","operationId":"download_attachment_api_plugins_kanban_attachments__attachment_id__get","parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"integer","title":"Attachment Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Remove Attachment","operationId":"remove_attachment_api_plugins_kanban_attachments__attachment_id__delete","parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"integer","title":"Attachment Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/comments":{"post":{"summary":"Add Comment","operationId":"add_comment_api_plugins_kanban_tasks__task_id__comments_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/links":{"post":{"summary":"Add Link","operationId":"add_link_api_plugins_kanban_links_post","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Link","operationId":"delete_link_api_plugins_kanban_links_delete","parameters":[{"name":"parent_id","in":"query","required":true,"schema":{"type":"string","title":"Parent Id"}},{"name":"child_id","in":"query","required":true,"schema":{"type":"string","title":"Child Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/bulk":{"post":{"summary":"Bulk Update","description":"Apply the same patch to every id in ``payload.ids``.\n\nThis is an *independent* iteration — per-task failures don't abort\nsiblings. Returns per-id outcome so the UI can surface partials.","operationId":"bulk_update_api_plugins_kanban_tasks_bulk_post","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkTaskBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/diagnostics":{"get":{"summary":"List Diagnostics","description":"Return ``[{task_id, task_title, task_status, task_assignee,\ndiagnostics: [...]}, ...]`` for every task on the board with at\nleast one active diagnostic.\n\nSeverity-filterable so the UI can render \"just the critical ones\"\nor the CLI can grep. Useful for the board-header attention strip\nAND for ``hermes kanban diagnostics`` which shells to this\nendpoint when the dashboard's running, or invokes the engine\ndirectly when it isn't.","operationId":"list_diagnostics_api_plugins_kanban_diagnostics_get","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by severity: warning|error|critical","title":"Severity"},"description":"Filter by severity: warning|error|critical"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/workers/active":{"get":{"summary":"List Active Workers","description":"Return every currently-running worker on the board.\n\nA worker is a ``task_runs`` row whose ``ended_at`` is NULL and whose\n``worker_pid`` is non-NULL, belonging to a task with ``status='running'``.\n\nReturns ``{workers: [...], count: N, checked_at: <epoch>}``.  Each\nworker entry carries enough context for the dashboard to link back to\nits task without a second round-trip.","operationId":"list_active_workers_api_plugins_kanban_workers_active_get","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/runs/{run_id}":{"get":{"summary":"Get Run Endpoint","description":"Direct lookup of a ``task_runs`` row by its integer id.\n\nReturns ``{run: {...}}`` using the same serialisation as the\nper-task run history embedded in ``GET /tasks/{task_id}``.\n404 when no such run exists.","operationId":"get_run_endpoint_api_plugins_kanban_runs__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/runs/{run_id}/inspect":{"get":{"summary":"Inspect Run Endpoint","description":"Live PID stats for a run's worker process via psutil.\n\nIf the run has already ended, or has no recorded ``worker_pid``,\nreturns ``{alive: false}`` with a human-readable ``reason``.\n\nWhen the process is live, returns CPU, memory, thread count, fd count,\nstatus, create_time, and cmdline.  ``access_denied`` is set when the\nOS refuses inspection rather than raising a 500.\n\npsutil availability: if psutil is not installed the endpoint still\nworks but ``alive`` is always returned as ``false`` with\n``reason=\"psutil not available\"``.","operationId":"inspect_run_endpoint_api_plugins_kanban_runs__run_id__inspect_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/runs/{run_id}/terminate":{"post":{"summary":"Terminate Run Endpoint","description":"Terminate the worker process backing an in-flight run.\n\nResolves ``run_id`` to its parent ``task_id`` and routes through\n:func:`kanban_db.reclaim_task` so the SIGTERM->SIGKILL flow,\nrun-outcome bookkeeping, and event-log append all match what the\nexisting ``POST /tasks/{task_id}/reclaim`` endpoint does.\n\nResponses:\n  * 200 ``{\"ok\": true, \"run_id\": ..., \"task_id\": ...}`` on success.\n  * 404 when ``run_id`` is unknown.\n  * 409 when the run has already ended, or the task is no longer in\n    a claimable state.\n\nCloses the gap left by PR #28432, which shipped the read-only\nsibling endpoints (``/workers/active``, ``/runs/{run_id}``,\n``/runs/{run_id}/inspect``) but no termination control surface.","operationId":"terminate_run_endpoint_api_plugins_kanban_runs__run_id__terminate_post","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kanban board slug (omit for current)","title":"Board"},"description":"Kanban board slug (omit for current)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerminateRunBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/reclaim":{"post":{"summary":"Reclaim Task Endpoint","description":"Release an active worker claim on a running task.\n\nUsed by the dashboard recovery popover when an operator wants to\nabort a stuck worker (e.g. one that keeps hallucinating card ids)\nwithout waiting for the claim TTL. Maps 1:1 to\n``hermes kanban reclaim <task_id> --reason ...``.","operationId":"reclaim_task_endpoint_api_plugins_kanban_tasks__task_id__reclaim_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReclaimBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/specify":{"post":{"summary":"Specify Task Endpoint","description":"Flesh out a triage-column task via the auxiliary LLM and promote\nit to ``todo``. Maps 1:1 to ``hermes kanban specify <task_id>``.\n\nReturns the outcome shape used by the CLI: ``{ok, task_id, reason,\nnew_title}``. A non-OK outcome is NOT an HTTP error — the UI renders\nthe reason inline (e.g. \"no auxiliary client configured\") so the\noperator knows what to fix, and retries without a page reload.\n\nThis endpoint runs in FastAPI's threadpool (sync ``def``) because\nthe underlying LLM call can take tens of seconds to minutes on\nreasoning models, which would block the event loop if we used\n``async def`` without an explicit ``run_in_executor``.","operationId":"specify_task_endpoint_api_plugins_kanban_tasks__task_id__specify_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecifyBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/reassign":{"post":{"summary":"Reassign Task Endpoint","description":"Reassign a task to a different profile, optionally reclaiming first.\n\nUsed by the dashboard recovery popover when an operator wants to\nretry a task with a different worker profile (e.g. switch to a\nsmarter model after the assigned profile keeps hallucinating).\nMaps 1:1 to ``hermes kanban reassign <task_id> <profile> [--reclaim]``.","operationId":"reassign_task_endpoint_api_plugins_kanban_tasks__task_id__reassign_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReassignBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/config":{"get":{"summary":"Get Config","description":"Return kanban dashboard preferences from ~/.hermes/config.yaml.\n\nReads the ``dashboard.kanban`` section if present; defaults otherwise.\nUsed by the UI to pre-select tenant filters, toggle markdown rendering,\nor set column-width preferences without a round-trip per page load.","operationId":"get_config_api_plugins_kanban_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/kanban/home-channels":{"get":{"summary":"Get Home Channels","description":"List every platform with a home channel, plus whether *task_id*\n(if given) is currently subscribed to that home.\n\nWhen ``task_id`` is omitted, every entry's ``subscribed`` is ``false``\n— useful for the \"no task selected\" state of the UI.","operationId":"get_home_channels_api_plugins_kanban_home_channels_get","parameters":[{"name":"task_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/home-subscribe/{platform}":{"post":{"summary":"Subscribe Home","description":"Subscribe *task_id* to notifications routed to *platform*'s home channel.\n\nIdempotent — re-subscribing is a no-op at the DB layer. 404 if the\nplatform has no home channel configured. 404 if the task doesn't exist.","operationId":"subscribe_home_api_plugins_kanban_tasks__task_id__home_subscribe__platform__post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Unsubscribe Home","description":"Remove any notify subscription on *task_id* that matches *platform*'s home.","operationId":"unsubscribe_home_api_plugins_kanban_tasks__task_id__home_subscribe__platform__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/stats":{"get":{"summary":"Get Stats","description":"Per-status + per-assignee counts + oldest-ready age.\n\nDesigned for the dashboard HUD and for router profiles that need to\nanswer \"is this specialist overloaded?\" without scanning the whole\nboard themselves.","operationId":"get_stats_api_plugins_kanban_stats_get","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/assignees":{"get":{"summary":"Get Assignees","description":"Known profiles + per-profile task counts.\n\nReturns the union of ``~/.hermes/profiles/*`` on disk and every\ndistinct assignee currently used on the board. The dashboard uses\nthis to populate its assignee dropdown so a freshly-created profile\nappears in the picker before it's been given any task.","operationId":"get_assignees_api_plugins_kanban_assignees_get","parameters":[{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/log":{"get":{"summary":"Get Task Log","description":"Return the worker's stdout/stderr log.\n\n``tail`` caps the response size (bytes) so the dashboard drawer\ndoesn't paginate megabytes into the browser. Returns 404 if the task\nhas never spawned. The on-disk log is rotated at 2 MiB per\n``_rotate_worker_log`` — a single ``.log.1`` is kept, no further\ngenerations, so disk usage per task is bounded at ~4 MiB.","operationId":"get_task_log_api_plugins_kanban_tasks__task_id__log_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"tail","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2000000,"minimum":1},{"type":"null"}],"title":"Tail"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/dispatch":{"post":{"summary":"Dispatch","operationId":"dispatch_api_plugins_kanban_dispatch_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dry Run"}},{"name":"max","in":"query","required":false,"schema":{"type":"integer","default":8,"title":"Max"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/boards":{"get":{"summary":"List Boards","description":"Return every board on disk with task counts and the active slug.","operationId":"list_boards_api_plugins_kanban_boards_get","parameters":[{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Board Endpoint","description":"Create a new board. Idempotent — ``slug`` collision returns existing.","operationId":"create_board_endpoint_api_plugins_kanban_boards_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBoardBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/boards/{slug}":{"patch":{"summary":"Rename Board","description":"Update a board's display metadata + default project directory (slug is immutable — create a new one to rename the directory).","operationId":"rename_board_api_plugins_kanban_boards__slug__patch","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameBoardBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Board","description":"Archive (default) or hard-delete a board.","operationId":"delete_board_api_plugins_kanban_boards__slug__delete","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"delete","in":"query","required":false,"schema":{"type":"boolean","description":"Hard-delete instead of archive","default":false,"title":"Delete"},"description":"Hard-delete instead of archive"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/boards/{slug}/switch":{"post":{"summary":"Switch Board","description":"Persist ``slug`` as the active board for subsequent CLI / slash calls.\n\nDashboard users pick boards via a client-side ``localStorage`` — this\nendpoint is for ``/kanban boards switch`` parity so gateway slash\ncommands and the CLI share the same current-board pointer.","operationId":"switch_board_api_plugins_kanban_boards__slug__switch_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/profiles":{"get":{"summary":"List Profile Roster","description":"Return every installed profile with its description.\n\nConsumed by the dashboard's settings panel (orchestrator picker)\nand the profile-description editing UI. Profiles without a\ndescription still appear here — they're routable on name alone,\njust less precisely.","operationId":"list_profile_roster_api_plugins_kanban_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plugins/kanban/profiles/{profile_name}":{"patch":{"summary":"Update Profile Description","description":"Set or clear the description of a profile.\n\nEmpty string clears the description; non-empty stores it as a\nuser-authored description (``description_auto: false``) so the\nauto-describer won't overwrite it on a sweep without\n``--overwrite``.","operationId":"update_profile_description_api_plugins_kanban_profiles__profile_name__patch","parameters":[{"name":"profile_name","in":"path","required":true,"schema":{"type":"string","title":"Profile Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DescribeBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/profiles/{profile_name}/describe-auto":{"post":{"summary":"Auto Describe Profile","description":"Generate a description for the named profile via the auxiliary\nLLM (``auxiliary.profile_describer``). Persists with\n``description_auto: true`` so the dashboard can surface a \"review\"\nbadge.\n\nMaps 1:1 to ``hermes profile describe <name> --auto``. Non-OK\noutcomes are NOT HTTP errors — the UI renders the reason inline\n(e.g. \"no auxiliary client configured\") so the operator can fix\nconfig and retry without a page reload.","operationId":"auto_describe_profile_api_plugins_kanban_profiles__profile_name__describe_auto_post","parameters":[{"name":"profile_name","in":"path","required":true,"schema":{"type":"string","title":"Profile Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DescribeAutoBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/tasks/{task_id}/decompose":{"post":{"summary":"Decompose Task Endpoint","description":"Fan a triage-column task out into a graph of child tasks via the\nauxiliary LLM, routed to specialist profiles by description. Maps\n1:1 to ``hermes kanban decompose <task_id>``.\n\nReturns the outcome shape used by the CLI: ``{ok, task_id, reason,\nfanout, child_ids, new_title}``. A non-OK outcome is NOT an HTTP\nerror — the UI renders the reason inline.\n\nRuns in FastAPI's threadpool (sync ``def``) because the LLM call\ncan take minutes on reasoning models.","operationId":"decompose_task_endpoint_api_plugins_kanban_tasks__task_id__decompose_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"board","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecomposeBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plugins/kanban/orchestration":{"get":{"summary":"Get Orchestration Settings","description":"Return the current kanban orchestration knobs from config.yaml\nplus the resolved effective values (filling in fallbacks).","operationId":"get_orchestration_settings_api_plugins_kanban_orchestration_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"put":{"summary":"Set Orchestration Settings","description":"Update the kanban orchestration knobs in ~/.hermes/config.yaml.\n\nEach field is optional — only fields explicitly passed are\nwritten. ``orchestrator_profile`` / ``default_assignee`` accept\nempty strings to clear the override and fall back to the default\nprofile.","operationId":"set_orchestration_settings_api_plugins_kanban_orchestration_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrchestrationSettingsBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login":{"get":{"summary":"Login Page","operationId":"login_page_login_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/auth/providers":{"get":{"summary":"Auth Providers","operationId":"auth_providers_api_auth_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Auth Providers Api Auth Providers Get"}}}}}}},"/auth/login":{"get":{"summary":"Auth Login","operationId":"auth_login_auth_login_get","parameters":[{"name":"provider","in":"query","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"next","in":"query","required":false,"schema":{"type":"string","default":"","title":"Next"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/callback":{"get":{"summary":"Auth Callback","operationId":"auth_callback_auth_callback_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string","default":"","title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"","title":"State"}},{"name":"error","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error"}},{"name":"error_description","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error Description"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/password-login":{"post":{"summary":"Auth Password Login","description":"Authenticate a username/password against a password provider.\n\nMirrors the cookie-minting tail of ``/auth/callback`` but skips the\nPKCE/state/code machinery (those are OAuth-only). On success sets the\nsession cookies and returns JSON ``{\"ok\": true, \"next\": <path>}`` —\nthe credential form POSTs via fetch and navigates client-side, so a\n302 (which fetch follows opaquely) is the wrong shape here.\n\nFailure modes, all deliberately generic so the endpoint can't be used\nas a username oracle or a provider-enumeration oracle:\n  * unknown provider / provider lacks password support → 404\n  * bad credentials → 401 (\"Invalid credentials\")\n  * backing store unreachable → 503\n  * too many attempts from this IP → 429","operationId":"auth_password_login_auth_password_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_PasswordLoginBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"summary":"Auth Logout","operationId":"auth_logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/auth/me":{"get":{"summary":"Auth Me","description":"Return the verified session as JSON. Auth-required (gate enforces).","operationId":"auth_me_api_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/auth/ws-ticket":{"post":{"summary":"Auth Ws Ticket","description":"Mint a short-lived single-use ticket for the authenticated session.\n\nBrowsers cannot set ``Authorization`` on a WebSocket upgrade, so in\ngated mode the SPA POSTs this endpoint to get a ``?ticket=`` value to\nappend to ``/api/pty``, ``/api/console``, ``/api/ws``, ``/api/pub``, or\n``/api/events``.\n\nThe ticket has a 30-second TTL and is single-use. Calling this endpoint\nmultiple times in quick succession (e.g. one ticket per WS) is the\nexpected pattern.","operationId":"auth_ws_ticket_api_auth_ws_ticket_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/assets/{filename}.css":{"get":{"summary":"Serve Css","operationId":"serve_css_assets__filename__css_get","parameters":[{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{full_path}":{"get":{"summary":"Serve Spa","operationId":"serve_spa__full_path__get","parameters":[{"name":"full_path","in":"path","required":true,"schema":{"type":"string","title":"Full Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AudioTranscriptionRequest":{"properties":{"data_url":{"type":"string","title":"Data Url"},"mime_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mime Type"}},"type":"object","required":["data_url"],"title":"AudioTranscriptionRequest"},"AutomationBlueprintInstantiate":{"properties":{"blueprint":{"type":"string","title":"Blueprint"},"values":{"additionalProperties":true,"type":"object","title":"Values","default":{}}},"type":"object","required":["blueprint"],"title":"AutomationBlueprintInstantiate"},"BackupRequest":{"properties":{"output":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output"}},"type":"object","title":"BackupRequest"},"Body_run_import_upload_api_ops_import_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","required":["file"],"title":"Body_run_import_upload_api_ops_import_upload_post"},"Body_upload_managed_file_stream_api_files_upload_stream_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"path":{"type":"string","title":"Path"},"overwrite":{"type":"boolean","title":"Overwrite","default":true}},"type":"object","required":["file","path"],"title":"Body_upload_managed_file_stream_api_files_upload_stream_post"},"Body_upload_task_attachment_api_plugins_kanban_tasks__task_id__attachments_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"uploaded_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploaded By"}},"type":"object","required":["file"],"title":"Body_upload_task_attachment_api_plugins_kanban_tasks__task_id__attachments_post"},"BulkDeleteSessions":{"properties":{"ids":{"items":{"type":"string"},"type":"array","title":"Ids"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["ids"],"title":"BulkDeleteSessions"},"BulkTaskBody":{"properties":{"ids":{"items":{"type":"string"},"type":"array","title":"Ids"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"},"priority":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Priority"},"archive":{"type":"boolean","title":"Archive","default":false},"result":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"reclaim_first":{"type":"boolean","title":"Reclaim First","default":false}},"type":"object","required":["ids"],"title":"BulkTaskBody"},"ChatImageUpload":{"properties":{"data_url":{"type":"string","title":"Data Url"},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"}},"type":"object","required":["data_url"],"title":"ChatImageUpload"},"CommentBody":{"properties":{"body":{"type":"string","title":"Body"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author","default":"dashboard"}},"type":"object","required":["body"],"title":"CommentBody"},"ConfigUpdate":{"properties":{"config":{"additionalProperties":true,"type":"object","title":"Config"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["config"],"title":"ConfigUpdate"},"CreateBoardBody":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"default_workdir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Workdir"},"switch":{"type":"boolean","title":"Switch","default":false}},"type":"object","required":["slug"],"title":"CreateBoardBody"},"CreateTaskBody":{"properties":{"title":{"type":"string","title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"},"assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"},"tenant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant"},"priority":{"type":"integer","title":"Priority","default":0},"workspace_kind":{"type":"string","title":"Workspace Kind","default":"scratch"},"workspace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Path"},"parents":{"items":{"type":"string"},"type":"array","title":"Parents"},"triage":{"type":"boolean","title":"Triage","default":false},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key"},"max_runtime_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Runtime Seconds"},"skills":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skills"},"goal_mode":{"type":"boolean","title":"Goal Mode","default":false},"goal_max_turns":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Goal Max Turns"}},"type":"object","required":["title"],"title":"CreateTaskBody"},"CredentialPoolAdd":{"properties":{"provider":{"type":"string","title":"Provider"},"api_key":{"type":"string","title":"Api Key"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","required":["provider","api_key"],"title":"CredentialPoolAdd"},"CronJobCreate":{"properties":{"prompt":{"type":"string","title":"Prompt","default":""},"schedule":{"type":"string","title":"Schedule"},"name":{"type":"string","title":"Name","default":""},"deliver":{"type":"string","title":"Deliver","default":"local"},"skills":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skills"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url"},"script":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Script"},"context_from":{"anyOf":[{},{"type":"null"}],"title":"Context From"},"enabled_toolsets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Enabled Toolsets"},"workdir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workdir"},"no_agent":{"type":"boolean","title":"No Agent","default":false}},"type":"object","required":["schedule"],"title":"CronJobCreate"},"CronJobUpdate":{"properties":{"updates":{"additionalProperties":true,"type":"object","title":"Updates"}},"type":"object","required":["updates"],"title":"CronJobUpdate"},"CuratorPause":{"properties":{"paused":{"type":"boolean","title":"Paused"}},"type":"object","required":["paused"],"title":"CuratorPause"},"CustomEndpointUpdate":{"properties":{"id":{"type":"string","title":"Id","default":""},"name":{"type":"string","title":"Name"},"base_url":{"type":"string","title":"Base Url"},"model":{"type":"string","title":"Model"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"},"context_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Context Length"},"discover_models":{"type":"boolean","title":"Discover Models","default":true},"make_default":{"type":"boolean","title":"Make Default","default":false}},"type":"object","required":["name","base_url","model"],"title":"CustomEndpointUpdate"},"DebugShareRequest":{"properties":{"redact":{"type":"boolean","title":"Redact","default":true},"lines":{"type":"integer","title":"Lines","default":200}},"type":"object","title":"DebugShareRequest"},"DecomposeBody":{"properties":{"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"}},"type":"object","title":"DecomposeBody"},"DescribeAutoBody":{"properties":{"overwrite":{"type":"boolean","title":"Overwrite","default":false}},"type":"object","title":"DescribeAutoBody"},"DescribeBody":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"DescribeBody"},"EnvVarDelete":{"properties":{"key":{"type":"string","title":"Key"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["key"],"title":"EnvVarDelete"},"EnvVarReveal":{"properties":{"key":{"type":"string","title":"Key"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["key"],"title":"EnvVarReveal"},"EnvVarUpdate":{"properties":{"key":{"type":"string","title":"Key"},"value":{"type":"string","title":"Value"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"},"api_key":{"type":"string","title":"Api Key","default":""}},"type":"object","required":["key","value"],"title":"EnvVarUpdate"},"FontSetBody":{"properties":{"font":{"type":"string","title":"Font"}},"type":"object","required":["font"],"title":"FontSetBody"},"FsWriteText":{"properties":{"path":{"type":"string","title":"Path"},"content":{"type":"string","title":"Content"}},"type":"object","required":["path","content"],"title":"FsWriteText"},"GitBranchSwitchBody":{"properties":{"path":{"type":"string","title":"Path"},"branch":{"type":"string","title":"Branch"}},"type":"object","required":["path","branch"],"title":"GitBranchSwitchBody"},"GitCommitBody":{"properties":{"path":{"type":"string","title":"Path"},"message":{"type":"string","title":"Message"},"push":{"type":"boolean","title":"Push","default":false}},"type":"object","required":["path","message"],"title":"GitCommitBody"},"GitFileBody":{"properties":{"path":{"type":"string","title":"Path"},"file":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File"}},"type":"object","required":["path"],"title":"GitFileBody"},"GitPathBody":{"properties":{"path":{"type":"string","title":"Path"}},"type":"object","required":["path"],"title":"GitPathBody"},"GitWorktreeAddBody":{"properties":{"path":{"type":"string","title":"Path"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"branch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch"},"base":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"},"existingBranch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Existingbranch"}},"type":"object","required":["path"],"title":"GitWorktreeAddBody"},"GitWorktreeRemoveBody":{"properties":{"path":{"type":"string","title":"Path"},"worktreePath":{"type":"string","title":"Worktreepath"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","required":["path","worktreePath"],"title":"GitWorktreeRemoveBody"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HookCreate":{"properties":{"event":{"type":"string","title":"Event"},"command":{"type":"string","title":"Command"},"matcher":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matcher"},"timeout":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timeout"},"approve":{"type":"boolean","title":"Approve","default":true}},"type":"object","required":["event","command"],"title":"HookCreate"},"HookDelete":{"properties":{"event":{"type":"string","title":"Event"},"command":{"type":"string","title":"Command"}},"type":"object","required":["event","command"],"title":"HookDelete"},"ImportRequest":{"properties":{"archive":{"type":"string","title":"Archive"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","required":["archive"],"title":"ImportRequest"},"LearningNodeEdit":{"properties":{"id":{"type":"string","title":"Id"},"content":{"type":"string","title":"Content"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["id","content"],"title":"LearningNodeEdit"},"LearningNodeRef":{"properties":{"id":{"type":"string","title":"Id"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["id"],"title":"LearningNodeRef"},"LinkBody":{"properties":{"parent_id":{"type":"string","title":"Parent Id"},"child_id":{"type":"string","title":"Child Id"}},"type":"object","required":["parent_id","child_id"],"title":"LinkBody"},"MCPCatalogInstall":{"properties":{"name":{"type":"string","title":"Name"},"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env","default":{}},"enable":{"type":"boolean","title":"Enable","default":true},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name"],"title":"MCPCatalogInstall"},"MCPEnabledToggle":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["enabled"],"title":"MCPEnabledToggle"},"MCPServerCreate":{"properties":{"name":{"type":"string","title":"Name"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"command":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command"},"args":{"items":{"type":"string"},"type":"array","title":"Args","default":[]},"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env","default":{}},"auth":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Auth"},"bearer_token":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Bearer Token"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name"],"title":"MCPServerCreate"},"MCPServersReplace":{"properties":{"servers":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Servers","default":{}},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"MCPServersReplace"},"ManagedDirectoryCreate":{"properties":{"path":{"type":"string","title":"Path"}},"type":"object","required":["path"],"title":"ManagedDirectoryCreate"},"ManagedFileDelete":{"properties":{"path":{"type":"string","title":"Path"},"recursive":{"type":"boolean","title":"Recursive","default":false}},"type":"object","required":["path"],"title":"ManagedFileDelete"},"ManagedFileUpload":{"properties":{"path":{"type":"string","title":"Path"},"data_url":{"type":"string","title":"Data Url"},"overwrite":{"type":"boolean","title":"Overwrite","default":true}},"type":"object","required":["path","data_url"],"title":"ManagedFileUpload"},"MemoryProviderConfigUpdate":{"properties":{"values":{"additionalProperties":true,"type":"object","title":"Values","default":{}}},"type":"object","title":"MemoryProviderConfigUpdate"},"MemoryProviderSelect":{"properties":{"provider":{"type":"string","title":"Provider"}},"type":"object","required":["provider"],"title":"MemoryProviderSelect"},"MemoryProviderSetupRequest":{"properties":{"values":{"additionalProperties":true,"type":"object","title":"Values","default":{}}},"type":"object","title":"MemoryProviderSetupRequest"},"MemoryReset":{"properties":{"target":{"type":"string","title":"Target","default":"all"}},"type":"object","title":"MemoryReset"},"MessagingPlatformUpdate":{"properties":{"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env","default":{}},"clear_env":{"items":{"type":"string"},"type":"array","title":"Clear Env","default":[]},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"MessagingPlatformUpdate"},"MoaConfigPayload":{"properties":{"default_preset":{"type":"string","title":"Default Preset","default":"default"},"active_preset":{"type":"string","title":"Active Preset","default":""},"presets":{"additionalProperties":{"$ref":"#/components/schemas/MoaPresetPayload"},"type":"object","title":"Presets","default":{}},"reference_models":{"items":{"$ref":"#/components/schemas/MoaModelSlot"},"type":"array","title":"Reference Models","default":[]},"aggregator":{"$ref":"#/components/schemas/MoaModelSlot","default":{"provider":"","model":""}},"reference_temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Reference Temperature"},"aggregator_temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregator Temperature"},"max_tokens":{"type":"integer","title":"Max Tokens","default":4096},"reference_max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reference Max Tokens"},"fanout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fanout"},"enabled":{"type":"boolean","title":"Enabled","default":true},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"MoaConfigPayload"},"MoaModelSlot":{"properties":{"provider":{"type":"string","title":"Provider","default":""},"model":{"type":"string","title":"Model","default":""},"reasoning_effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Effort"}},"type":"object","title":"MoaModelSlot"},"MoaPresetPayload":{"properties":{"reference_models":{"items":{"$ref":"#/components/schemas/MoaModelSlot"},"type":"array","title":"Reference Models","default":[]},"aggregator":{"$ref":"#/components/schemas/MoaModelSlot","default":{"provider":"","model":""}},"reference_temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Reference Temperature"},"aggregator_temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregator Temperature"},"max_tokens":{"type":"integer","title":"Max Tokens","default":4096},"reference_max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reference Max Tokens"},"fanout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fanout"},"enabled":{"type":"boolean","title":"Enabled","default":true}},"type":"object","title":"MoaPresetPayload"},"ModelAssignment":{"properties":{"scope":{"type":"string","title":"Scope"},"provider":{"type":"string","title":"Provider"},"model":{"type":"string","title":"Model"},"task":{"type":"string","title":"Task","default":""},"base_url":{"type":"string","title":"Base Url","default":""},"api_key":{"type":"string","title":"Api Key","default":""},"confirm_expensive_model":{"type":"boolean","title":"Confirm Expensive Model","default":false},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["scope","provider","model"],"title":"ModelAssignment","description":"Payload for POST /api/model/set — assign a provider/model to a slot.\n\nscope=\"main\"        → writes model.provider + model.default\nscope=\"auxiliary\"   → writes auxiliary.<task>.provider + auxiliary.<task>.model\nscope=\"auxiliary\" with task=\"\"  → applied to every auxiliary.* slot\nscope=\"auxiliary\" with task=\"__reset__\"  → resets every slot to provider=\"auto\""},"OAuthSubmitBody":{"properties":{"session_id":{"type":"string","title":"Session Id"},"code":{"type":"string","title":"Code"}},"type":"object","required":["session_id","code"],"title":"OAuthSubmitBody"},"OrchestrationSettingsBody":{"properties":{"orchestrator_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Orchestrator Profile"},"default_assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Assignee"},"auto_decompose":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Decompose"},"auto_promote_children":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Promote Children"}},"type":"object","title":"OrchestrationSettingsBody"},"PairingApprove":{"properties":{"platform":{"type":"string","title":"Platform"},"code":{"type":"string","title":"Code"}},"type":"object","required":["platform","code"],"title":"PairingApprove"},"PairingRevoke":{"properties":{"platform":{"type":"string","title":"Platform"},"user_id":{"type":"string","title":"User Id"}},"type":"object","required":["platform","user_id"],"title":"PairingRevoke"},"ProfileActiveUpdate":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"ProfileActiveUpdate"},"ProfileCreate":{"properties":{"name":{"type":"string","title":"Name"},"clone_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clone From"},"clone_from_default":{"type":"boolean","title":"Clone From Default","default":false},"clone_all":{"type":"boolean","title":"Clone All","default":false},"no_skills":{"type":"boolean","title":"No Skills","default":false},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"mcp_servers":{"items":{"$ref":"#/components/schemas/MCPServerCreate"},"type":"array","title":"Mcp Servers","default":[]},"keep_skills":{"items":{"type":"string"},"type":"array","title":"Keep Skills","default":[]},"hub_skills":{"items":{"type":"string"},"type":"array","title":"Hub Skills","default":[]}},"type":"object","required":["name"],"title":"ProfileCreate"},"ProfileDescribeAuto":{"properties":{"overwrite":{"type":"boolean","title":"Overwrite","default":false}},"type":"object","title":"ProfileDescribeAuto"},"ProfileDescriptionUpdate":{"properties":{"description":{"type":"string","title":"Description","default":""}},"type":"object","title":"ProfileDescriptionUpdate"},"ProfileModelUpdate":{"properties":{"provider":{"type":"string","title":"Provider"},"model":{"type":"string","title":"Model"}},"type":"object","required":["provider","model"],"title":"ProfileModelUpdate"},"ProfileRename":{"properties":{"new_name":{"type":"string","title":"New Name"}},"type":"object","required":["new_name"],"title":"ProfileRename"},"ProfileSoulUpdate":{"properties":{"content":{"type":"string","title":"Content"}},"type":"object","required":["content"],"title":"ProfileSoulUpdate"},"RawConfigUpdate":{"properties":{"yaml_text":{"type":"string","title":"Yaml Text"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["yaml_text"],"title":"RawConfigUpdate"},"ReassignBody":{"properties":{"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"},"reclaim_first":{"type":"boolean","title":"Reclaim First","default":false},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"ReassignBody"},"ReclaimBody":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"ReclaimBody"},"RenameBoardBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"default_workdir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Workdir"}},"type":"object","title":"RenameBoardBody"},"SessionPrune":{"properties":{"older_than_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Older Than Days","default":90},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"},"started_before":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started Before"},"started_after":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started After"},"title_like":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Like"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Reason"},"cwd_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd Prefix"},"min_messages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Messages"},"max_messages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Messages"},"model_like":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Like"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"chat_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chat Id"},"chat_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chat Type"},"branch_like":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch Like"},"min_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Tokens"},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"min_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Cost"},"max_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Cost"},"min_tool_calls":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Tool Calls"},"max_tool_calls":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tool Calls"},"include_archived":{"type":"boolean","title":"Include Archived","default":false},"dry_run":{"type":"boolean","title":"Dry Run","default":false}},"type":"object","title":"SessionPrune"},"SessionRename":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"archived":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Archived"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"SessionRename"},"SkillContentUpdate":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name","content"],"title":"SkillContentUpdate"},"SkillCreate":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name","content"],"title":"SkillCreate"},"SkillInstallRequest":{"properties":{"identifier":{"type":"string","title":"Identifier"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["identifier"],"title":"SkillInstallRequest"},"SkillToggle":{"properties":{"name":{"type":"string","title":"Name"},"enabled":{"type":"boolean","title":"Enabled"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name","enabled"],"title":"SkillToggle"},"SkillUninstallRequest":{"properties":{"name":{"type":"string","title":"Name"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["name"],"title":"SkillUninstallRequest"},"SkillsUpdateRequest":{"properties":{"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"SkillsUpdateRequest"},"SpecifyBody":{"properties":{"author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author"}},"type":"object","title":"SpecifyBody","description":"Optional author override. Nothing else is configurable from the\ndashboard — model + prompt come from ``auxiliary.triage_specifier``\nin config.yaml, same as the CLI."},"TTSSpeakRequest":{"properties":{"text":{"type":"string","title":"Text"}},"type":"object","required":["text"],"title":"TTSSpeakRequest"},"TelegramOnboardingApply":{"properties":{"allowed_user_ids":{"items":{"type":"string"},"type":"array","title":"Allowed User Ids"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["allowed_user_ids"],"title":"TelegramOnboardingApply"},"TelegramOnboardingStart":{"properties":{"bot_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Name"}},"type":"object","title":"TelegramOnboardingStart"},"TerminalBackendSelect":{"properties":{"backend":{"type":"string","title":"Backend"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["backend"],"title":"TerminalBackendSelect"},"TerminateRunBody":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"TerminateRunBody"},"ThemeSetBody":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"ThemeSetBody"},"ToolsetEnvUpdate":{"properties":{"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["env"],"title":"ToolsetEnvUpdate"},"ToolsetModelSelect":{"properties":{"model":{"type":"string","title":"Model"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["model"],"title":"ToolsetModelSelect"},"ToolsetPostSetup":{"properties":{"key":{"type":"string","title":"Key"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["key"],"title":"ToolsetPostSetup"},"ToolsetProviderSelect":{"properties":{"provider":{"type":"string","title":"Provider"},"capability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Capability"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["provider"],"title":"ToolsetProviderSelect"},"ToolsetToggle":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","required":["enabled"],"title":"ToolsetToggle"},"UpdateTaskBody":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"assignee":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Assignee"},"priority":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Priority"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"},"result":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result"},"block_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Block Reason"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","title":"UpdateTaskBody"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookCreate":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"events":{"items":{"type":"string"},"type":"array","title":"Events","default":[]},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt"},"script":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Script"},"skills":{"items":{"type":"string"},"type":"array","title":"Skills","default":[]},"deliver":{"type":"string","title":"Deliver","default":"log"},"deliver_only":{"type":"boolean","title":"Deliver Only","default":false},"deliver_chat_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deliver Chat Id"},"secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secret"}},"type":"object","required":["name"],"title":"WebhookCreate"},"WebhookEnabledToggle":{"properties":{"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["enabled"],"title":"WebhookEnabledToggle"},"WhatsAppOnboardingApply":{"properties":{"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"},"allowed_users":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Allowed Users"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"WhatsAppOnboardingApply"},"WhatsAppOnboardingStart":{"properties":{"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode","default":"bot"},"allowed_users":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Allowed Users","default":""},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"}},"type":"object","title":"WhatsAppOnboardingStart"},"_AgentPluginInstallBody":{"properties":{"identifier":{"type":"string","title":"Identifier"},"force":{"type":"boolean","title":"Force","default":false},"enable":{"type":"boolean","title":"Enable","default":true}},"type":"object","required":["identifier"],"title":"_AgentPluginInstallBody"},"_PasswordLoginBody":{"properties":{"provider":{"type":"string","title":"Provider"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"next":{"type":"string","title":"Next","default":""}},"type":"object","required":["provider","username","password"],"title":"_PasswordLoginBody"},"_PluginProvidersPutBody":{"properties":{"memory_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Memory Provider"},"context_engine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context Engine"}},"type":"object","title":"_PluginProvidersPutBody"},"_PluginVisibilityBody":{"properties":{"hidden":{"type":"boolean","title":"Hidden"}},"type":"object","required":["hidden"],"title":"_PluginVisibilityBody"}}}}