Commit graph hyperhive/hive-c0re
Author SHA1 Message Date
atlas
97edd6baac feat(#2346): request_merge_config_pr — submission path for the PR-based config flow
MergeConfigPr approvals had a fully-implemented approve handler
(run_merge_config_pr, ff_push_to_main, mark_pr_merged) and dashboard
display, but no way to submit one.  An agent with the `approvals` tool
group calling request_merge_config_pr(agent, pr_number) is the missing
piece.

What this adds:
- RequestMergeConfigPr variant in hive-sh4re AgentRequest + ToolGroup::Approvals
- submit_merge_config_pr: fetches PR head sha (the drift-gate reviewed sha),
  queues a MergeConfigPr row, sets fetched_sha, emits approval_added with
  pr_number so the dashboard card links to the forge PR
- handle_request_merge_config_pr: topology (require_descendant) +
  tool-group (require_group(approvals)) guards before submit
- socket_server/mod.rs: dispatch arm for RequestMergeConfigPr
- hive-ag3nt MCP tool: request_merge_config_pr with full description
- docs/tools/lifecycle.md: documents the new tool + boundary table row

Unlike submit_apply_commit, no flake pre-flight at submission time (eval-
verify happens at approval time inside run_merge_config_pr, same as the
rest of the merge pipeline).  Applied repo must already exist (guard added
with a clear error message pointing at request_apply_commit for first-spawn).
2026-07-11 12:19:52 +02:00
damocles
cef9e633f7 docs(#1970): rewrite for UI-driven shape (github.enable + host switch), purge githubAccount refs, regen hivectl-cli.md 2026-07-11 12:18:55 +02:00
damocles
18965ff7bd feat(#1970): host services.hyperhive.github.enable (default true) + meta.rs propagation of the off-switch 2026-07-11 12:18:55 +02:00
damocles
3e5aff39eb fix(#1970): address argus review — # Errors doc, regen hivectl-cli.md, GET /api/github-account status 2026-07-11 12:18:55 +02:00
damocles
1b6b307aa7 feat(#1970): add POST /api/github-account dashboard endpoint for the credentials UI 2026-07-11 12:18:55 +02:00
damocles
80ef7d8151 wip(#1970): github-token injection path (priv wire + hive-priv handler + priv_client + hivectl github set-token) 2026-07-11 12:18:55 +02:00
atlas
dcd559e7c7 fix(#2368): AGENT_RUNTIME_ROOT → priv_proto; fix stale priv comment; cross-ref lockstep
- Add `priv_proto::AGENT_RUNTIME_ROOT` to hive-sh4re as the shared
  single source for the per-agent runtime root path.  hive-priv now
  imports it instead of carrying a local const with a stale comment
  that still pointed at `coordinator::AGENT_RUNTIME_ROOT` (removed in
  #2285/#2367 — moved to `paths::agent_runtime_root()`).

- Add 'must stay in sync' cross-ref comments on both sides of the
  privsep boundary:
    · priv_proto::META_DIR ↔ paths::meta_root()
    · priv_proto::AGENT_STATE_ROOT ↔ paths::AGENTS_ROOT
    · priv_proto::AGENT_RUNTIME_ROOT ↔ paths::RUNTIME_ROOT + agent_runtime_root()
    · paths::AGENTS_ROOT ↔ priv_proto::AGENT_STATE_ROOT
    · paths::RUNTIME_ROOT ↔ priv_proto::AGENT_RUNTIME_ROOT

  The dep graph prevents a shared import (hive-sh4re is a leaf; both
  hive-c0re and hive-priv depend on it but not each other), so the
  lockstep comments are the enforced contract.
2026-07-11 01:22:50 +02:00
damocles
dfbf198ef3 fix(#2279): idempotent column-guard migrations, drop invalid ADD COLUMN IF NOT EXISTS 2026-07-10 22:05:08 +02:00
atlas
c47faf0af9 fix: idempotent migrations (ADD COLUMN IF NOT EXISTS), stale doc, safety note 2026-07-10 22:05:08 +02:00
atlas
7d36ec5e1f fix(#2279): versioned DB migrations via schema_versions table
Replace the try-and-ignore-duplicate-column approach in apply_migrations
with proper schema versioning using a shared schema_versions table.

## mechanism

New function: db::apply_versioned_migrations(conn, subsystem,
legacy_column, migrations). Tracks the applied-migration count in a
schema_versions table (one row per subsystem key). Only migrations past
the stored version run.

Legacy detection: pre-versioning databases have no schema_versions row.
The legacy_column tuple (table, column) identifies a column that exists
only in a fully-migrated legacy database. If present, all known
migrations are skipped. If absent, migrations start from 0.

## stores migrated

- broker: removes bespoke ensure_message_columns / ensure_reminder_columns.
  Unified into BROKER_MIGRATIONS (v1-v5). Legacy detector: messages.priority
  (added in the last pre-versioning migration).
- approvals: 4 historical migrations (v1-v4). Legacy detector:
  approvals.submitter.
- operator_questions: 3 historical migrations (v1-v3). Legacy detector:
  operator_questions.target.
- scheduled_prompts: 1 historical migration (v1). Legacy detector:
  scheduled_prompts.paused_at_unix.

apply_migrations removed (no callers).

## tests (db.rs)

- fresh_install_runs_all_migrations
- legacy_install_skips_all_migrations
- partial_migration_resumes_from_version
- already_at_latest_is_noop
- multiple_stores_in_same_db
2026-07-10 22:05:08 +02:00
damocles
556a213320 refactor(#2285): inline remaining 1:1 path wrappers (meta_dir, marker fns, host_conf_path) 2026-07-10 20:32:03 +02:00
damocles
cfb84b420a refactor(#2285): drop coordinator 1:1 path accessors, callers use paths:: directly 2026-07-10 20:32:03 +02:00
damocles
187c364feb refactor(#2285): repoint all hive-c0re host-path consumers to paths.rs 2026-07-10 20:32:03 +02:00
damocles
4162f557c9 refactor(#2285): repoint knowledge + forge core-token to paths.rs consts 2026-07-10 20:32:03 +02:00
damocles
1cefaf2c16 refactor(#2285): add consolidated path fns/consts to paths.rs (foundation) 2026-07-10 20:32:03 +02:00
damocles
e0d5c98356 refactor(#2282): split dag_progress out of hivectl.rs 2026-07-10 19:09:14 +02:00
damocles
4fd3928506 feat(#2282): animated indicatif DAG progress render for hivectl wait 2026-07-10 19:09:14 +02:00
atlas
4d76305f2f fix(clippy): collapse nested if-let in build_graph (collapsible_if) 2026-07-10 15:16:22 +02:00
atlas
0af14d8ef8 refactor(#2281): petgraph for topology — replace bounded walks with graph algorithms
The is_descendant_of and apply_set_parent cycle detection both used
hand-rolled 32-hop bounded ancestor walks. Correct in practice (no
real hive exceeds 32 levels) but carried an arbitrary ceiling and were
harder to reason about than proven graph primitives.

Changes:
- Add build_graph(): converts BTreeMap<name, parent|null> → DiGraph
  with parent→child edges + BTreeMap<name, NodeIndex> index
- Add is_descendant_of_in(): pure (no disk I/O), uses
  petgraph::algo::has_path_connecting from ancestor to candidate
- Rewrite is_descendant_of(): delegates to is_descendant_of_in(&read())
- Rewrite apply_set_parent() cycle detection: build_graph() + speculative
  edge + is_cyclic_directed(); no depth limit
- Add tests for is_descendant_of_in (self, direct child, grandchild,
  parent-is-not-child, sibling, unknown)

petgraph was already a workspace dep (used elsewhere). On-disk format
unchanged (flat JSON map). Public API surface unchanged.
2026-07-10 15:16:22 +02:00
damocles
28dbb529c0 feat(#2289): debounced SweepHealth banner tracker, wire knowledge pull 2026-07-10 14:46:43 +02:00
damocles
cd155f28e4 fix(#2313): validate GetAgentMeta target against path traversal 2026-07-10 14:07:08 +02:00
damocles
bbbc2e28c7 fix(#2319): treat container start as success when the unit reaches active, not on the start exit code 2026-07-10 13:58:27 +02:00
damocles
9f98925c14 feat(#2289): push-based server-warning registry with RAII guard 2026-07-10 13:52:59 +02:00
lexis
b864dd6a7b docs(hivectl): clarify start command restores previously-running agents (follow-up to #1946) 2026-07-10 13:49:54 +02:00
damocles
17fa4a3ea5 fix(#2311): verify operator branch protection exists on create error instead of failing open 2026-07-10 12:40:03 +02:00
damocles
e58805b1ff feat(broker): add message priority, operator messages surface first 2026-07-10 02:44:35 +02:00
atlas
e9667f9c1a fix(#2287): reconcile team settings on 409 (upsert via org_edit_team)
On 409 (team already exists), list the org teams to find the operators
team id, then unconditionally PATCH to the desired settings via
org_edit_team. This self-heals a team that was created with the wrong
shape by an older code path (missing units, wrong permission) without
touching membership (separate endpoint, operator-managed).

Addresses mara's review: 'shouldnt we get, then change, then update'.
Unconditional PATCH is simpler than GET→diff→conditional PATCH and safe
here since we own units/permission/description fully.
2026-07-10 02:43:37 +02:00
atlas
beaa220dc2 fix(#2287): use is_conflict (409-only) for team create, supply explicit units 2026-07-10 02:43:37 +02:00
damocles
493face93c feat(#2300): recv reports remaining inbox depth so agents know how many messages are left 2026-07-10 02:03:29 +02:00
atlas
dfd159d1de refactor: drop Coordinator::ensure_runtime dead shim (no callers post #2290) 2026-07-10 01:12:04 +02:00
atlas
df44becd4a fix(#2290): update stale spawn_poll references in comments 2026-07-09 01:08:38 +02:00
atlas
66c6828359 fix(#2290): register_agent in handle_spawn (event-driven, replaces stale spawn_poll comment) 2026-07-09 01:08:38 +02:00
atlas
73f1020a7e refactor(#2290): replace mcp_sockets poll with event-driven register_agent
mara: the background worker is redundant if c0re knows when its own
sockets go missing. damocles: 10s poll latency and redundancy are two
faces of the same issue — poll adds a reconnect window and does
redundant work when c0re could react directly.

design: c0re owns the MCP listener lifecycle, so the only time a
listener disappears without c0re knowing is when c0re itself restarts.

- replace spawn_poll (recurring 10s loop) with sync_on_start (one-shot
  sweep at daemon boot): re-registers all running agents on startup
  after /run/hyperhive/agents/ is cleared by the tmpfs reset.
- run_reconcile (reconcile-start path): add coord.register_agent(name)
  immediately after start_with_fallback — event-driven, no poll delay.
- run_create already calls register_agent eagerly; kill/destroy paths
  already call unregister_agent — no changes needed there.

tracker: #2290
2026-07-09 01:08:38 +02:00
atlas
44dd9d45f0 docs(#2290): update mcp_sockets module doc — no eager register_agent after converge cleanup 2026-07-09 01:08:38 +02:00
atlas
afdd8c6c9f feat(#2290): converge unification cleanup — pull preamble into lifecycle
Collapse the scattered ensure_agent_runtime_dir calls into the lifecycle
functions themselves so callers have a single responsibility:

- lifecycle::spawn: calls ensure_agent_runtime_dir before write_dropins.
  Callers (handle_spawn, ensure_root_agent) no longer need a separate
  preamble step.

- lifecycle::rebuild_no_meta spawn path: calls ensure_agent_runtime_dir
  before write_dropins. apply_commit / merge_config_pr flows no longer
  need a manual ensure_agent_runtime_dir.

- run_create (job-queue): drops ensure_agent_runtime_dir + register_agent.
  The tail Reconcile's converge_start_preamble handles the runtime dir
  and mcp_sockets::spawn_poll handles the listener. Create stays purely
  'provision + create', not 'create + start'.

- handle_spawn (server.rs): drops manual preamble; lifecycle::spawn owns it.
  Drops unneeded unregister_agent on failure (supervisor handles listener).

- ensure_root_agent (auto_update.rs): drops manual ensure_agent_runtime_dir.

- actions.rs apply_commit / merge_config_pr: drop manual
  ensure_agent_runtime_dir; rebuild_no_meta's spawn path handles it.

Result: ensure_agent_runtime_dir lives in exactly two places —
lifecycle::spawn (direct spawn) and converge_start_preamble (start/reconcile
path). All other callers are clean call sites.
2026-07-09 01:08:38 +02:00
atlas
a45f65bd73 style: rustfmt 2026-07-09 01:08:38 +02:00
atlas
950a13bc69 feat(#2290): StartableAgent token — start_with_fallback requires preamble proof
- lifecycle::StartableAgent: opaque token produced only by
  converge_start_preamble. #[must_use] with a hint to call
  start_with_fallback(token).

- lifecycle::converge_start_preamble(name, hive, paths): runs
  ensure_agent_runtime_dir + write_dropins, returns StartableAgent.
  The only way to obtain a token.

- lifecycle::start_with_fallback(token: StartableAgent): public API
  now requires the token. Callers that skip the preamble get a compile
  error, not a runtime outage.

- lifecycle::start_with_fallback_inner(name): private; used internally
  by rebuild_no_meta where the preamble is already enforced structurally
  (write_dropins was called on the line above).

- exec.rs ReconcileAction::Start: migrated to converge_start_preamble
  + start_with_fallback(token). The write_dropins + start_with_fallback
  two-step is now a single typed pipeline.
2026-07-09 01:08:38 +02:00
atlas
15fc33d2e1 style: rustfmt 2026-07-09 00:58:51 +02:00
atlas
3d919b596f feat(#2290): split ensure_runtime — dirs to lifecycle, listeners to mcp_sockets supervisor
- lifecycle::ensure_agent_runtime_dir(name): pure filesystem op, no
  Coordinator dep. Creates /run/hyperhive/agents/<name> without touching
  the MCP listener map.

- workers/mcp_sockets::spawn_poll(coord): 10 s reconcile loop (same shape
  as agent_sockets::spawn_poll). Converges 'agent running => MCP listener
  bound'. First tick is immediate so hive-c0re restarts re-register all
  running agents without waiting a full interval. Fixes the dead-listener-
  after-daemon-restart gap.

- All ensure_runtime() call sites updated:
  - Prebuild/Swap/WriteDropin: Coordinator::agent_dir() (pure, no IO)
  - Reconcile-Start: ensure_agent_runtime_dir + agent_dir (dir may be
    missing after reboot; listener deferred to supervisor)
  - run_create / handle_spawn: ensure_agent_runtime_dir + register_agent
    (eager on first spawn so socket ready before harness first turn)
  - apply_commit / merge_config_pr: ensure_agent_runtime_dir + agent_dir
  - Manager (auto_update): ensure_agent_runtime_dir + agent_dir
    (manager has no MCP listener; socket_server::start_manager owns it)

- ensure_runtime() retained in Coordinator with updated doc pointing at
  the preferred split form. No callers remain outside tests.
2026-07-09 00:58:51 +02:00
atlas
ae3ecc1de2 fix(#2290): drop redundant async blocks around sync_tmpfiles spawn 2026-07-09 00:52:32 +02:00
atlas
f32fba0238 fix(#2290): use 0777 for per-agent socket dirs in tmpfiles.d
systemd-tmpfiles d entries adjust mode+owner on existing dirs. Using
0755 root root would stomp live agents' socket dirs (owned by agent
uid:gid) on every sync_tmpfiles call, breaking the harness's ability
to bind new sockets until host_config rechowns them.

Fix: 0777 root root — matches the chmod_socket_dir(0o777) fallback
already used by host_config when the agent uid is unavailable. World-
writable dirs let the non-root harness bind sockets regardless of who
owns the dir. host_config's chown_socket_dir tightens ownership when
the agent uid is resolved.

Also add missing # Errors doc to priv_client::sync_agent_tmpfiles.
2026-07-09 00:52:32 +02:00
atlas
9d1f5ebe76 feat(#2290): maintain /etc/tmpfiles.d/hyperhive-agents.conf for boot safety
Root cause of the boot outage: container@h-* units try to start before
hive-c0re reaches ensure_runtime, so bind-mount source dirs are missing.

Fix: hive-c0re (via hive-priv, which runs as root) writes
/etc/tmpfiles.d/hyperhive-agents.conf whenever the agent set changes.
systemd-tmpfiles-setup.service (sysinit.target) reads it at every boot
BEFORE any container units start, pre-creating:

  /run/hyperhive/agents/<name>  — MCP socket dir (bind -> /run/hive)
  /run/hive-agent/<name>        — web socket dir (bind -> /run/hive-agent)

This alone removes the outage class: even if hive-c0re is slow to start,
the bind-mount sources exist and container units can activate.

Added:
- PrivRequest::SyncAgentTmpfiles { agents } in hive-sh4re
- sync_agent_tmpfiles() in hive-priv: generates content, writes atomically,
  calls systemd-tmpfiles --create to apply immediately
- priv_client::sync_agent_tmpfiles() wrapper
- lifecycle::sync_tmpfiles() best-effort helper (list + priv call)
- Call sites: hive-c0re startup, handle_spawn success, destroy success
2026-07-09 00:52:32 +02:00
atlas
6f3e400903 refactor(#1868): drop tokenised_repo_url — call forge_git_url directly 2026-07-09 00:45:13 +02:00
atlas
031edbd41f fix(#1868): use HIVE_FORGE_URL for internal forge calls
Replace the hardcoded FORGE_HTTP const with forge_http_base() which
reads HIVE_FORGE_URL from the environment (already set unconditionally
by hive-c0re.nix to http://<forge.domain>). Add forge_git_url() helper
that inserts core:<token> credentials between scheme and authority for
git push/clone URLs.

All call sites updated:
- forge/mod.rs: api() OnceLock + new forge_git_url/forge_http_base fns
- forge/repos.rs: push_meta, push_config, ensure_meta_remote
- forge/pr_merge.rs: tokenised_repo_url delegate + test loosened
- workers/knowledge.rs: clone + push URLs
- socket_server/mod.rs: clone_url in RepoCreated response

No new env var: HIVE_FORGE_URL was already the right knob (mara).

Closes #1868. Closes #2174 (this supersedes the operators-team fix from
the closed #2218, which is re-applied in the ensure_operators_team call
that was already merged separately).
2026-07-09 00:45:13 +02:00
damocles
05c91245c7 refactor(#2286): make transient set/clear private — RAII guard is the only door 2026-07-09 00:44:47 +02:00
müde
c7c156e57b fix(hive-c0re): converge /run bind sources + limits drop-in before reconcile-start 2026-07-08 21:48:37 +02:00
müde
261f02439b fix(forge): review fixes for the forgejo-api port 2026-07-07 14:42:43 +02:00
müde
b8a3927c43 refactor(hive-c0re): port forge module + knowledge hooks to forgejo-api 2026-07-07 09:11:15 +02:00
müde
0f035ce1e9 build: add time + url deps for forgejo-api port 2026-07-07 08:50:35 +02:00
müde
39fe0f306a build: add forgejo-api workspace dep (sync feature for hive-forge) 2026-07-07 08:48:07 +02:00