| 2026-10-09 |

webclient: the settings screen in en, uk and ru
...
Settings is the first area off hard-coded English: 122 strings for the shell and
its five tabs — App, Account, Notifications, Synapse and MCP — plus the 43 the
shared vocabulary contributes (common.*, col.*, confirm.*, toast.*).
The English dictionary carries the very literals the templates used, so the
interface a test reads is byte-for-byte what it was and the 56 assertions on
English UI text stay green; only a slug that is genuinely counted had to be
restructured into a plural. In ru and uk the counted strings get the three
Slavic forms driven by n. Product names are never translated: Navi, Synapse,
MCP, Ollama, Tool call, Subagent and Token read the same in all three
languages, and the settings screen keeps one settings.* area with
panel-prefixed slugs rather than a slug per panel, as the other gnexus clients
do.
Strings carrying markup are split around it instead of hiding tags in the
dictionary: the install steps keep their inline icons and <code>http://</code>
in the template, with the words of each sentence on either side. Four lists of
labels — the settings tabs, two table headers, and the reaction options — are
now computed rather than module-level constants, since a list built at import
keeps the language that was active then and ignores a switch. Dates in the
panels go through the interface language as well, not the browser's.
Checked in Chromium against the built bundle: all three languages on all five
tabs, with a scan for a slug leaking into the rendered text as the pass
condition, and the account left with no override afterwards.
Eugene Sukhodolskiy
committed
1 day ago
|

profiles: restricted profiles for ordinary users, and a role gate that holds
...
`is_admin_only` was checked in one place out of nine and was not read from
config.json at all, so all seven profiles were reachable by every account with
role `user`. The flag now lives in config.json — the file is the baseline, a
`profile_overrides` row still wins on top of it — and one predicate,
`admin_only_blocked`, is the single place the rule is expressed. The nine
surfaces that list, switch to, spawn or resolve a profile all consult it:
`POST /sessions`, the WebSocket, switch_profile, list_profiles, the system
prompt's "Available profiles" block, spawn_agent and the Synapse reaction
runner. The prompt cache is now keyed by (profile, role), so a user's prompt
can never be served an admin's profile list.
The seven existing profiles (developer, discuss, dispatcher, modeler_3d,
navi_code, secretary, server_admin) are marked admin-only. Three new ones take
their place for ordinary users: assistant, designer_3d and coder. They share one
native tool set — ssh_exec, peer, reload_tools, create_mcp_server, test_mcp_tool,
image_view and gmail are withheld — and differ only in system prompt, model and
MCP groups. navi-web's raw `request` group, and the whole of gnexus-creds and
tgclient, are withheld too.
MCP per-user keys gain the missing half of the rule: a server that declares a
`user_key` slot is refused to anyone but an admin who has no personal key, and
is left out of their tool list entirely, instead of quietly falling back to the
owner's credential and appearing as a tool that cannot work. The refusal names
the server and points at Settings.
Also closes `GET /agents/prompts`, which served every profile's system prompt to
anyone, with no user dependency at all.
The accepted residual risk is written down in docs/profiles.md: the working
directory is a convention, not a sandbox.
Eugene Sukhodolskiy
committed
2 days ago
|
| 2026-10-07 |
webclient: keep MCP rows at content height on a phone
...
.mcp-keys-row stacks into a column below 768px, and .mcp-keys-info kept
its flex: 1 1 240px. That basis is a width in the desktop row and a
height once the row stacks, so every server reserved 240px and its text
sat at the top of the gap — 402px for a row whose content is 90px.
Back to content height on mobile only, and drop the kit's .form-group
bottom margin there: the row's own flex gap already separates the field
from the buttons.
Eugene Sukhodolskiy
committed
3 days ago
|

MCP settings tab: list every connected server, slot only where declared
...
The tab was empty on every install: it listed only servers whose config
declares a `user_key` slot, and no config declared one — which read as
"no MCP servers connected" even though five are wired to profiles.
- GET /mcp-keys now returns every server referenced by at least one
profile, keyed ones first, with `accepts_user_key`, the slot location
(null when there is none) and the profile ids that connect it. The
per-user key store is skipped entirely when nothing has a slot.
- gnexus-creds declares `user_key: {header: Authorization, prefix:
"Bearer "}` — it is the one server carrying a shared credential, so its
personal-key field is now real: users with a key run under their own,
users without one fall back to the shared default.
- The panel lists all servers (transport + profiles), dims the keyless
rows, and shows a key input only for slotted ones, spelling out the
shared-key fallback.
docs/api.md and docs/mcp.md updated; backend 1367 passed, webclient 148.
Eugene Sukhodolskiy
committed
3 days ago
|
webclient: settings page fits the app frame — flat chat-style header bar, single full-bleed scroll region, mobile adaptation (stacked MCP rows, viewport-safe modals)
Eugene Sukhodolskiy
committed
3 days ago
|
webclient: MCP keys tab gets an empty-state when no server declares a user_key slot
Eugene Sukhodolskiy
committed
3 days ago
|
webclient: settings loaders switched to kit circle spinner (GnLoader circle)
Eugene Sukhodolskiy
committed
3 days ago
|
webclient: MCP user keys panel (BYOK) + frontend tests
Eugene Sukhodolskiy
committed
3 days ago
|