fix: make the panel usable on a phone, and show every page in the docs - #40
Conversation
Mobile navigation was broken outright. The stylesheet had a 768px breakpoint that slid the sidebar off-screen and waited for a .sidebar.open class, but nothing in the markup or the JS ever added it and there was no control to trigger it. On a phone you signed in, landed on the dashboard, and could not reach a single other page — the nav buttons were laid out beyond the viewport. - add a hamburger in the topbar, shown only under 768px, with a backdrop, an Escape binding, and auto-close when a destination is picked - stop wide content dragging the page sideways. The clients page overflowed by 398px and the monitor by 2838px, so the layout slid out from under the sticky topbar. min-width:0 on the layout chain is the load-bearing part: a grid child defaults to min-width:auto, so a wide table widens its ancestors instead of letting the scroll container work - the topbar had a fixed 64px height. Once its controls wrapped to a second row the sticky bar painted its overflow over the first card Docs: every page now shows the screen it describes, at widescreen and on a phone, captured from a real deployment rather than mocked. Troubleshooting gains the five failures actually hit while running this: a reinstalled satellite that cannot reconnect (reset-noise-pin), two services fighting over 5678, an upgrade that leaves the hub on an old version because the panel's own pins hold it back, a crash loop after optional plugins go missing, and this mobile bug. Screenshots are downscaled and palette-reduced: 35 images, 2.2MB.
📝 WalkthroughWalkthroughThe panel adds mobile sidebar controls and broader responsive layout rules. The security checks no longer report websocket TLS status. Documentation pages add widescreen and mobile interface previews and troubleshooting guidance. ChangesResponsive panel and documentation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant AdminPanelUser
participant NavigationToggle
participant SidebarController
participant Sidebar
participant Backdrop
AdminPanelUser->>NavigationToggle: Click menu button
NavigationToggle->>SidebarController: Call toggleSidebar()
SidebarController->>Sidebar: Toggle open state
SidebarController->>Backdrop: Toggle visibility
SidebarController->>NavigationToggle: Update aria-expanded
AdminPanelUser->>Backdrop: Click backdrop
Backdrop->>SidebarController: Call closeSidebar()
SidebarController->>Sidebar: Remove open state
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Beep boop! Here's the latest status of your PR checks. 🤖I've aggregated the results of the automated checks for this PR below. 🔍 LintA quick update on the progress of your PR checks. 📈 ❌ ruff: issues found — see job log 📋 Repo HealthThe repo's annual physical is complete! 🩺 ✅ All required files present. Latest Version: ✅ 🏷️ Release PreviewPredicting the ripple effect of this release. 🌊 Current:
✅ PR title follows conventional commit format. 🚀 Release Channel Compatibility Predicted next version:
📊 CoverageEnsuring our code is as robust as it looks. 💎 Per-file coverage (8 files)
Full report: download the 🔨 Build TestsChecking if the gears are still turning smoothly... ⚙️ ✅ All versions pass
⚖️ License CheckKeeping the lawyers happy, one file at a time. 👔 ✅ No license violations found. Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed. 🔒 Security (pip-audit)I've checked for any insecure file permissions. 📂 ✅ No known vulnerabilities found (99 packages scanned). Your automated guardian for repository health 🛡️ |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
docs/troubleshooting.md (1)
159-162: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd language identifiers to diagnostic output fences.
markdownlintreports MD040 for both fences. Addtextto each opening fence.
docs/troubleshooting.md#L159-L162: change the opening fence to ````text`.docs/troubleshooting.md#L229-L233: change the opening fence to ````text`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/troubleshooting.md` around lines 159 - 162, Update the opening diagnostic-output fences in docs/troubleshooting.md at lines 159-162 and 229-233 to specify the text language identifier, changing each plain fence to a text fence.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/api-reference.md`:
- Around line 69-75: Replace the promotional or purpose-based screenshot alt
text with concise visual descriptions: in docs/api-reference.md lines 69-75,
describe the dashboard elements visible in both widescreen and mobile images; in
docs/cli.md lines 95-101, describe the Clients page, its list, and visible
controls; and in docs/glossary.md lines 139-145, describe the visible dashboard
content rather than mentioning glossary terms.
In `@docs/bridges.md`:
- Around line 79-87: Update the “What it looks like” preview in docs/bridges.md
to use bridge-specific widescreen and mobile image assets with captions
describing the bridge UI, or remove the preview section until those assets are
available; do not retain the Agent Protocol images or captions.
In `@docs/index.md`:
- Line 14: Change the “What it looks like” heading from H3 to H2 so the document
heading hierarchy follows the existing H1 without skipping a level.
In `@hivemind_admin_panel/static/css/style.css`:
- Around line 884-902: Update the mobile overlay stacking in .sidebar-backdrop
and the responsive .sidebar rules: assign the backdrop a z-index above the
.topbar’s 100 level, then assign the sidebar a still higher z-index so it
renders above the backdrop and prevents topbar interaction while the drawer is
open.
- Around line 966-974: Replace the deprecated word-break declaration in the
pre/code/.log-entry/.monitor-log rule with overflow-wrap: anywhere, preserving
the existing max-width, horizontal overflow, and whitespace behavior.
In `@hivemind_admin_panel/static/js/app.js`:
- Around line 4618-4654: Update openSidebar() to focus the first .nav-item after
opening and set `#navToggle`’s accessible label to “Close navigation”; update
closeSidebar() to restore focus to `#navToggle` when the active element is inside
`#sidebar` and reset the label to its closed-state value, preserving the existing
drawer class and aria-expanded behavior.
---
Nitpick comments:
In `@docs/troubleshooting.md`:
- Around line 159-162: Update the opening diagnostic-output fences in
docs/troubleshooting.md at lines 159-162 and 229-233 to specify the text
language identifier, changing each plain fence to a text fence.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2ed7f656-63af-4327-95bf-bd550e758456
⛔ Files ignored due to path filters (35)
docs/img/acl-mobile.pngis excluded by!**/*.pngdocs/img/acl.pngis excluded by!**/*.pngdocs/img/agents-mobile.pngis excluded by!**/*.pngdocs/img/agents.pngis excluded by!**/*.pngdocs/img/binary-mobile.pngis excluded by!**/*.pngdocs/img/binary.pngis excluded by!**/*.pngdocs/img/chat-mobile.pngis excluded by!**/*.pngdocs/img/chat.pngis excluded by!**/*.pngdocs/img/clients-mobile.pngis excluded by!**/*.pngdocs/img/clients.pngis excluded by!**/*.pngdocs/img/dashboard-mobile.pngis excluded by!**/*.pngdocs/img/dashboard.pngis excluded by!**/*.pngdocs/img/database-mobile.pngis excluded by!**/*.pngdocs/img/database.pngis excluded by!**/*.pngdocs/img/encodings-mobile.pngis excluded by!**/*.pngdocs/img/encodings.pngis excluded by!**/*.pngdocs/img/login-mobile.pngis excluded by!**/*.pngdocs/img/login.pngis excluded by!**/*.pngdocs/img/monitor-mobile.pngis excluded by!**/*.pngdocs/img/monitor.pngis excluded by!**/*.pngdocs/img/nav-drawer-mobile.pngis excluded by!**/*.pngdocs/img/network-mobile.pngis excluded by!**/*.pngdocs/img/network.pngis excluded by!**/*.pngdocs/img/ops-mobile.pngis excluded by!**/*.pngdocs/img/ops.pngis excluded by!**/*.pngdocs/img/personas-mobile.pngis excluded by!**/*.pngdocs/img/personas.pngis excluded by!**/*.pngdocs/img/presets-mobile.pngis excluded by!**/*.pngdocs/img/presets.pngis excluded by!**/*.pngdocs/img/servers-mobile.pngis excluded by!**/*.pngdocs/img/servers.pngis excluded by!**/*.pngdocs/img/topology-mobile.pngis excluded by!**/*.pngdocs/img/topology.pngis excluded by!**/*.pngdocs/img/voice-plugins-mobile.pngis excluded by!**/*.pngdocs/img/voice-plugins.pngis excluded by!**/*.png
📒 Files selected for processing (24)
docs/api-reference.mddocs/architecture.mddocs/bridges.mddocs/cli.mddocs/concepts.mddocs/configuration.mddocs/deployment.mddocs/development.mddocs/extending.mddocs/getting-started.mddocs/glossary.mddocs/index.mddocs/operations.mddocs/ovos-servers.mddocs/presets.mddocs/roadmap.mddocs/running.mddocs/security.mddocs/test-chat.mddocs/troubleshooting.mddocs/tutorial.mdhivemind_admin_panel/static/css/style.csshivemind_admin_panel/static/index.htmlhivemind_admin_panel/static/js/app.js
| **Widescreen** | ||
|
|
||
|  | ||
|
|
||
| **Mobile** | ||
|
|
||
|  |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use visual descriptions for screenshot alt text.
The new alt text describes page purpose or uses promotional wording instead of describing the visible interface.
docs/api-reference.md#L69-L75: describe the dashboard elements visible in both screenshots.docs/cli.md#L95-L101: describe the Clients page, its list, and visible controls.docs/glossary.md#L139-L145: describe the dashboard content instead of stating that glossary terms appear there.
📍 Affects 3 files
docs/api-reference.md#L69-L75(this comment)docs/cli.md#L95-L101docs/glossary.md#L139-L145
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/api-reference.md` around lines 69 - 75, Replace the promotional or
purpose-based screenshot alt text with concise visual descriptions: in
docs/api-reference.md lines 69-75, describe the dashboard elements visible in
both widescreen and mobile images; in docs/cli.md lines 95-101, describe the
Clients page, its list, and visible controls; and in docs/glossary.md lines
139-145, describe the visible dashboard content rather than mentioning glossary
terms.
| ### What it looks like | ||
|
|
||
| **Widescreen** | ||
|
|
||
|  | ||
|
|
||
| **Mobile** | ||
|
|
||
|  |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use bridge screenshots on the Chat bridges page.
The new preview links agents.png and agents-mobile.png, and both captions identify the Agent Protocol UI. Use bridge-specific widescreen and mobile images, or remove this preview until those assets exist.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/bridges.md` around lines 79 - 87, Update the “What it looks like”
preview in docs/bridges.md to use bridge-specific widescreen and mobile image
assets with captions describing the bridge UI, or remove the preview section
until those assets are available; do not retain the Agent Protocol images or
captions.
|  | ||
|
|
||
|
|
||
| ### What it looks like |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the heading level for What it looks like.
The page starts with an H1 and has no H2 before Line 14, so ### skips a heading level. Change it to ##, or add an H2 parent.
Suggested fix
-### What it looks like
+## What it looks like📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### What it looks like | |
| ## What it looks like |
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 14-14: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/index.md` at line 14, Change the “What it looks like” heading from H3 to
H2 so the document heading hierarchy follows the existing H1 without skipping a
level.
Source: Linters/SAST tools
| pre, | ||
| code, | ||
| .log-entry, | ||
| .monitor-log { | ||
| max-width: 100%; | ||
| overflow-x: auto; | ||
| white-space: pre-wrap; | ||
| word-break: break-word; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
npx --no-install stylelint hivemind_admin_panel/static/css/style.css
rg -n 'word-break:\s*break-word' hivemind_admin_panel/static/css/style.cssRepository: JarbasHiveMind/hivemind-admin-panel
Length of output: 1113
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- matching declarations ---'
rg -n -C 3 'word-break\s*:\s*break-word|overflow-wrap\s*:\s*anywhere' hivemind_admin_panel/static/css/style.css || true
printf '%s\n' '--- stylelint configuration files ---'
git ls-files | rg '(^|/)(stylelint|\.stylelintrc)([^/]*|/.*)$|package\.json$' || true
printf '%s\n' '--- repository references to the rule or value ---'
rg -n 'declaration-property-value-disallowed-list|word-break|break-word|overflow-wrap' --glob '!hivemind_admin_panel/static/css/style.css' . || trueRepository: JarbasHiveMind/hivemind-admin-panel
Length of output: 1213
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- package.json ---'
cat package.json
printf '%s\n' '--- tracked Stylelint-related files ---'
git ls-files | rg -i 'stylelint|\.stylelintrc|package-lock|npm-shrinkwrap|yarn\.lock|pnpm-lock' || trueRepository: JarbasHiveMind/hivemind-admin-panel
Length of output: 697
🌐 Web query:
MDN CSS word-break break-word deprecated value overflow-wrap anywhere
💡 Result:
The CSS value word-break: break-word is deprecated [1][2][3]. It is maintained in specifications primarily for legacy compatibility [2][4]. Modern CSS development should avoid using word-break: break-word [5]. Instead, authors should use the overflow-wrap property [3], specifically: 1. overflow-wrap: anywhere: This is the modern, recommended way to ensure long words or strings do not overflow their container [6]. It allows the browser to break lines at any point if no other break opportunities exist [6]. Unlike overflow-wrap: break-word, it considers these breaks when calculating the min-content intrinsic size of the element, which often leads to more predictable layouts in modern layout systems like Flexbox or Grid [6][7]. 2. overflow-wrap: break-word: This remains a valid option if you want the browser to prevent overflow while keeping the soft wrap opportunities from being considered in min-content size calculations [6]. The deprecated word-break: break-word behaves identically to overflow-wrap: anywhere (combined with word-break: normal) [1][8][9]. Because overflow-wrap: anywhere provides the same behavior with standard, non-deprecated syntax, it is the preferred replacement [3].
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/word-break
- 2: https://drafts.csswg.org/css-text/
- 3: https://web-platform-dx.github.io/web-features-explorer/features/word-break-break-word/
- 4: [css-text-3] Implement or unship word-break:break-word w3c/csswg-drafts#2390
- 5: [css-text-3] Normatively disallow break-word w3c/csswg-drafts#4087
- 6: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/overflow-wrap
- 7: https://stackoverflow.com/questions/68593758/difference-between-overflow-wrap-anywhere-overflow-wrap-break-word
- 8: https://github.com/mdn/content/blob/main/files/en-us/web/css/reference/properties/word-break/index.md
- 9: https://stackoverflow.com/questions/66724509/overflow-wrap-break-word-vs-word-break-break-word
Replace the deprecated word-break value.
Use overflow-wrap: anywhere for equivalent long-token wrapping.
🧰 Tools
🪛 Stylelint (17.14.0)
[error] 973-973: Deprecated keyword "break-word" for property "word-break" (declaration-property-value-keyword-no-deprecated)
(declaration-property-value-keyword-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@hivemind_admin_panel/static/css/style.css` around lines 966 - 974, Replace
the deprecated word-break declaration in the pre/code/.log-entry/.monitor-log
rule with overflow-wrap: anywhere, preserving the existing max-width, horizontal
overflow, and whitespace behavior.
Source: Linters/SAST tools
An adversarial review drove the live panel across 8 viewports and refuted the previous claim: on a 360x640 phone six of sixteen destinations were still unreachable, because the drawer itself never scrolled. Blockers fixed: - the drawer scrolls (100dvh + overflow-y). 16 nav items and a footer are taller than a short phone; nothing clipped or scrolled them, so Presets through Operations and the theme/logout footer were simply off the bottom - the drawer sits above the topbar (z-index 200 vs 100). Equal z-index with the topbar later in the DOM meant a tap in the top 17px of the first nav item silently hit the header instead - opening the drawer moves focus into it. Tabbing from the toggle walked past the drawer entirely — it is earlier in the DOM — and landed on the destructive Restart button behind an opaque backdrop - a closed drawer leaves the tab order (inert + aria-hidden). Six invisible controls came before any page content - the toggle relabels itself Open/Close instead of always saying Open - the page no longer scrolls underneath the backdrop - landscape phones get the drawer: the query is now max-width 768px OR a short landscape viewport. At 844x390 none of the mobile CSS applied and the monitor overflowed by 2676px - modals are a flex column, so the body scrolls and the footer stays put. In landscape the footer sat below the modal and Save could not be reached - the min-width:0 containment and the topbar wrap moved OUT of the phone query. Scoped to <=768 they left 769px and every tablet overflowing, and the monitor still slid 960px sideways at 2560 Also: the dashboard no longer nags about websocket TLS. HiveMind encrypts its payloads end to end — AES session key on v1/v2, Noise on v3 — so ws:// is not cleartext. Flagging it taught operators to add TLS for a problem they did not have. Docs: duplicate screenshots removed, the bridges page no longer illustrated with an unrelated screen, the drawer screenshot now documents the drawer, and the five orphan images are placed. No orphans, no duplicates, no broken refs.
The committed images still showed the TLS banner that was removed, and the pre-fix topbar. Recaptured from the live deployment with the final CSS.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/getting-started.md (1)
68-74: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winComplete the widescreen preview section.
The visible
Widescreenlabel is followed by no image or explanation. Ifimg/login.pngis the intended widescreen preview, state that it appears above or move the image into this subsection.Proposed fix
**Widescreen** -<!-- duplicate screenshot removed --> +The widescreen sign-in screen is shown above.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/getting-started.md` around lines 68 - 74, Complete the Widescreen section in the getting-started documentation by restoring or adding the intended img/login.png preview, or explicitly explaining where it appears. Keep the existing Mobile subsection and its img/login-mobile.png image unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@hivemind_admin_panel/api.py`:
- Around line 5037-5041: Revise the websocket security handling around the
protocol-version transport check: retain core_tls or an equivalent
transport-security validation instead of claiming ws:// is always safe. Update
docs/security.md to accurately describe handshake metadata and
endpoint-authentication risks across v0–v3, and add regression tests enforcing
the minimum supported protocol security behavior.
In `@hivemind_admin_panel/static/js/app.js`:
- Around line 4628-4648: Update openSidebar() to keep keyboard focus within
`#sidebar` while it is open by making outside content inert or implementing a
focus trap, including wrapping Tab navigation from the last control to the
first. Update the Escape-key listener near the related sidebar handlers so it
dismisses the drawer only when focus is within the drawer context, and restore
outside interactivity when closing.
- Around line 4674-4684: The _syncSidebarInertness function must fully close and
reset the drawer when transitioning from mobile to desktop, clearing the
sidebar’s open/visible state, aria-expanded value, backdrop, and document.body
scroll lock while retaining the existing inert and aria-hidden synchronization.
---
Outside diff comments:
In `@docs/getting-started.md`:
- Around line 68-74: Complete the Widescreen section in the getting-started
documentation by restoring or adding the intended img/login.png preview, or
explicitly explaining where it appears. Keep the existing Mobile subsection and
its img/login-mobile.png image unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: bfaeb3ba-967b-4a59-9a73-8cfcbc9fdae5
⛔ Files ignored due to path filters (32)
docs/img/acl-mobile.pngis excluded by!**/*.pngdocs/img/agents-mobile.pngis excluded by!**/*.pngdocs/img/agents.pngis excluded by!**/*.pngdocs/img/binary-mobile.pngis excluded by!**/*.pngdocs/img/binary.pngis excluded by!**/*.pngdocs/img/chat-mobile.pngis excluded by!**/*.pngdocs/img/clients-mobile.pngis excluded by!**/*.pngdocs/img/clients.pngis excluded by!**/*.pngdocs/img/dashboard-mobile.pngis excluded by!**/*.pngdocs/img/dashboard.pngis excluded by!**/*.pngdocs/img/database-mobile.pngis excluded by!**/*.pngdocs/img/database.pngis excluded by!**/*.pngdocs/img/encodings-mobile.pngis excluded by!**/*.pngdocs/img/encodings.pngis excluded by!**/*.pngdocs/img/login-mobile.pngis excluded by!**/*.pngdocs/img/login.pngis excluded by!**/*.pngdocs/img/monitor-mobile.pngis excluded by!**/*.pngdocs/img/monitor.pngis excluded by!**/*.pngdocs/img/nav-drawer-mobile.pngis excluded by!**/*.pngdocs/img/network-mobile.pngis excluded by!**/*.pngdocs/img/network.pngis excluded by!**/*.pngdocs/img/ops-mobile.pngis excluded by!**/*.pngdocs/img/ops.pngis excluded by!**/*.pngdocs/img/personas-mobile.pngis excluded by!**/*.pngdocs/img/presets-mobile.pngis excluded by!**/*.pngdocs/img/presets.pngis excluded by!**/*.pngdocs/img/servers-mobile.pngis excluded by!**/*.pngdocs/img/servers.pngis excluded by!**/*.pngdocs/img/topology-mobile.pngis excluded by!**/*.pngdocs/img/topology.pngis excluded by!**/*.pngdocs/img/voice-plugins-mobile.pngis excluded by!**/*.pngdocs/img/voice-plugins.pngis excluded by!**/*.png
📒 Files selected for processing (14)
docs/bridges.mddocs/concepts.mddocs/configuration.mddocs/deployment.mddocs/getting-started.mddocs/index.mddocs/operations.mddocs/presets.mddocs/running.mddocs/troubleshooting.mddocs/tutorial.mdhivemind_admin_panel/api.pyhivemind_admin_panel/static/css/style.csshivemind_admin_panel/static/js/app.js
🚧 Files skipped from review as they are similar to previous changes (10)
- docs/configuration.md
- docs/bridges.md
- docs/index.md
- docs/deployment.md
- docs/running.md
- docs/concepts.md
- docs/tutorial.md
- docs/troubleshooting.md
- docs/presets.md
- hivemind_admin_panel/static/css/style.css
| # There is deliberately no check for websocket TLS. HiveMind encrypts its | ||
| # own payloads end to end — an AES session key on protocol v1/v2 and the | ||
| # Noise transport on v3 — so ws:// is not cleartext and a satellite on a | ||
| # plain socket is not exposed. Flagging it taught operators to add TLS for | ||
| # a problem they did not have, and trained them to ignore this panel. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 6 '\bcore_tls\b|setup/status|setup_acked|\bchecks\b' \
--glob '*.py' --glob '*.js' --glob '*.html' --glob '*.md' . || true
rg -n -C 8 'hivemind-core|Noise|AES|session key|ws://|wss://|websocket|tls|SSL' \
--glob '*.py' --glob '*.toml' --glob '*.yaml' --glob '*.yml' .Repository: JarbasHiveMind/hivemind-admin-panel
Length of output: 50394
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- package declarations ---'
rg -n -C 3 'hivemind-core|hivemind_core' pyproject.toml setup.py setup.cfg requirements\* *.toml 2>/dev/null || true
printf '%s\n' '--- security-check implementation and consumers ---'
sed -n '4980,5110p' hivemind_admin_panel/api.py
rg -n -C 4 'admin_password|bind_host|core_tls|checks\.|checks\]|secure|clean|warnings' \
hivemind_admin_panel tests docs --glob '*.py' --glob '*.js' --glob '*.html' --glob '*.md'
printf '%s\n' '--- protocol and connection configuration references ---'
rg -n -C 5 'protocol_version|protocol|session_key|AES|Noise|websocket|ws://|wss://|tls|ssl|cert' \
hivemind_admin_panel tests docs pyproject.toml setup.py setup.cfg requirements\* 2>/dev/null \
--glob '*.py' --glob '*.js' --glob '*.md' --glob '*.toml' --glob '*.yaml' --glob '*.yml' | head -n 1000
printf '%s\n' '--- tracked files that may contain vendored core code ---'
git ls-files | rg '(^|/)(hivemind_core|hivemind-core|protocol|transport|websocket|crypto|security)(/|\.|$)' | head -n 300Repository: JarbasHiveMind/hivemind-admin-panel
Length of output: 50394
🌐 Web query:
hivemind-core protocol v1 v2 AES session key v3 Noise websocket TLS encryption authentication
💡 Result:
The HiveMind-core protocol architecture manages communication security through versioned handshake and encryption standards [1][2]. Protocol versions are negotiated at connection time [1]: Protocol Versions and Encryption: - v0: Legacy/Deprecated. Uses JSON-only encoding and a pre-shared AES key without a handshake, providing no forward secrecy [1][2][3]. - v1/v2: Handshake-based. v1 uses JSON-based communication (with binary framing optional in v2), authenticated via PBKDF2-SHA256 password hashes or RSA handshakes to derive session keys [1][4][5]. After the handshake, payload encryption is performed using negotiated ciphers [4]. - v3: Modern/Recommended. Employs a Noise-based handshake (typically Noise_XXpsk2_25519_ChaChaPoly_SHA256) [1]. It is always encrypted, utilizes binary framing, and requires a shared password for the PSK [1][2]. Authentication and Key Exchange: - Authentication is handled via API keys paired with either passwords or pre-shared keys [3]. - In v1/v2, the password itself is never transmitted; instead, both sides derive a shared session key through a handshake [4][3]. - For v3, the Noise protocol provides the cryptographic handshake to establish an encrypted session [1][5]. Transport and Security: - WebSocket/TLS: The reference transport is the hivemind-websocket-plugin [6]. While the protocol supports standard ws:// connections, TLS encryption (wss://) can be enabled in server.json by setting ssl to true and configuring the certificate directory [6]. - Cipher Negotiation: For v1/v2, the server and client negotiate an encryption cipher from an allowed list, defaulting to ["CHACHA20-POLY1305", "AES-GCM"] [4][7][8]. v3 natively handles the cipher suite via the Noise handshake [1]. Operators can enforce minimum security standards by setting the min_protocol_version in the server configuration [4][8]. Setting this to 3 forces all clients to use the modern, Noise-encrypted v3 protocol [4].
Citations:
- 1: https://jarbashivemind.github.io/HiveMind-community-docs/developers/protocol-spec/
- 2: https://github.com/JarbasHiveMind/HiveMind-core/blob/HEAD/hivemind_core/protocol.py
- 3: https://deepwiki.com/JarbasHiveMind/HiveMind-core/6.2-authentication
- 4: https://jarbashivemind.github.io/HiveMind-community-docs/concepts/security/
- 5: https://deepwiki.com/JarbasHiveMind/HiveMind-core/6.1-cryptography-and-handshakes
- 6: https://github.com/JarbasHiveMind/hivemind-websocket-protocol
- 7: https://jarbashivemind.github.io/HiveMind-community-docs/reference/config/
- 8: https://github.com/JarbasHiveMind/HiveMind-core/blob/HEAD/hivemind_core/config.py
🌐 Web query:
site:github.com/JarbasHiveMind hivemind-core Noise protocol AES websocket
💡 Result:
In hivemind-core, the integration of the Noise protocol, AES, and WebSockets forms the foundation of its secure communication architecture, primarily implemented in protocol version 3 [1]. WebSockets act as the transport layer, with the hivemind-websocket-protocol serving as the reference implementation for persistent connections between satellites and the hub [2][3]. The Noise protocol is used for an authenticated key exchange during the handshake process, which enables the establishment of an always-encrypted session [1][4]. Specifically, it utilizes the poorman_handshake library, which wraps the vetted noiseprotocol library (leveraging pyca/cryptography) to support patterns like KK_PSK0 and XX_PSK2 [4]. This v3 protocol handshake handles the security negotiation, binding, and session key derivation [1]. Once the Noise handshake is complete, the session transitions to using AES (specifically AES-GCM) for transport encryption [1][5]. In v3 connections, this Noise-based transport layer provides replay-resistant, sequential encryption for all subsequent communication, replacing the legacy AEAD-based crypto methods used in earlier protocol versions [1][5].
Citations:
- 1: https://github.com/JarbasHiveMind/HiveMind-core/blob/HEAD/hivemind_core/protocol.py
- 2: https://github.com/JarbasHiveMind/hivemind-websocket-protocol
- 3: https://github.com/JarbasHiveMind/hivemind-core
- 4: https://github.com/JarbasHiveMind/poorman_handshake/blob/HEAD/poorman_handshake/noise/__init__.py
- 5: https://github.com/JarbasHiveMind/hivemind-websocket-client/blob/HEAD/hivemind_bus_client/client.py
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- local manifests ---'
fd -a -t f '^(pyproject\.toml|setup\.py|setup\.cfg|requirements.*|Pipfile|poetry\.lock)$' . \
-x sh -c 'echo "--- $1"; rg -n -C 3 "hivemind.?core|hivemind.?websocket|hivemind" "$1"' sh {}
printf '%s\n' '--- exact local core_tls references ---'
rg -n -C 3 '\bcore_tls\b' . || true
printf '%s\n' '--- stale transport-TLS documentation ---'
rg -n -C 4 'websocket has TLS|websocket TLS|wss://|server\.json.*ssl|TLS configured' \
docs hivemind_admin_panel tests --glob '*.md' --glob '*.py' --glob '*.js' --glob '*.html' || true
printf '%s\n' '--- upstream protocol source ---'
curl -fsSL https://raw.githubusercontent.com/JarbasHiveMind/HiveMind-core/dev/hivemind_core/protocol.py \
| rg -n -C 5 'class .*Protocol|protocol_version|min_protocol|Noise|handshake|encrypt|decrypt|password|api_key' \
| head -n 1200
printf '%s\n' '--- upstream configuration and websocket TLS source ---'
curl -fsSL https://raw.githubusercontent.com/JarbasHiveMind/HiveMind-core/dev/hivemind_core/config.py \
| rg -n -C 5 'ssl|tls|websocket|protocol|cipher|allowed' \
| head -n 800
curl -fsSL https://raw.githubusercontent.com/JarbasHiveMind/hivemind-websocket-protocol/dev/hivemind_websocket_protocol/__init__.py \
| rg -n -C 5 'ssl|tls|websocket|protocol|handshake|encrypt|decrypt' \
| head -n 800Repository: JarbasHiveMind/hivemind-admin-panel
Length of output: 50391
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- websocket repository branches ---'
git ls-remote --heads https://github.com/JarbasHiveMind/hivemind-websocket-protocol.git \
| head -n 30
printf '%s\n' '--- websocket repository tree ---'
curl -fsSL https://api.github.com/repos/JarbasHiveMind/hivemind-websocket-protocol/git/trees/HEAD?recursive=1 \
| jq -r '.tree[]?.path' | head -n 300
printf '%s\n' '--- core protocol version and handshake ranges ---'
curl -fsSL https://raw.githubusercontent.com/JarbasHiveMind/HiveMind-core/dev/hivemind_core/protocol.py \
| nl -ba | sed -n '100,165p;840,930p;1420,1535p'
printf '%s\n' '--- websocket TLS references from repository contents ---'
for path in \
hivemind_websocket_protocol/__init__.py \
hivemind_websocket_protocol/server.py \
hivemind_websocket_protocol/client.py \
README.md \
setup.py \
pyproject.toml
do
url="https://raw.githubusercontent.com/JarbasHiveMind/hivemind-websocket-protocol/HEAD/$path"
body="$(curl -fsSL "$url" 2>/dev/null || true)"
if [ -n "$body" ]; then
printf '%s\n' "--- $path"
printf '%s\n' "$body" | rg -n -C 5 'ssl|tls|cert|websocket|WebSocket|create_connection|server' || true
fi
doneRepository: JarbasHiveMind/hivemind-admin-panel
Length of output: 2430
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- websocket repository branches ---'
git ls-remote --heads https://github.com/JarbasHiveMind/hivemind-websocket-protocol.git \
| head -n 30
printf '%s\n' '--- websocket repository tree ---'
curl -fsSL 'https://api.github.com/repos/JarbasHiveMind/hivemind-websocket-protocol/git/trees/HEAD?recursive=1' \
| jq -r '.tree[]?.path' | head -n 300
printf '%s\n' '--- core protocol version and handshake ranges ---'
curl -fsSL https://raw.githubusercontent.com/JarbasHiveMind/HiveMind-core/dev/hivemind_core/protocol.py \
| nl -ba | sed -n '100,165p;840,930p;1420,1535p'
printf '%s\n' '--- websocket TLS references from repository contents ---'
for path in \
hivemind_websocket_protocol/__init__.py \
hivemind_websocket_protocol/server.py \
hivemind_websocket_protocol/client.py \
README.md \
setup.py \
pyproject.toml
do
url="https://raw.githubusercontent.com/JarbasHiveMind/hivemind-websocket-protocol/HEAD/$path"
body="$(curl -fsSL "$url" 2>/dev/null || true)"
if [ -n "$body" ]; then
printf '%s\n' "--- $path"
printf '%s\n' "$body" | rg -n -C 5 'ssl|tls|cert|websocket|WebSocket|create_connection|server' || true
fi
doneRepository: JarbasHiveMind/hivemind-admin-panel
Length of output: 2430
Retain a transport-security check or narrow the replacement claim.
hivemind-core does not provide this guarantee for every supported version. v0 has no handshake, v1/v2 expose the initial handshake before session-key establishment, and v3 establishes Noise after initial negotiation. Payload encryption does not replace TLS for protecting handshake metadata or authenticating the endpoint. Retain core_tls or an equivalent transport check, update docs/security.md, and add protocol-floor regression tests.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@hivemind_admin_panel/api.py` around lines 5037 - 5041, Revise the websocket
security handling around the protocol-version transport check: retain core_tls
or an equivalent transport-security validation instead of claiming ws:// is
always safe. Update docs/security.md to accurately describe handshake metadata
and endpoint-authentication risks across v0–v3, and add regression tests
enforcing the minimum supported protocol security behavior.
| function openSidebar() { | ||
| const bar = document.getElementById('sidebar'); | ||
| const backdrop = document.getElementById('sidebarBackdrop'); | ||
| const toggle = document.getElementById('navToggle'); | ||
| if (bar) { | ||
| bar.classList.add('open'); | ||
| bar.removeAttribute('inert'); | ||
| bar.removeAttribute('aria-hidden'); | ||
| } | ||
| if (backdrop) backdrop.classList.add('visible'); | ||
| if (toggle) { | ||
| toggle.setAttribute('aria-expanded', 'true'); | ||
| toggle.setAttribute('aria-label', 'Close navigation'); | ||
| } | ||
| // Move focus into the drawer. Without this, tabbing from the toggle walked | ||
| // straight past it — the drawer is earlier in the DOM — and landed on | ||
| // "Restart HiveMind" with an opaque backdrop over the page. | ||
| const target = bar && (bar.querySelector('.nav-item.active') || bar.querySelector('.nav-item')); | ||
| if (target) target.focus(); | ||
| // Stop the page scrolling underneath the backdrop. | ||
| document.body.style.overflow = 'hidden'; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Keep keyboard focus within the open drawer.
openSidebar() moves initial focus into #sidebar, but it does not trap focus or make the rest of the page inert. After the last drawer control, Tab can move to controls behind the visible backdrop. The Escape listener can also close the drawer from any focused element.
Make content outside #sidebar inert while the drawer is open, or add a focus trap. Limit Escape dismissal to the drawer context.
Also applies to: 4701-4707
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@hivemind_admin_panel/static/js/app.js` around lines 4628 - 4648, Update
openSidebar() to keep keyboard focus within `#sidebar` while it is open by making
outside content inert or implementing a focus trap, including wrapping Tab
navigation from the last control to the first. Update the Escape-key listener
near the related sidebar handlers so it dismisses the drawer only when focus is
within the drawer context, and restore outside interactivity when closing.
| function _syncSidebarInertness() { | ||
| const bar = document.getElementById('sidebar'); | ||
| if (!bar) return; | ||
| if (_mobileLayout() && !bar.classList.contains('open')) { | ||
| bar.setAttribute('inert', ''); | ||
| bar.setAttribute('aria-hidden', 'true'); | ||
| } else { | ||
| bar.removeAttribute('inert'); | ||
| bar.removeAttribute('aria-hidden'); | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Synchronize drawer state when leaving the mobile layout.
If _mobileLayout() changes from true to false while the drawer is open, _syncSidebarInertness() only removes inert and aria-hidden. It leaves .open, .visible, aria-expanded="true", and document.body.style.overflow = "hidden" set. The desktop page then keeps the backdrop and scroll lock until the user clicks the backdrop.
Close the drawer and clear all related state during this breakpoint transition.
Also applies to: 4699-4699
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@hivemind_admin_panel/static/js/app.js` around lines 4674 - 4684, The
_syncSidebarInertness function must fully close and reset the drawer when
transitioning from mobile to desktop, clearing the sidebar’s open/visible state,
aria-expanded value, backdrop, and document.body scroll lock while retaining the
existing inert and aria-hidden synchronization.
The panel did not work on a phone
Not "looked cramped" — did not work. The stylesheet had a 768px breakpoint that slid the sidebar off-screen and waited for a
.sidebar.openclass:Nothing ever added that class.
grep -rn "sidebar.open\|hamburger\|toggleSidebar"across the markup and both JS files returned nothing. So on a phone you signed in, landed on the dashboard, and could not reach a single other page — Playwright's diagnosis was blunt:element is outside of the viewport.Fixed with the control the stylesheet was already written for: a ☰ in the topbar under 768px, a backdrop, an Escape binding, and auto-close when a destination is picked (a drawer that covers the page you just asked for is its own bug).
Two layout bugs behind it
Wide content dragged the page sideways. Measured: clients overflowed by 398px, monitor by 2838px, so the layout slid out from under the sticky topbar. The fix that matters is
min-width: 0on the layout chain — a grid child defaults tomin-width: auto, so a wide table widens its ancestors rather than letting the scroll container do its job. Tables now scroll inside their own box; logs and key material wrap.The topbar had a fixed
height: 64px. Once its controls wrapped to a second row, the sticky bar kept that height and painted its overflow straight over the first card — the status pill landed on top of the security banner. Visible in the before/after captures.Docs
Every page now shows the screen it describes, at widescreen and on a phone — 35 screenshots from the live deployment. Downscaled and palette-reduced to 2.2MB total rather than the 8MB they came out at.
Troubleshooting gains the five failures I actually hit running this thing today, which is the useful kind:
hivemind-core reset-noise-pinAddress already in useon 5678 → the panel owns the hub in-process; a secondhivemind-coreservice cannot also have itKeyError: 'vad'rather than falling backVerification
Summary by CodeRabbit
Documentation
Enhancements
Changes