feat: profiles.list/profiles.create ws RPC + plugin session-navigation doors - #85093
Merged
Merged
Conversation
…n doors Desktop plugins reach the backend exclusively through the generic ws JSON-RPC door (host.request), but profile enumeration/creation only existed on the dashboard REST router, which plugins cannot reach — so anything 'one chat per agent profile'-shaped (bot rosters, profile pickers, team panes) was impossible to build as a plugin. - tui_gateway/methods_profiles.py: new @method handlers * profiles.list — profiles + optional last_session preview per profile (mirrors session.list's kanban/tool deny-list; best-effort per-profile state.db probe degrades to null instead of failing the call) * profiles.create — ws twin of POST /api/profiles (clone_from/clone_all/ no_skills/description), plus optional SOUL.md content and a best-effort model+provider pin; mirrors the CLI flow (seed skills, safe alias) Both run on the RPC pool, not the WS reader thread (list_profiles walks skill trees; create copies bundles). - SDK: host.openSession(id, { profile, intent }) — open a stored session the way core surfaces do, soft-swapping to the owning profile's backend first (ensureGatewayProfile), and host.newChat(profile) — fresh draft in a named profile (same door as the sidebar's per-profile '+'). - Docs: desktop-plugin-sdk.md gains both surfaces. First consumer: a Grok Bot-style 'Bots' roster plugin (one persistent chat per agent profile with a New Agent dialog) built on exactly these four doors.
Contributor
૮ >ﻌ< ა ci reviewran on da118f6 — feat: profiles.list/profiles.create ws RPC + plugin session-
|
teknium1
added a commit
that referenced
this pull request
Aug 13, 2026
…un (#85111) A profile created through the headless ws door (profiles.create, #85093) was born with no inference provider: create_profile() seeds a comment-only .env, never copies auth.json, and a fresh profile has no config.yaml. Its first message failed with 'No inference provider configured' and the flow has no interactive setup step to recover with. New mirror_credentials param (default true): copy the launch profile's .env (only over the seeded stub — never clobber cloned secrets) and auth.json (only when absent), both chmod 600, and inherit model.provider/model.default when the caller gave no explicit pin and no config was cloned. mirror_credentials:false preserves the old isolated behavior byte-for-byte. Result gains a mirrored:{env,auth,model_inherited} receipt. CLI and REST create paths untouched.
This was referenced Aug 13, 2026
teknium1
added a commit
that referenced
this pull request
Aug 13, 2026
…#85216) profiles.list/create (#85093) let plugins enumerate and create profiles but not read or modify an existing profile's configuration over ws. profiles.describe returns the full editor snapshot (description, SOUL.md, model pin, per-skill enablement via the disabled-list model, per-toolset enablement via the tools.enabled_toolsets pin); profiles.configure applies any subset (description via write_profile_meta, soul, model via _write_profile_model, disabled_skills replace-semantics via save_disabled_skills, enabled_toolsets replace-semantics with empty-list clearing the pin) independently and best-effort, reporting per-section results. Both scoped via the HERMES_HOME override and pool-dispatched.
This was referenced Aug 14, 2026
Merged
skappafrost
pushed a commit
to skappafrost/hermes-agent
that referenced
this pull request
Aug 15, 2026
…n doors (NousResearch#85093) Desktop plugins reach the backend exclusively through the generic ws JSON-RPC door (host.request), but profile enumeration/creation only existed on the dashboard REST router, which plugins cannot reach — so anything 'one chat per agent profile'-shaped (bot rosters, profile pickers, team panes) was impossible to build as a plugin. - tui_gateway/methods_profiles.py: new @method handlers * profiles.list — profiles + optional last_session preview per profile (mirrors session.list's kanban/tool deny-list; best-effort per-profile state.db probe degrades to null instead of failing the call) * profiles.create — ws twin of POST /api/profiles (clone_from/clone_all/ no_skills/description), plus optional SOUL.md content and a best-effort model+provider pin; mirrors the CLI flow (seed skills, safe alias) Both run on the RPC pool, not the WS reader thread (list_profiles walks skill trees; create copies bundles). - SDK: host.openSession(id, { profile, intent }) — open a stored session the way core surfaces do, soft-swapping to the owning profile's backend first (ensureGatewayProfile), and host.newChat(profile) — fresh draft in a named profile (same door as the sidebar's per-profile '+'). - Docs: desktop-plugin-sdk.md gains both surfaces. First consumer: a Grok Bot-style 'Bots' roster plugin (one persistent chat per agent profile with a New Agent dialog) built on exactly these four doors.
skappafrost
pushed a commit
to skappafrost/hermes-agent
that referenced
this pull request
Aug 15, 2026
…un (NousResearch#85111) A profile created through the headless ws door (profiles.create, NousResearch#85093) was born with no inference provider: create_profile() seeds a comment-only .env, never copies auth.json, and a fresh profile has no config.yaml. Its first message failed with 'No inference provider configured' and the flow has no interactive setup step to recover with. New mirror_credentials param (default true): copy the launch profile's .env (only over the seeded stub — never clobber cloned secrets) and auth.json (only when absent), both chmod 600, and inherit model.provider/model.default when the caller gave no explicit pin and no config was cloned. mirror_credentials:false preserves the old isolated behavior byte-for-byte. Result gains a mirrored:{env,auth,model_inherited} receipt. CLI and REST create paths untouched.
skappafrost
pushed a commit
to skappafrost/hermes-agent
that referenced
this pull request
Aug 15, 2026
…NousResearch#85216) profiles.list/create (NousResearch#85093) let plugins enumerate and create profiles but not read or modify an existing profile's configuration over ws. profiles.describe returns the full editor snapshot (description, SOUL.md, model pin, per-skill enablement via the disabled-list model, per-toolset enablement via the tools.enabled_toolsets pin); profiles.configure applies any subset (description via write_profile_meta, soul, model via _write_profile_model, disabled_skills replace-semantics via save_disabled_skills, enabled_toolsets replace-semantics with empty-list clearing the pin) independently and best-effort, reporting per-section results. Both scoped via the HERMES_HOME override and pool-dispatched.
bobaba76
pushed a commit
to bobaba76/hermes-agent
that referenced
this pull request
Aug 27, 2026
…n doors (NousResearch#85093) Desktop plugins reach the backend exclusively through the generic ws JSON-RPC door (host.request), but profile enumeration/creation only existed on the dashboard REST router, which plugins cannot reach — so anything 'one chat per agent profile'-shaped (bot rosters, profile pickers, team panes) was impossible to build as a plugin. - tui_gateway/methods_profiles.py: new @method handlers * profiles.list — profiles + optional last_session preview per profile (mirrors session.list's kanban/tool deny-list; best-effort per-profile state.db probe degrades to null instead of failing the call) * profiles.create — ws twin of POST /api/profiles (clone_from/clone_all/ no_skills/description), plus optional SOUL.md content and a best-effort model+provider pin; mirrors the CLI flow (seed skills, safe alias) Both run on the RPC pool, not the WS reader thread (list_profiles walks skill trees; create copies bundles). - SDK: host.openSession(id, { profile, intent }) — open a stored session the way core surfaces do, soft-swapping to the owning profile's backend first (ensureGatewayProfile), and host.newChat(profile) — fresh draft in a named profile (same door as the sidebar's per-profile '+'). - Docs: desktop-plugin-sdk.md gains both surfaces. First consumer: a Grok Bot-style 'Bots' roster plugin (one persistent chat per agent profile with a New Agent dialog) built on exactly these four doors.
bobaba76
pushed a commit
to bobaba76/hermes-agent
that referenced
this pull request
Aug 27, 2026
…un (NousResearch#85111) A profile created through the headless ws door (profiles.create, NousResearch#85093) was born with no inference provider: create_profile() seeds a comment-only .env, never copies auth.json, and a fresh profile has no config.yaml. Its first message failed with 'No inference provider configured' and the flow has no interactive setup step to recover with. New mirror_credentials param (default true): copy the launch profile's .env (only over the seeded stub — never clobber cloned secrets) and auth.json (only when absent), both chmod 600, and inherit model.provider/model.default when the caller gave no explicit pin and no config was cloned. mirror_credentials:false preserves the old isolated behavior byte-for-byte. Result gains a mirrored:{env,auth,model_inherited} receipt. CLI and REST create paths untouched.
melon-xf
added a commit
to melon-xf/hermes-agent
that referenced
this pull request
Sep 3, 2026
…n doors (NousResearch#85093) Desktop plugins reach the backend exclusively through the generic ws JSON-RPC door (host.request), but profile enumeration/creation only existed on the dashboard REST router, which plugins cannot reach — so anything 'one chat per agent profile'-shaped (bot rosters, profile pickers, team panes) was impossible to build as a plugin. - tui_gateway/methods_profiles.py: new @method handlers * profiles.list — profiles + optional last_session preview per profile (mirrors session.list's kanban/tool deny-list; best-effort per-profile state.db probe degrades to null instead of failing the call) * profiles.create — ws twin of POST /api/profiles (clone_from/clone_all/ no_skills/description), plus optional SOUL.md content and a best-effort model+provider pin; mirrors the CLI flow (seed skills, safe alias) Both run on the RPC pool, not the WS reader thread (list_profiles walks skill trees; create copies bundles). - SDK: host.openSession(id, { profile, intent }) — open a stored session the way core surfaces do, soft-swapping to the owning profile's backend first (ensureGatewayProfile), and host.newChat(profile) — fresh draft in a named profile (same door as the sidebar's per-profile '+'). - Docs: desktop-plugin-sdk.md gains both surfaces. First consumer: a Grok Bot-style 'Bots' roster plugin (one persistent chat per agent profile with a New Agent dialog) built on exactly these four doors.
melon-xf
added a commit
to melon-xf/hermes-agent
that referenced
this pull request
Sep 3, 2026
…un (NousResearch#85111) A profile created through the headless ws door (profiles.create, NousResearch#85093) was born with no inference provider: create_profile() seeds a comment-only .env, never copies auth.json, and a fresh profile has no config.yaml. Its first message failed with 'No inference provider configured' and the flow has no interactive setup step to recover with. New mirror_credentials param (default true): copy the launch profile's .env (only over the seeded stub — never clobber cloned secrets) and auth.json (only when absent), both chmod 600, and inherit model.provider/model.default when the caller gave no explicit pin and no config was cloned. mirror_credentials:false preserves the old isolated behavior byte-for-byte. Result gains a mirrored:{env,auth,model_inherited} receipt. CLI and REST create paths untouched.
melon-xf
added a commit
to melon-xf/hermes-agent
that referenced
this pull request
Sep 3, 2026
…NousResearch#85216) profiles.list/create (NousResearch#85093) let plugins enumerate and create profiles but not read or modify an existing profile's configuration over ws. profiles.describe returns the full editor snapshot (description, SOUL.md, model pin, per-skill enablement via the disabled-list model, per-toolset enablement via the tools.enabled_toolsets pin); profiles.configure applies any subset (description via write_profile_meta, soul, model via _write_profile_model, disabled_skills replace-semantics via save_disabled_skills, enabled_toolsets replace-semantics with empty-list clearing the pin) independently and best-effort, reporting per-section results. Both scoped via the HERMES_HOME override and pool-dispatched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Widens the generic plugin surface so profile-shaped desktop plugins are possible — the "plugins live at the edges; if a plugin needs more, widen the generic plugin surface" path from AGENTS.md.
Two additions, both with an immediate concrete consumer (a Grok Bot-style "Bots" roster plugin: one persistent chat per agent profile, a New Agent dialog, cross-profile chat opens):
1.
profiles.list/profiles.createws JSON-RPC (tui_gateway/methods_profiles.py)Desktop plugins reach the backend exclusively through
host.request(ws JSON-RPC), but profile enumeration/creation only existed on the dashboard REST router (hermes_cli/web_routers/profiles.py), which plugins cannot reach.profiles.list— every profile (name, path, model/provider, description, skill_count) plus an optionallast_sessionpreview per profile (include_sessions: falseto skip). The per-profilestate.dbprobe mirrorssession.list'skanban/tooldeny-list and is best-effort: a missing/locked db degrades that profile's preview tonullinstead of failing the call.profiles.create— ws twin ofPOST /api/profiles:name,description,clone_from,clone_all,no_skills, plus optionalsoul(SOUL.md content) and a best-effortmodel+providerpin. Mirrors the CLI/REST create flow (seed bundled skills for fresh profiles, safe alias wrapper).Both registered in the RPC pool set —
list_profiles()walks skill trees andcreate_profile()copies bundles, so neither belongs on the WS reader thread. Handler helpers are nested inside the handler body (themethod_ctx.pyinstall seam rebinds__globals__onto server.py, so module-level helpers are invisible — noted in a comment for the next author).2. SDK session-navigation doors (
apps/desktop/src/sdk/index.ts)host.openSession(id, { profile?, intent? })— open a stored session the way core surfaces do (focus existing tile/main, else load into main), soft-swapping to the owning profile's backend first viaensureGatewayProfile— the same gesture the unified sidebar uses for cross-profile resumes.host.newChat(profile?)— fresh chat draft pointed at a named profile (the sidebar per-profile "+" door,newSessionInProfile).Without these, a plugin could only
host.navigate('/<sessionId>'), which breaks for any session owned by a non-active profile.Verification
profiles.list/profiles.createexercised end-to-end against the real registry (server._methods[...]dispatch): list returns the live roster withlast_sessionpreviews; create built a real profile (dir + SOUL.md + skills), verified on disk, then deleted viahermes profile delete.vite buildgreen in a full desktopnpm run pack).website/docs/developer-guide/desktop-plugin-sdk.mddocuments all four surfaces.No new model tools, no config keys, no env vars; prompt caching and message alternation untouched. Sweep of open issues/PRs found no duplicates for this surface.