The MCP server instructions string omitted three behaviours added in
earlier PRs, leaving agents without context on them:
- send_file / download_file tools (#1829, #1830)
- [file:]/[image:]/[audio:]/[video:] attachment markers in read_room (#1830)
- unread guard: send_message, send_dm, send_file, send_reply all
reject if the room has unread messages; read_room + mark_read
are required first (#1828)
Closes#1828. Closes#1829. Closes#1830.
fix(dashboard): update 'view queue' link to /builds.html
The build queue moved to its own /builds.html page. The queue-summary
'view queue →' link in tabs.js still pointed at /core.html, so clicking
it landed on the wrong page.
fix(broker): filter agent inbox to unread (acked_at IS NULL)
recent_for was returning all messages regardless of ack state, so the
agent inbox showed everything even after 'mark all read'. Now filters
to acked_at IS NULL — mirroring exactly what mark_all_read drains —
so the inbox empties on reload after the operator drains it.
When a tool call fails, claude wraps the result text in
<tool_use_error>...</tool_use_error> XML tags. The terminal was
displaying these raw, producing output like:
'<tool_use_error>File has not been read yet.</tool_use_error>'
Fix renderToolResult in app.js:
- Check c.is_error on the tool_result content block.
- Strip the <tool_use_error>...</tool_use_error> wrapper from the text.
- Render error results with a '✗' prefix under '.tool-result.error'
(flat, ≤120c) or '.tool-result-block.error' (<details>, longer text).
Add .live .tool-result.error { color: var(--red); } to terminal.css
so error results are visually distinct (red, same as turn-end-fail).
Update terminal-rendering.md row taxonomy to document the two new
error row classes.
Closes#2104.
mode_of mapped .nix to hash-mode (# only); nix also supports /* */ block
comments, so a long one would slip past. Split .nix into its own 'nix' mode
that handles BOTH # line comments and /* */ blocks. .sh stays hash (no block
comments in sh). Verified: tree still 6 offenders (no nix block offenders), and
a 33-line nix /* */ block is now caught.
Flags any contiguous comment block longer than 30 lines — the threshold
above which a why/impl-notes block should move to docs/ rather than live
in-code (the #2077 rubric, made self-enforcing).
- scripts/check-comment-blocks.sh: git+awk, mirrors check-issue-refs.sh's
capture-output shape (robust to xargs batching). Handles # line comments
(nix/sh), // line comments (rs/js/ts), and /* */ (rs/js/ts/css) + <!-- -->
(html) block comments. Blank separates line-comment blocks; a blank inside
a /* */ / <!-- --> block stays part of it. lint:allow-long-comment escape
hatch. Threshold is a tunable constant.
- ci.yml: own 'comment-block lint' job, kept OUT of required checks while the
tree settles (red signal, not a merge gate), like the tracker-tag lint.
Current tree has 6 blocks > 30 (all in the frontend + hive-c0re-core #2077
slices, none in nix/infra): matrix-accounts.js, permissions.js,
stream-worker.js, terminal.js, hivectl.rs:1036, assets.rs. Non-required, so
non-blocking — they're the remaining #2077 targets for those area owners.
'Mirrors the logic previously embedded in hive-ag3nt' is pure provenance
(where the code moved from) — the #2077 rubric says drop impl-history. The
rest of my slice (nix modules + hive-priv/matrix-mcp/bash-mcp + forge.rs) is
already lean: surveyed it, the long comment blocks are all legit why/invariant/
contract docs under the 30-line threshold, not bloat.
ensure_mirror_repo treated 409|422 as success (copied from ensure_org, where
422 *does* mean 'org exists'). For the migrate endpoint 422 is a validation
error (bad clone_addr/service); the GET-first check is the real idempotency
guard, so 409 stays as a race guard but 422 now falls through to the bail arm
(→ caller warns) instead of silently dropping a misconfigured mirror.
Per mara: the mirror seeding belongs in hive-c0re's forge provisioning
sweep, where the core admin token + org-ensure already live — not a parallel
host-side nix oneshot.
- forge.rs: ensure_mirrors() reads HYPERHIVE_FORGE_MIRRORS (JSON list of
{upstream,dest}), ensures each dest org (reuse ensure_org) + creates the
pull-mirror via the migrate API (reuse forge_http, serde_json::json! body,
409/existing = success). Called in ensure_all() right after the SEEDED_ORGS
loop (token in scope, warn-and-continue like the other ensure_* steps).
- hive-forge.nix: forward effectiveMirrors to c0re via
systemd.services.hive-c0re.environment.HYPERHIVE_FORGE_MIRRORS; drop the
forgejo-seed-mirrors.service + its script + the host-side core-token read.
Keep the forge.mirrors option, DEFAULT_ACTIONS_URL=self (CI-gated), and the
dest-shape / no-c0re-namespace-collision assertions.
Verified locally: nix parse + treefmt (incl rustfmt) clean; serde/serde_json
patterns mirror dashboard.rs. cargo build runs in CI (no cc in my container).
nixfmt wanted the ${...} on a single line (verified locally:
nix build .#checks.x86_64-linux.formatting passes). The earlier CI 'docs'
failure was a transient muede-pc2 build hiccup — the docs check builds clean
locally on the same drv.
- drop the three cross-ref tracker tags from comments/description (prose only)
- build the orgs + migrate JSON bodies with jq -n --arg (an upstream URL
containing a quote no longer corrupts the request)
- don't auto-append the actions/checkout mirror when the operator already
declared that dest (avoids a duplicate effectiveMirrors entry when CI is on)
General-purpose mirror mechanism for the internal forge, per mara's call on
#2074 (real Forgejo pull-mirrors, nix-configured — not a pushed clone).
- services.hyperhive.forge.mirrors: list of { upstream, dest } pull-mirrors,
any repo. Each is created as a real Forgejo pull-mirror (re-syncs from
upstream), dest = <owner>/<repo> in its own org.
- When forge.ci.enable is set: an actions/checkout mirror is auto-appended +
forgejo DEFAULT_ACTIONS_URL is pointed at this instance, so CI
'uses: actions/checkout@vN' resolves on loopback — immune to a host-resolver
blip that previously reded every checkout (the seed/re-sync needs external
DNS, but that's off the CI critical path).
- forgejo-seed-mirrors.service: host-side oneshot (the core admin token never
enters a container), modelled on hive-ci-prefetch — waits <=60s for the core
token, then idempotently ensures each dest org + creates the pull-mirror via
the migrate API. partOf the forge container so it re-ensures on restart.
- assertions: dest must be <owner>/<repo>; mirror orgs can't shadow the
c0re-managed namespaces (config/shared/agents/core) so the seed never races
hive-c0re's own provisioning.
Supersedes #2074 (the raw-clone stopgap) as the durable #2072 fix.
General-purpose Forgejo pull-mirror config (services.hyperhive.forge.mirrors:
list of {upstream, dest}). When CI is enabled, auto-append an actions/checkout
mirror + point forgejo DEFAULT_ACTIONS_URL at this instance so CI's
actions/checkout@vN resolves on loopback (immune to host-resolver blips, #2072).
Seed oneshot (creates the dest orgs + pull-mirrors via the migrate API) is the
next commit.
Remove or shorten comment blocks that:
- explain where code used to live (impl history)
- duplicate rationale already in docs/web-ui.md
- contain speculative/future-work notes
Changes:
- tabs.js: drop "SYST3M tab used to render this" history; keep badge purpose
- schedules.js: drop "used to be a card layout" history + speculative nit note
- stream-worker.js: replace 10-line problem-statement with docs pointer
(rationale already in docs/web-ui.md SSE multiplexing section); trim
future-work parenthetical from subscription-tracking comment
- system-sections.css: drop extraction-history prose; keep what it does
- core.css: drop move-history prose; keep what it imports and why
Part of issue cleanup per operator feedback.
New standalone page /builds.html consolidating rebuild queue, meta
inputs, and build log history into one place, with a new 'Builds' home
tile linking to it. Addresses mara's request: new sub-page with a new
home tile, all three items moved there.
Changes:
- builds.html: new page with three sub-tabs: R3BU1LD QU3U3, M3T4 1NPUTS,
BUILD L0GS. Same minimal-chrome header + createTabStrip pattern as core
and logs pages.
- builds.js: new bundle combining rebuild queue renderer (from core.js),
meta inputs renderer (from core.js), rebuild-live-log renderer (from
core.js), and build log history renderer (from logs.js). Deep-links to
/builds.html?id=N#buildlogs. Count pill id: builds-tab-count-rebuild.
BUILD L0GS tab lazy-loads on first activation.
- builds.css: @imports system-sections.css (rebuild queue + meta inputs +
live-log styles) and logs.css (build-logs-* component styles).
- build.mjs: register builds.js, builds.css, builds.html.
- core.html: remove R3BU1LD QU3U3 + M3T4 1NPUTS tabs (now on builds.html).
Default tab changes to K3PT ST4T3.
- core.js: remove renderMetaInputs, renderRebuildQueue + helpers,
renderRebuildLiveLog + live-log state, elapsed-time tickers,
updateRebuildCount, and the rebuild_queue/meta_inputs SSE handlers.
Remove openBuildLogStream + util imports no longer needed.
- core.css: remove .rebuild-live-log-* rules (moved to system-sections.css
so builds.css can share them via @import).
- system-sections.css: add .rebuild-live-log-* styles (moved from core.css);
update comment to mention builds.html.
- logs.html: remove BUILD tab + pane (moved to builds.html).
- logs.js: remove fetchBuild(), fmtTs, fmtDuration, openBuildLogStream
import, and rebuild_queue_changed SSE debounce. Default tab: 'agent'.
SSE stream retained for audit_entry_added live-appends.
- index.html: add Builds tile (🔨, rebuild queue · meta inputs · build
logs); update Core tile desc to 'kept state · container load'; update
Logs tile desc to remove 'build'.
The variable was misleadingly named `tombstones` and commented as
'any name here is a tombstone', but kept_state_names() returns ALL
agents with a state dir on disk — both live containers and soft-deleted
tombstones. The logic was always correct (union with the live roster
filters both), but the comment would mislead future readers.
Rename the variable to `kept` and update comments to accurately
describe the contents.