Commit graph hyperhive/hive-c0re/src/forge.rs
Author SHA1 Message Date
damocles
745d95d2f5 forge: core token gets admin scope so PATCH /admin/users/* works (#646) 2026-05-30 18:14:31 +02:00
damocles
71abf2471e forge: replace removed forgejo admin user edit CLI with PATCH /api/v1/admin/users/{name} (closes #574) 2026-05-29 16:39:50 +02:00
iris
73684fb00a rust+nix: load static assets at runtime, drop build.rs (#555)
Cuts every `include_bytes!`/`include_str!` of a non-rust path in
the workspace over to runtime file loads from `$HIVE_ASSETS_DIR`
(the `hyperhive-assets` derivation introduced in the previous
commit). After this commit the rust derivation has no compile-time
dependency on `branding/*` or `hive-ag3nt/prompts/*` anymore.

Call-site flips:

- `hive-c0re/src/forge.rs::CORE_AVATAR_PNG` /
  `CONFIG_ORG_AVATAR_PNG`: were `include_bytes!` of
  `branding/hyperhive.png` and `$OUT_DIR/agent-configs.png`. Now
  `ensure_core_avatar` / `ensure_config_org_avatar` `tokio::fs::read`
  via `hive_sh4re::assets::{core_avatar_png, config_org_avatar_png}`
  at startup. The `agent-configs.png` is now rendered by the
  `hyperhive-assets` derivation's rsvg-convert step (was
  `hive-c0re/build.rs` + librsvg on the rust derivation's
  nativeBuildInputs — both gone in the next commit).
- `hive-ag3nt/src/prompt.rs::TEMPLATE`: `render` now takes the
  template as an argument; `write_system_prompt` reads it once from
  `$HIVE_ASSETS_DIR/prompts/system.md` before calling render. The
  test module still `include_str!`s the production template so
  `cargo test --workspace` doesn't need `HIVE_ASSETS_DIR` set —
  this is the only remaining compile-time reference to the file
  from the rust workspace, gated to `#[cfg(test)]`.
- `hive-ag3nt/src/turn.rs::CLAUDE_SETTINGS`: was `include_str!`'d
  and written via `tokio::fs::write`; now `tokio::fs::copy` from
  `$HIVE_ASSETS_DIR/prompts/claude-settings.json` into the
  per-agent socket dir.
- `hive-ag3nt/src/web_ui.rs::DEFAULT_ICON`: was `include_str!`'d;
  now read on-demand from `$HIVE_ASSETS_DIR/branding/hyperhive.svg`
  inside `serve_icon`. Falls back to an empty body if missing so
  the endpoint never panics on a misconfigured container (matches
  the existing "per-agent icon.svg override" fallthrough).

`HIVE_ASSETS_DIR` wiring:

- Inside containers: `nix/templates/harness-base.nix`
  `environment.variables` sets it to
  `${pkgs.hyperhive-assets}/share/hyperhive` (resolved through
  the default overlay applied in `mkContainer`). Verified by
  building `agent-base-toplevel` and grepping the resulting
  `/etc/set-environment`.
- Host-side: `nix/modules/hive-c0re.nix` adds an `assets` option
  defaulting to `hyperhive.packages.${system}.assets`, threaded
  in from the flake's nixosModules wiring, and sets the same env
  var on the `hive-c0re` systemd unit so the daemon's
  `forge::ensure_*_avatar` startup hooks find the PNGs.

`hive-c0re/build.rs` deleted entirely; `[package].build` removed
from `hive-c0re/Cargo.toml`; rsvg-convert dependency lives in the
assets derivation only.

Validated: `nix build .#default .#checks.x86_64-linux.clippy
.#agent-base-toplevel .#manager-toplevel --fallback` all succeed.
`/etc/set-environment` in the toplevel shows
`HIVE_ASSETS_DIR="/nix/store/.../hyperhive-assets-0.1.0/share/hyperhive"`.
2026-05-29 12:59:48 +02:00
iris
a444774ab3 forge: auto-set agent-configs org avatar on core start (#424)
Sibling to ensure_core_avatar (#320). Same one-shot marker-guarded
upload pattern, this time aimed at the Forgejo per-org avatar
endpoint (`POST /api/v1/orgs/{org}/avatar`).

## SVG-to-PNG at build time

Mara: *don't check in the png. instead generate png on the fly or
in build.*

`hive-c0re/build.rs` renders `branding/agent-configs.svg` →
`$OUT_DIR/agent-configs.png` via `rsvg-convert` (librsvg) on every
compile; `forge.rs` then `include_bytes!`s the OUT_DIR PNG. The
raster never gets checked into git — SVG stays source of truth,
the PNG is a build artifact.

- `hive-c0re/Cargo.toml`: declares `build = "build.rs"`
- `flake.nix`: adds `librsvg` to `naersk-lib.buildPackage`
  `nativeBuildInputs` (covers both the runtime package and the
  clippy check derivation) and to the dev shell so local
  `cargo build` finds `rsvg-convert` on PATH.
- For dev builds outside Nix, install librsvg (Debian:
  `librsvg2-bin`, macOS: `brew install librsvg`).

## Icon design

Sibling visual to the main hyperhive mark — same dark base + outer
ring + corner-bracket frame so the family reads at a glance. Centre
swaps the hexagonal hive for a stacked-config-files motif: three
offset sheets, folded-corner affordance, curly-brace `{ }` glyph
telegraphing "config file."

Brace font-size dropped 78→56 + letter-spacing -3 (#424 mara:
"braces cross the boundaries of the page") so the glyphs sit
comfortably inside the 120-wide front sheet with clear breathing
room on the left/right edges. The stack is shifted so the front
sheet centres on canvas-(150, 150); brace text anchors there with
`dominant-baseline=central` for true vertical centring.

## Validation

- `cargo check` clean (only pre-existing warnings).
- One-shot marker honoured: re-runs of `ensure_all` skip after the
  first success; `rm /var/lib/hyperhive/forge-agent-configs-avatar-set`
  forces re-upload (useful for icon revisions).
- Behaviour mirrors the existing `ensure_core_avatar` pattern.

Browser smoke test isn't possible from inside iris's container.
Worth eyeballing post-deploy: `http://localhost:3000/agent-configs`
should show the new avatar where the default identicon used to be.
2026-05-26 00:10:52 +02:00
iris
ce539559d5 forge: use base64 crate for avatar payload
Per @mara on #328: the hand-rolled encoder was over-cautious. Swap
for base64 = 0.22 from crates.io — a standard, widely-trusted dep,
no maintenance surface to carry. Drops the 15-line encoder and its
two RFC 4648 unit tests.
2026-05-23 01:15:16 +02:00
iris
dbb2ca4393 forge: upload hyperhive logo as the core user's avatar
The 'core' Forgejo user (hive-c0re's identity for commits in
core/meta + agent-configs/*) was showing the default hash identicon.
Adds a one-shot ensure_core_avatar in the ensure_all bootstrap that
POSTs the branding PNG to the admin avatar API and writes a marker
file (CORE_AVATAR_MARKER) so subsequent startups skip the call
(delete the marker to re-upload). Best-effort: a non-2xx is logged
and swallowed, doesn't gate startup.

PNG bytes baked in via include_bytes! from branding/hyperhive.png.
Base64 is hand-rolled (one small image in one cold path, not worth
a new workspace dep) with RFC 4648 §10 test vectors.

Closes #320.
2026-05-23 01:05:58 +02:00
damocles
3e94914569 fix #289: full forge sync on rebuild (extract sync_agent, use in rebuild_agent)
extract per-agent forge logic from ensure_all() into sync_agent()
so both the startup sweep and rebuild_agent call identical code.
rebuild now runs: ensure_user_for + ensure_config_repo + push_config
+ meta_read_access + ensure_meta_remote — same as the boot sweep.
missing tokens and drift in any forge state are fixed by rebuild,
not just hive reboot.
2026-05-22 22:18:05 +02:00
damocles
30d82148e0 clippy: apply auto-fixable warnings across workspace (closes #265 partial) 2026-05-22 18:55:57 +02:00
damocles
b283768f26 forge: replace curl shell-outs with reqwest http helper (closes #249) 2026-05-22 16:26:44 +02:00
damocles
bbe4cdb872 add meta read access and remote for agents on forge 2026-05-22 15:28:06 +02:00
damocles
49caf6e539 fix: also add write:notification scope to mark notifications as read 2026-05-20 19:08:21 +02:00
damocles
72aef13eaf fix: add read:notification scope, always remint token on ensure_user_for 2026-05-20 19:06:32 +02:00
damocles
a024ca65c0 fix: align forge user email to git user.email so commits link to profiles
agent users were created with {name}@hive.local but git commits use
{name}@hyperhive (set by meta::render_flake). forgejo matches by email,
so no profile link appeared on any commit.

- extract agent_email() helper returning {name}@hyperhive
- use it in ensure_user_exists (new users)
- add ensure_user_email() that runs gitea admin user edit to patch
  existing users; called from ensure_all on every startup sweep

Closes #64
2026-05-20 16:36:32 +02:00
müde
5aad2d67e1 forge: mirror applied config repos to a private agent-configs org
on startup (and after every applied-repo ref mutation) core pushes
each agent's hive-c0re-owned applied repo — main plus every
proposal/approved/building/deployed/failed/denied tag — to
agent-configs/<name> on the local forge. the org is private and
agents are not members, so core is the only principal that can read
it.

the tokenised push url is passed inline, never stored as a named
remote: the applied repo is bind-mounted read-only into the manager,
so a token in .git/config would leak the core admin credential to an
agent.

push_config is best-effort at every site (ensure_all, spawn,
approve, deny, submit) — a missing or down forge never blocks a
deploy.
2026-05-20 10:24:50 +02:00
damocles
f9f1346eae clippy: zero pedantic warnings across the tree 2026-05-18 22:09:34 +02:00
müde
600ed509f4 forge: ensure core/meta repo + mirror meta commits to forge
startup sweep adds ensure_repo('meta', core_token) after the orgs
so the first push isn't a 404. meta::git_commit now calls
forge::push_meta after every successful commit — token-in-URL
`git push http://core:$token@localhost:3000/core/meta.git` —
gated on the core token file existing (no-op when forge isn't
seeded). push failures log warn, don't bubble up.

no tea needed on the host; git is already on the hive-c0re service
PATH via /run/current-system/sw.
2026-05-17 01:52:00 +02:00
müde
68020a15c9 forge: drop redundant 'core' org — meta repo lives under core user 2026-05-17 01:50:12 +02:00
müde
db87167469 forge: seed core admin user + 'core'/'agents' orgs on startup
new ensure_core_user_and_token mints a site-admin 'core' user with
its token at /var/lib/hyperhive/forge-core-token (root 0600) —
hive-c0re's own forge identity for pushing the meta repo + driving
the admin API. that token then drives ensure_org for 'core' (meta
repo lives here) and 'agents' (per-agent applied config repos).
both org-create calls are idempotent: HTTP 422/409 treated as
success. failures log but don't abort the rest of the sweep.

curl is shelled out from the host — already on the hive-c0re
service PATH via /run/current-system/sw, no new dep.
2026-05-17 01:47:54 +02:00
müde
411cf86632 nix fmt + rustfmt sweep 2026-05-17 01:40:28 +02:00
müde
2b076f8ce4 forge: pass --work-path to admin CLI so app.ini is found
without --work-path, forgejo's admin CLI defaults WorkPath to the
binary's directory (RO nix store), can't find custom/conf/app.ini
there, falls back to defaults, and F3 init mkdir-fails inside the
store. systemd unit sets WORK_PATH for the daemon; mirror it here
for every nixos-container-driven 'forgejo admin' invocation.
2026-05-17 00:42:03 +02:00
müde
dccbd99b0c forge: broaden token scopes for repo create / PRs / orgs / misc
bumped from (read:user,write:repository,write:issue) to also include
write:user (own profile + create repos under own namespace),
write:organization (share namespaces between agents), write:misc
(hooks/attachments). still excludes admin and package scopes.
2026-05-16 20:58:20 +02:00
müde
480d646f69 forge: auto-create a user + token per agent on spawn / startup
new forge module probes the hive-forge nixos-container (no-op when
absent), and ensures every agent + the manager has a forgejo user
named after them with an access token at `<state>/forge-token`
(visible inside the container as `/state/forge-token`).

idempotent: skips user creation when forgejo reports 'already
exists', skips token issuance when the file is present, scopes the
token to read:user,write:repository,write:issue. token-name suffixed
with a clock so re-issuing doesn't collide with a stale name. shells
out via `nixos-container run hive-forge -- runuser -u forgejo --
forgejo admin` (runuser instead of sudo since sudo isn't in the
container by default).

hooks: ensure_all sweeps existing containers at hive-c0re startup
(backgrounded), and the actions.rs spawn task calls ensure_user_for
the new agent right after lifecycle::spawn succeeds. failures log a
warning but don't abort spawn — a missing token is recoverable from
the next startup sweep.
2026-05-16 20:55:13 +02:00