'Set as active' on the Profiles page only flips the sticky active_profile
file (future CLI/gateway runs) — it never retargets the running dashboard
process. The skills/toolsets endpoints called bare load_config()/
save_config(), so after 'activating' a profile in the web UI, deactivating
a skill silently wrote into the dashboard's own profile and the activated
profile was untouched.
Backend:
- _profile_scope() context manager on the skills/toolsets endpoints:
context-local HERMES_HOME override for call-time config resolution +
cron-style locked swap of tools.skills_tool's import-time SKILLS_DIR
- profile param on /api/skills, /api/skills/toggle, /api/tools/toolsets*
(list/toggle/config/provider/env), hub sources/search installed-state
- hub install/uninstall/update spawn 'hermes -p <profile> skills ...' so
the child rebinds skills_hub.SKILLS_DIR at import (the override cannot
reach import-time globals); profile validated -> 404/400 before spawn
Frontend:
- Skills page: profile selector (deep-linkable /skills?profile=<name>),
amber banner naming the managed profile, threaded through skill toggles,
toolset drawer, and hub browser
- Profiles page: 'Manage skills & tools' action per card; 'Set as active'
toast now says it applies to new CLI/gateway runs only
Omitted profile keeps legacy behavior (dashboard's own profile).
Replicate the `hermes tools` configurator in the dashboard Skills →
Toolsets view. Each toolset now opens a config drawer that covers the
full lifecycle the CLI offers: enable/disable, pick a provider/backend,
enter and save API keys, and run a provider's post-setup install hook
with a live log tail.
The toolset view was previously read+toggle only — the provider matrix
and key-status endpoints existed but the page never called them, and
there was no way to save a key or run a backend install (npm/pip/binary)
from the browser.
Backend:
- New CLI subcommand `hermes tools post-setup <KEY>` — non-interactive,
scriptable target that runs a provider's install hook (agent_browser,
camofox, cua_driver, kittentts, piper, ddgs, spotify, langfuse,
xai_grok). Validated against valid_post_setup_keys() so an arbitrary
key can't drive _run_post_setup.
- PUT /api/tools/toolsets/{name}/env — save API keys to ~/.hermes/.env
via save_env_value (same store the CLI writes), validated against the
toolset category's env-var allowlist; blank values skipped.
- POST /api/tools/toolsets/{name}/post-setup — spawn-action that runs
`hermes tools post-setup <key>`; frontend tails the log via the
existing /api/actions/tools-post-setup/status. Registered in
_ACTION_LOG_FILES.
Frontend:
- New ToolsetConfigDrawer component (provider radios, password key
inputs with saved-state, get-a-key links, Run-setup + live install
log). Toolset cards get a Configure button + the drawer also exposes
the enable toggle.
- api.ts: toggleToolset, getToolsetConfig, selectToolsetProvider,
saveToolsetEnv, runToolsetPostSetup + ToolsetConfig/Provider/EnvVar/
EnvResult types.
Validation: 56 admin-endpoint tests pass (10 new: env save w/ CLI
parity + allowlist reject + blank-skip, post-setup spawn validation,
auth gate); 232 web_server tests pass; web npm run build + eslint clean;
HTTP E2E exercises save-key (CLI reads it back) and spawn+poll
post-setup to exit 0.