Commit graph

1,353 commits

Author SHA1 Message Date
damocles
5e0da97ee5 fix: update stale doc comment example root→ruth in capabilities.rs 2026-06-02 18:18:06 +02:00
damocles
89665b94de feat(#1014): rename manager agent root→ruth across all crates + frontend 2026-06-02 18:18:06 +02:00
damocles
0c5760b0da feat(#1014): rename manager agent 'root' to 'ruth' in lifecycle + sh4re 2026-06-02 18:18:06 +02:00
atlas
268c2a66ad fix(#1087): use correct "cmd" tag in matrix wake signal
hive_sh4re::Request uses #[serde(tag = "cmd")] so Wake serialises as
{"cmd":"wake",...}. The wake.rs in hive-matrix-mcp was sending
{"kind":"wake",...} — the harness could not deserialise the message
and silently discarded every incoming matrix event.

Also: drain the server's response line instead of just shutting the
write half. Without the drain the server got ECONNRESET writing back,
which logged a spurious error even though the wake itself was now
processed.

Root cause of the matrix notification blackhole reported in #1087.
2026-06-02 17:27:25 +02:00
damocles
eae0e875cf feat(#1086): serialize perm changes through rebuild queue
add QueueKind::PermChange — dashboard tool-group and capability
handlers no longer write the shared JSON files inline. instead they
enqueue a PermChange entry; the FIFO worker applies the file write
then calls rebuild_agent so the updated env var takes effect.

concurrent batch-apply actions for different agents previously raced
on tool-groups.json / capabilities.json (last write wins, earlier
change silently dropped). serialising through the queue prevents this.

dedup check extended with perm-type discriminant so tool-groups and
capabilities changes for the same agent are kept as distinct entries
and never collapse into one slot.
2026-06-02 16:42:22 +02:00
damocles
dce2bd0686 feat(#343): route container restart through rebuild queue 2026-06-02 13:34:24 +02:00
damocles
817d94023d feat(#1081): add --approve/--request-changes/--comment to pr-reviews 2026-06-02 13:33:30 +02:00
iris
5d4b62ccca fix: Diagnostics description — get_logs reads sub-agent container journal, not host journal 2026-06-02 12:53:50 +02:00
iris
2368bec634 feat(#1082): add description() to ToolGroup + Capability; expose in API + UI tooltips
- hive-sh4re: ToolGroup::description() and Capability::description() return
  short human-readable strings for each variant
- hive-c0re: ToolGroupsSnapshot and CapabilitiesSnapshot now include a
  `descriptions` map (name → description); get_capabilities now iterates
  Capability::ALL instead of hardcoding the list
- tabs.js: renderToolGroups + renderCapabilities use descriptions[name] as
  the column header title attribute (native browser tooltip on hover)
2026-06-02 12:53:50 +02:00
iris
4a632fabcc docs(CLAUDE.md): fix stale systemd-run reference in gateway_nginx.rs entry
Argus flagged that since PR #1054 the nginx reload path is
`gateway_systemctl(["reload", "nginx"])` = `systemctl -M hive-gateway reload nginx`.
Replace the stale `systemd-run --machine=hive-gateway` reference.
2026-06-02 12:47:36 +02:00
iris
b8b571b626 docs(CLAUDE.md): add missing hive-c0re modules to file map
Four modules were absent: capabilities.rs, build_logs.rs,
gateway_nginx.rs, priv_client.rs. Added at their natural
positions alongside related modules.
2026-06-02 12:47:36 +02:00
iris
0da736f2a1 fix(docs): web_tools is a tool group, not a capability
Remove web_tools from the C4P4B1L1T13S table in dashboard.md and add
it to the T00L GR0UPS section with a note that it gates Claude built-ins
rather than MCP tools. Fix turn-loop.md to say 'tool-group-gated' and
'web_tools tool group' throughout.
2026-06-02 12:47:18 +02:00
iris
91ad9877dc docs(web-ui): add P3RM1SS10NS to dashboard tab list in index 2026-06-02 12:47:18 +02:00
iris
de8c446a3a docs: document web_tools capability in turn-loop and dashboard 2026-06-02 12:47:18 +02:00
iris
834d9cb2c4 docs(web-ui): update CSS bundle description for split stylesheet layout 2026-06-02 12:47:18 +02:00
iris
f55d3baa0a docs(web-ui): add P3RM1SS10NS to tab strip list and URL hash list 2026-06-02 12:47:18 +02:00
iris
b3ccd1500c docs(web-ui): document P3RM1SS10NS tab and tool-groups/capabilities endpoints 2026-06-02 12:47:18 +02:00
iris
5946c8fbd8 docs(gotchas): update stale 'claude's Bash tool' reference to bash_run
The Bash built-in is now denied; bash_run is the correct MCP tool.
2026-06-02 12:46:53 +02:00
iris
50f14f28ff fix(dashboard): have get_capabilities iterate Capability::ALL
The hardcoded vec was a maintenance hazard — any new capability added
to Capability::ALL would silently be omitted from the permissions UI
column list until get_capabilities was manually updated.

Now both the GET and POST handlers derive their known-capability lists
from the same Capability::ALL source of truth.
2026-06-02 12:46:12 +02:00
iris
febb10a7d7 docs(CLAUDE.md): note capabilities in conventions.md file map entry 2026-06-02 12:46:12 +02:00
iris
1e04047059 docs(conventions): add Capabilities section parallel to Tool groups
Capabilities were added with the permissions tab but conventions.md only
documented tool groups. Adds a full Capabilities section covering: the
known capabilities table, config storage path, HIVE_CAPABILITIES env var
injection, runtime resolution, operator-only grant constraint, and the
pattern for adding a new capability.
2026-06-02 12:46:12 +02:00
iris
14368b2e09 docs(dashboard): add L0GS page section documenting three sub-tabs
/logs.html was undocumented — only mentioned in passing in API
endpoint lists. Adds a proper section covering BUILD / AGENT /
SYSTEM sub-tabs, their API endpoints, and behaviour.
2026-06-02 12:45:42 +02:00
iris
30c8459add docs(persistence): expand meta/ dir section to list config JSON files
The meta/ section only described the flake. Added entries for
topology.json, tool-groups.json, and capabilities.json — the three
system-level config files also committed there — with their writers,
readers, and injected env vars.
2026-06-02 12:43:59 +02:00
damocles
cbd14e9cd0 fix(#1066): retry turn once on 401 before parking for re-login 2026-06-02 12:43:41 +02:00
iris
ae695931ce chore(agent): move screen.html inline styles into agent.css; add --blue/--yellow/--subtext0 to palette 2026-06-02 12:43:11 +02:00
iris
c0f16c870f fix(web_tools): remove WebFetch/WebSearch from permissions.deny
The deny list takes precedence over --allowedTools, so granting the
web_tools group had no effect — both tools were silently blocked.

WebFetch/WebSearch are now gated solely via --tools (builtin_tools_arg):
agents without the web_tools tool group don't get them in --tools so
claude never sees them; agents with the group get them in both --tools
and --allowedTools.
2026-06-02 11:31:33 +02:00
iris
f6b80cf02e feat(#1065): web_tools tool group gates WebFetch/WebSearch built-ins
Replaces the earlier capability-based approach (closed #1069) with a
ToolGroup — capabilities are for privileged system access, web egress is
a tool permission.

Add ToolGroup::WebTools to hive-sh4re:
- tools() returns &[] (no MCP tools gated)
- builtin_tools() returns &["WebFetch", "WebSearch"] — new method on ToolGroup
- Present in ALL and as_str() → "web_tools"

In hive-ag3nt/mcp.rs:
- allowed_tools_arg() now iterates group.builtin_tools() to prepend any
  group-gated built-ins alongside the base ALLOWED_BUILTIN_TOOLS set
- builtin_tools_arg_for_flavor(flavor) replaces builtin_tools_arg() so
  the flavor-correct effective groups are used when building --tools
- builtin_tools_arg() kept as a flavor=Agent convenience alias
- turn.rs updated to call builtin_tools_arg_for_flavor(files.flavor) so
  manager sessions also see web tools when web_tools is in their groups

The dashboard T00L GR0UPS table gains a web_tools column automatically
(ToolGroup::ALL drives the columns).
2026-06-02 11:31:08 +02:00
iris
cd6cbf9997 chore: fix stale build.mjs comments + CLAUDE.md dashboard package map 2026-06-02 11:19:32 +02:00
iris
ea5115c3a6 feat(dashboard): split monolithic CSS into common + per-page bundles
dashboard.css was 2500+ lines covering every page. Split into four
separate esbuild entry points:

- common.css  — @hive/shared imports + shared typography, badges,
                buttons, inbox/compose, side panel, diff panel,
                path linkification, logs-header chrome (shared by
                flow + logs)
- dashboard.css — dashboard-only styles (tabs, container rows,
                  approvals, questions, permissions, schedules, etc.)
- flow.css    — flow page chrome (frosted header, composer, inbox pill)
- logs.css    — log viewer sub-tabs (journal-*, build-logs-*)

Each HTML file now loads common.css + its own page-specific bundle.
build.mjs updated to produce all four CSS outputs. All builds pass.

Closes #1056
2026-06-02 11:19:32 +02:00
atlas
ed6f40ba40 fix(#1061): suppress tuwunel default displayname suffix
Tuwunel 1.6.1 appends " 💕" to every new user's display name via the
new_user_displayname_suffix config option. Set it to empty string so
agent and operator matrix accounts get clean names.

Existing users (atlas, mara, root) need a one-time display name reset.
Atlas's was already corrected via the client API.
2026-06-02 11:18:38 +02:00
iris
f1103b1dbf chore(agent): move last inline style from stats.html into agent.css 2026-06-02 11:17:59 +02:00
iris
e350e20145 chore(agent): move stats page inline styles into agent.css
stats.html had a <style> block with all its page-specific CSS inline.
Move to agent.css under a '--- /stats page ---' section, renaming
the generic .grid/.card/.empty-note classes to .stats-grid/.stats-card/
.stats-empty-note to avoid future collisions with other agent pages.
2026-06-02 11:17:59 +02:00
iris
c7f02993d0 chore(#1055): address argus review nits
- rename cap-cap-col → cap-col; add CSS rules for .cap-col and .cap-save-col
- drop zero-width-space replace in capability header cells (nowrap makes it a no-op)
- add Capability::ALL to hive-sh4re; validate incoming cap strings in post_capabilities
2026-06-02 11:15:33 +02:00
damocles
3a1cfa26ec fix(#1060): dynamic meta commit message from staged files; skip commit on no-op 2026-06-02 09:33:16 +02:00
damocles
4ee7967e2a deprecate allowedBashPatterns with warning instead of hard removal 2026-06-02 09:28:14 +02:00
damocles
29724f5021 drop orphaned bash-allow doc comment on load_extra_mcp 2026-06-02 09:25:50 +02:00
damocles
88f22065b0 feat(#1058): disallow built-in Bash; remove allowedBashPatterns; prompt sweep 2026-06-02 01:14:24 +02:00
iris
013e8740bd feat(#1053): permissions tab — capabilities UI + move tool-groups
Add a new P3RM1SS10NS tab to the dashboard that consolidates all
per-agent permission configuration:

Backend:
- GET /api/capabilities returns { caps: [...], assignments: {...} }
  driven by Capability::ALL variants (manage_root_agent,
  read_host_journal, query_agent_state)
- POST /api/capabilities/{agent} writes capabilities.json and queues
  a rebuild so HIVE_CAPABILITIES takes effect

Frontend:
- New 'permissions' entry in TABS, placed after 'system'
- P3RM1SS10NS tab pane with two sections:
  C4P4B1L1T13S — agents × capabilities checkbox matrix (.cap-*)
  T00L GR0UPS — agents × tool-groups checkbox matrix (.tg-*) moved
    from SYST3M tab
- activateTab('permissions') fetches both tables; neither has an SSE
  channel so they re-fetch on each activation to stay fresh
- CSS for .cap-* mirrors the .tg-* layout (scrollable, Catppuccin)
2026-06-02 01:11:07 +02:00
damocles
9d11e5b6d6 fix(#1052): use systemctl reload nginx instead of systemd-run 2026-06-02 01:00:48 +02:00
damocles
637b170cc5 fix(#1052): use full nginx path in systemd-run reload (exit 203 = EXEC) 2026-06-02 00:52:56 +02:00
damocles
a187ef3dfb fix(#1049): regenerate Cargo.lock after libc dep addition 2026-06-02 00:39:07 +02:00
atlas
9d816431dc fix(#981): validate runner credentials on every boot, purge stale .runner
hive-ci-register.service now runs unconditionally on every boot (not
just when .runner is absent). Before fetching a registration token it
validates existing .runner credentials via the forge admin API:
- 200: runner still registered, write dummy token and exit
- 404: runner deleted from forge, purge .runner and re-register
- 000: forge unreachable, keep credentials (runner surfaces the error)
- other non-200 or malformed .runner: purge and re-register

Removes ConditionPathExists so stale credentials from a wiped forge
no longer block the runner indefinitely. Updates docs/ci.md to match.
2026-06-02 00:27:47 +02:00
atlas
4bd0228de0 docs(gateway): update Basic auth section for fixed htpasswd path
Remove stale htpasswdFile option from nix example (option no longer
exists). Update hivectl command examples to drop --file flag (now
optional with standard default). Add description of the fixed path
and how it's exposed inside the container.
2026-06-02 00:26:10 +02:00
atlas
167b4fa1f3 refactor(gateway): fixed htpasswd path, drop htpasswdFile option
Remove the custom htpasswdFile option and bind-mount. The htpasswd file
now lives at the fixed path /var/lib/hyperhive/gateway/gateway.htpasswd
on the host, which is already exposed inside the container at
/run/hive-state/gateway.htpasswd via the existing gateway state
bind-mount — no extra bind-mount needed.

A tmpfiles rule pre-creates the file so nginx can open it even before
any users exist (empty file → all requests return 401, which is correct).

hivectl gateway commands default --file to the standard path so
`hivectl gateway create-user alice` just works without any flags.
2026-06-02 00:26:10 +02:00
atlas
ba1d096391 fix(gateway): interpolate actual htpasswdFile path in 401 page
Per argus review: the hardcoded /etc/hyperhive/gateway.htpasswd
example was wrong for operators with a custom htpasswdFile path.

Move the unauthorized.html from the static agentErrorPagesDir derivation
into a pkgs.writeText inside the lib.optionalAttrs guard where
cfg.auth.htpasswdFile is in scope and statically known non-null.
The rendered page now shows the operator's actual configured path.
2026-06-02 00:26:10 +02:00
atlas
a248c6bee1 feat(gateway): custom 401 page explaining how to add users
When HTTP Basic auth is enabled and credentials are absent or rejected,
nginx serves a Catppuccin-styled 401 page that tells the operator which
hivectl command to run to create a user. Uses error_page 401 =401 so
the browser still receives a 401 status (login dialog fires on first
visit) while getting a human-readable body when the dialog is dismissed.

The exact-match location (= /__hive_auth_unauthorized) beats location /
in nginx's prefix ordering so the internal subrequest does not loop back
through auth_basic.
2026-06-02 00:26:10 +02:00
damocles
e4147e5cec fix(#1045): declare libc workspace dep + add to hive-c0re 2026-06-01 23:44:34 +02:00
iris
07e729ae24 chore: last frontend style nits — http case in common.js, setTimeout wrappers
- common.js fetchStateFile: 'HTTP' -> 'http' — last uppercase instance
  in the frontend (tabs.js, app.js, logs.js already fixed in prior PRs)
- tabs.js: two redundant arrow wrappers in setTimeout dropped —
  setTimeout(() => f(), N) -> setTimeout(f, N) where f takes no args
2026-06-01 23:34:52 +02:00
atlas
db50da570a refactor(#1003): nixpkgs + nixpkgs-unstable as top-level meta inputs
Per mara's direction: both nixpkgs and nixpkgs-unstable are now
top-level meta flake inputs with explicit store-path URLs.  Hyperhive
follows them rather than the other way around:

  inputs.nixpkgs.url            = "path:${pkgs.path}";
  inputs.nixpkgs-unstable.url   = "path:${nixpkgs-unstable}";
  inputs.hyperhive.url          = "...";
  inputs.hyperhive.inputs.nixpkgs.follows            = "nixpkgs";
  inputs.hyperhive.inputs.nixpkgs-unstable.follows   = "nixpkgs-unstable";

New NixOS host options (auto-set at build time, overridable):
  services.hyperhive.c0re.nixpkgsFlake
    default: "path:${pkgs.path}" — host's evaluated nixpkgs.
  services.hyperhive.c0re.nixpkgsUnstableFlake
    default: "path:${nixpkgs-unstable}" from hyperhive's flake.nix —
    the channel that carries claude-code.  Operators can override to
    track a different unstable snapshot.

Legacy fallback (both args empty) preserved for backward compat.
Two new Rust tests cover the full-URL and fallback paths.
2026-06-01 23:30:04 +02:00
atlas
fe5a41288d feat(#1003): inject pkgs.path into meta flake as explicit nixpkgs.url
meta flake was using `nixpkgs.follows = "hyperhive/nixpkgs"` but
`hyperhive` is a store-path input, so nix resolves hyperhive's own
pinned lock rather than the host's follows-substituted version.
When an operator sets `inputs.hyperhive.inputs.nixpkgs.follows =
"nixpkgs"` in their host flake, the meta flake was silently ignoring
it and using hyperhive's pinned nixpkgs instead.

Fix: hive-c0re.nix injects `--nixpkgs-flake path:${pkgs.path}` into
the daemon's ExecStart. `pkgs` IS the host's nixpkgs when follows is
set; otherwise it's hyperhive's own pin — so the meta flake gets the
right nixpkgs in both cases. render_flake emits `nixpkgs.url = "..."`
(explicit) when nixpkgs_flake is non-empty, falling back to the old
`follows` form when empty for backward compat.
2026-06-01 23:29:54 +02:00