initial landing scaffold (hyperhive/website MVP)
Tracks hyperhive#502 — landing-only first cut. Static site generator: Zola (Rust, fits the swarm's stack and the operator's "sounds exciting" go-ahead on the issue thread). ## Structure - `flake.nix` — `nix build .#website` produces the dist; `nix develop` drops into a shell with zola for `zola serve` live reload. No CI runner; the flake is the validation contract. - `config.toml` — Zola config; base URL `hyperhive.darkest.space` per #502. Single-page landing — feeds / search index off. - `content/_index.md` — landing copy. Editable without touching templates so non-engineers can refresh prose. - `templates/base.html` + `templates/index.html` — base layout + landing-specific extension. og:tags + favicon wired through. - `sass/main.scss` — theme. Catppuccin Mocha palette + the amber accent from the swarm's identity hex mark. Self-contained (no @import) so the file is reviewable in one place. - `static/{favicon,hex-mark,hyperhive}.svg` — copies of the dashboard's `branding/hyperhive.svg` (hex motif). Used as favicon, hero inline, and og:image respectively. ## Theme Monospace identity throughout — matches dashboard / agent terminals so the website reads as part of the same family rather than a separate marketing artifact. Banner glyphs (`░▒▓█▓▒░`) on the title, dashed dividers, cyan/mauve/amber accents, glow text-shadow on the hero. Subtle CSS-only pulse on the hex motif (slow `rotate` on the SVG; speeds up on hover for a small "noticed" cue). ## Three-column "what's inside" `the swarm` / `the dashboard` / `the boundary` — quick orientation for visitors who clicked through from a link without context. Copy intentionally short; deep dives belong in /docs (future, not in this MVP). ## Scope drop Per mara on #502: - no nav / blog / docs yet — landing only - no screenshots in MVP, follow via issues in this repo - public visibility ## Provenance Scaffolded under `iris/website` because my agent forge token doesn't carry org-admin to create repos under `hyperhive/`. Manager confirmed their token doesn't either; mara will do the org transfer once she gets to it. README documents this.
This commit is contained in:
parent
b1dd949291
commit
d3a55c5631
12 changed files with 873 additions and 2 deletions
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Zola build output
|
||||
public/
|
||||
|
||||
# nix
|
||||
result
|
||||
result-*
|
||||
|
||||
# editor / OS
|
||||
.direnv/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
57
README.md
57
README.md
|
|
@ -1,3 +1,56 @@
|
|||
# website
|
||||
# hyperhive website
|
||||
|
||||
hyperhive marketing landing — Zola static site, Catppuccin-themed (will transfer to hyperhive/website per #502)
|
||||
Marketing landing for hyperhive, deployed at
|
||||
[hyperhive.darkest.space](https://hyperhive.darkest.space). Tracks
|
||||
[hyperhive#502](http://localhost:3000/hyperhive/hyperhive/issues/502).
|
||||
|
||||
Built with [Zola](https://www.getzola.org/), the Rust static site
|
||||
generator. Single-page landing for now; nav / blog / docs land via
|
||||
follow-up issues in this repo if scope grows.
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
# one-shot build to ./public
|
||||
nix build .#website
|
||||
# → result/ is the dist, ready to drop under any static host
|
||||
|
||||
# dev server (live reload on http://127.0.0.1:1111/)
|
||||
nix develop
|
||||
zola serve
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
config.toml # zola config (single source of truth for site meta)
|
||||
content/_index.md # landing page copy — edit here for prose changes
|
||||
templates/
|
||||
base.html # base layout (head, footer, og tags)
|
||||
index.html # landing template extending base
|
||||
sass/
|
||||
main.scss # theme — Catppuccin Mocha + amber accent
|
||||
static/
|
||||
favicon.svg # hyperhive hex motif (copy of dashboard branding)
|
||||
hex-mark.svg # same SVG, used inline in the hero
|
||||
hyperhive.svg # og:image
|
||||
flake.nix # `nix build` → site dist, `nix develop` → zola shell
|
||||
```
|
||||
|
||||
## Theme
|
||||
|
||||
Catppuccin Mocha palette + the hyperhive amber from the swarm's
|
||||
identity hex mark. Monospace identity throughout (same family as
|
||||
the dashboard / agent terminals) so the website reads as part of
|
||||
the same project, not a separate marketing artifact.
|
||||
|
||||
Theme variables live in `sass/main.scss` (single source of truth).
|
||||
The hex motif in the hero is the same SVG that ships on the
|
||||
dashboard / forge / agent containers.
|
||||
|
||||
## Repo provenance
|
||||
|
||||
Currently scaffolded under `iris/website` because my agent forge
|
||||
token doesn't have org-admin to create repos under `hyperhive/`.
|
||||
Will be transferred to `hyperhive/website` once mara does the move
|
||||
(see hyperhive#502 thread).
|
||||
|
|
|
|||
34
config.toml
Normal file
34
config.toml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Zola config — hyperhive marketing landing (#502).
|
||||
#
|
||||
# Single-page landing for now; nav / blog / docs come later if scope grows.
|
||||
# Theme lives in `sass/main.scss` and `templates/`; no external Zola theme
|
||||
# import — the project's identity matches the dashboard / agent terminals
|
||||
# closely enough that pulling in a third-party theme would just give us
|
||||
# something to fight.
|
||||
|
||||
base_url = "https://hyperhive.darkest.space"
|
||||
title = "hyperhive"
|
||||
description = "a swarm of claude agents in nspawn containers, with an operator-shaped trust boundary."
|
||||
|
||||
# We don't need RSS / search / sitemaps for a single-page landing. Can
|
||||
# flip these on later if blog content lands.
|
||||
generate_feeds = false
|
||||
build_search_index = false
|
||||
|
||||
# Embed the SCSS pipeline; zola compiles `sass/*.scss` → `public/*.css`.
|
||||
compile_sass = true
|
||||
|
||||
# Markdown rendering defaults — landing has very little prose so the
|
||||
# fancier syntax-highlight setup isn't needed yet. Easy to turn on later.
|
||||
[markdown]
|
||||
highlight_code = false
|
||||
smart_punctuation = true
|
||||
|
||||
[extra]
|
||||
# Catppuccin Mocha palette + amber accent (matching the hex mark) is
|
||||
# the project's identity. Single source of truth — `main.scss` reads
|
||||
# these via Sass variables, not from this attrset (Zola doesn't pipe
|
||||
# extras into Sass). Keeping them here as documentation only so the
|
||||
# theme intent is reviewable in one place.
|
||||
palette = "catppuccin-mocha"
|
||||
accent = "amber"
|
||||
9
content/_index.md
Normal file
9
content/_index.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
+++
|
||||
title = "hyperhive"
|
||||
+++
|
||||
|
||||
A swarm of Claude agents running in nspawn containers, gated by an
|
||||
operator-shaped trust boundary. Each agent has a logical name, a
|
||||
state directory, and a NixOS config — and talks to its peers
|
||||
through a broker that the human at the dashboard can read, gate,
|
||||
or interrupt.
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1779560665,
|
||||
"narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
64
flake.nix
Normal file
64
flake.nix
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
# hyperhive marketing landing — Zola static site build (#502).
|
||||
#
|
||||
# `nix build` → `result/` is the `public/` Zola dist, ready to drop
|
||||
# under any static-file host. No CI runner needed; the flake is the
|
||||
# validation contract.
|
||||
description = "hyperhive marketing landing";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in {
|
||||
packages.website = pkgs.stdenv.mkDerivation {
|
||||
pname = "hyperhive-website";
|
||||
version = self.shortRev or "dev";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = [ pkgs.zola ];
|
||||
|
||||
# Zola reads `config.toml` from CWD, writes `public/` next to it,
|
||||
# which we then move to $out. The build is offline / hermetic —
|
||||
# no network access needed at build time, which fits the nix
|
||||
# sandbox without extra fetchurls.
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
zola build --output-dir public
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out
|
||||
cp -r public/. $out/
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
# Static-site dist; no shared libs to patchelf, no executables.
|
||||
dontFixup = true;
|
||||
};
|
||||
|
||||
# `nix build` with no attribute → the website dist.
|
||||
packages.default = self.packages.${system}.website;
|
||||
|
||||
# `nix develop` → a shell with zola for local iteration:
|
||||
# `zola serve` runs the dev server with live reload.
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = [ pkgs.zola ];
|
||||
};
|
||||
|
||||
# `nix run` is the dev-server shortcut: `nix run . -- serve`
|
||||
# boots Zola's hot-reload server on http://127.0.0.1:1111/.
|
||||
apps.default = {
|
||||
type = "app";
|
||||
program = "${pkgs.zola}/bin/zola";
|
||||
};
|
||||
});
|
||||
}
|
||||
249
sass/main.scss
Normal file
249
sass/main.scss
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
// hyperhive marketing landing — theme (#502).
|
||||
//
|
||||
// Matches the dashboard / agent terminals visually so the website
|
||||
// reads as part of the same family: Catppuccin Mocha palette + amber
|
||||
// accent (matching the hex mark), banner-thin block-glyph headings,
|
||||
// dashed dividers, glow text-shadow on titles.
|
||||
//
|
||||
// Single-file SCSS — landing is small enough that splitting into
|
||||
// partials would be premature. Re-evaluate if /docs or /blog land.
|
||||
|
||||
// ─── palette ───────────────────────────────────────────────────────
|
||||
// Catppuccin Mocha + the hyperhive amber from branding/hyperhive.svg.
|
||||
// Copying them in (not importing) so this file stays self-contained.
|
||||
|
||||
$base: #1e1e2e;
|
||||
$mantle: #181825;
|
||||
$crust: #11111b;
|
||||
|
||||
$text: #cdd6f4;
|
||||
$subtext1: #bac2de;
|
||||
$subtext0: #a6adc8;
|
||||
$overlay2: #9399b2;
|
||||
$overlay1: #7f849c;
|
||||
$overlay0: #6c7086;
|
||||
$surface2: #585b70;
|
||||
$surface1: #45475a;
|
||||
$surface0: #313244;
|
||||
|
||||
$rosewater: #f5e0dc;
|
||||
$flamingo: #f2cdcd;
|
||||
$pink: #f5c2e7;
|
||||
$mauve: #cba6f7;
|
||||
$red: #f38ba8;
|
||||
$maroon: #eba0ac;
|
||||
$peach: #fab387;
|
||||
$yellow: #f9e2af;
|
||||
$green: #a6e3a1;
|
||||
$teal: #94e2d5;
|
||||
$sky: #89dceb;
|
||||
$sapphire: #74c7ec;
|
||||
$blue: #89b4fa;
|
||||
$lavender: #b4befe;
|
||||
|
||||
// The hex-mark amber. Pure swarm identity colour.
|
||||
$amber: #ffb300;
|
||||
$amber-deep: #ff8f00;
|
||||
$amber-glow: rgba(255, 179, 0, 0.45);
|
||||
|
||||
// ─── globals ───────────────────────────────────────────────────────
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: $base;
|
||||
color: $text;
|
||||
// Same font stack as the dashboard's @hive/shared base.css —
|
||||
// monospace identity reads as "this is the terminal swarm" instead
|
||||
// of "this is a marketing site". Body copy stays readable at this
|
||||
// weight because the lines are short.
|
||||
font-family: ui-monospace, "JetBrains Mono", "Fira Code",
|
||||
Menlo, Consolas, monospace;
|
||||
font-size: 16px;
|
||||
line-height: 1.55;
|
||||
// Subtle background grid — same idea as the hex-mark's faint
|
||||
// horizontal lines, but at body scope. Cheaper than a full SVG
|
||||
// background.
|
||||
background-image:
|
||||
repeating-linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 23px,
|
||||
rgba(255, 179, 0, 0.025) 23px,
|
||||
rgba(255, 179, 0, 0.025) 24px
|
||||
);
|
||||
}
|
||||
|
||||
a {
|
||||
color: $sky;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dashed transparent;
|
||||
transition: border-color 0.15s, color 0.15s;
|
||||
}
|
||||
a:hover { color: $sapphire; border-bottom-color: $sapphire; }
|
||||
|
||||
::selection { background: $amber-glow; color: $crust; }
|
||||
|
||||
// ─── layout ────────────────────────────────────────────────────────
|
||||
|
||||
.shell {
|
||||
max-width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 4rem 1.5rem 2rem;
|
||||
}
|
||||
|
||||
// ─── hero ──────────────────────────────────────────────────────────
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(180px, 280px) 1fr;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
padding-bottom: 2rem;
|
||||
border-bottom: 1px dashed $surface1;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.hero { grid-template-columns: 1fr; text-align: center; }
|
||||
.hero-art { max-width: 220px; margin: 0 auto; }
|
||||
}
|
||||
|
||||
.hero-art svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
// Subtle pulse — only the outer ring + dashed orbit rotate. Quiet
|
||||
// enough to read as "active" instead of "noisy".
|
||||
animation: hex-orbit 24s linear infinite;
|
||||
}
|
||||
.hero-art:hover svg {
|
||||
// Speed up on hover for a tiny "you got noticed" cue. No JS needed.
|
||||
animation-duration: 8s;
|
||||
}
|
||||
|
||||
@keyframes hex-orbit {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hero-text h1 {
|
||||
margin: 0 0 0.6rem;
|
||||
font-size: 2.4rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
color: $amber;
|
||||
text-shadow:
|
||||
0 0 4px $amber-glow,
|
||||
0 0 12px rgba(255, 143, 0, 0.25);
|
||||
}
|
||||
|
||||
.banner-glyph {
|
||||
color: $amber-deep;
|
||||
opacity: 0.65;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.hero-tagline {
|
||||
margin: 0 0 1.6rem;
|
||||
font-size: 1.05rem;
|
||||
color: $subtext1;
|
||||
}
|
||||
|
||||
.hero-cta { margin: 0; }
|
||||
|
||||
.cta-primary {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid $amber;
|
||||
color: $amber;
|
||||
border-bottom-color: $amber;
|
||||
text-shadow: 0 0 6px $amber-glow;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
transition: box-shadow 0.15s ease, color 0.15s, border-color 0.15s;
|
||||
}
|
||||
.cta-primary:hover {
|
||||
color: $base;
|
||||
background: $amber;
|
||||
border-color: $amber;
|
||||
border-bottom-style: solid;
|
||||
box-shadow: 0 0 14px -2px $amber-glow;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
// ─── prose ─────────────────────────────────────────────────────────
|
||||
|
||||
.prose {
|
||||
padding: 2rem 0;
|
||||
color: $text;
|
||||
max-width: 64ch;
|
||||
font-size: 1.02rem;
|
||||
}
|
||||
.prose p { margin: 0 0 1rem; }
|
||||
|
||||
// ─── three-column grid ────────────────────────────────────────────
|
||||
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1rem;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px dashed $surface1;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.grid-3 { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem 1.2rem;
|
||||
background: $mantle;
|
||||
border: 1px solid $surface0;
|
||||
border-radius: 4px;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.card:hover {
|
||||
border-color: $amber;
|
||||
box-shadow: 0 0 14px -6px $amber-glow;
|
||||
}
|
||||
.card h2 {
|
||||
margin: 0 0 0.6rem;
|
||||
font-size: 1.1rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: $mauve;
|
||||
}
|
||||
.card-glyph { color: $amber; margin-right: 0.4em; }
|
||||
.card p {
|
||||
margin: 0;
|
||||
font-size: 0.92rem;
|
||||
color: $subtext1;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// ─── footer ────────────────────────────────────────────────────────
|
||||
|
||||
.site-footer {
|
||||
max-width: 920px;
|
||||
margin: 3rem auto 1.5rem;
|
||||
padding: 1.5rem 1.5rem 0;
|
||||
text-align: center;
|
||||
border-top: 1px dashed $surface1;
|
||||
}
|
||||
|
||||
.banner-thin {
|
||||
margin: 1.5rem 0 0.5rem;
|
||||
color: $amber-deep;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.18em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
margin: 0;
|
||||
font-size: 0.88rem;
|
||||
color: $subtext0;
|
||||
}
|
||||
.footer-links .sep { margin: 0 0.4em; opacity: 0.5; }
|
||||
97
static/favicon.svg
Normal file
97
static/favicon.svg
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<svg width="300" height="300" viewBox="0 0 300 300" role="img" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>HyperHive</title>
|
||||
<desc>HyperHive icon — hexagonal hive, amber on dark</desc>
|
||||
<defs>
|
||||
<clipPath id="clipH"><circle cx="150" cy="150" r="140"/></clipPath>
|
||||
</defs>
|
||||
|
||||
<g clip-path="url(#clipH)">
|
||||
<rect x="0" y="0" width="300" height="300" fill="#0a0600"/>
|
||||
<g stroke="#ffb300" stroke-width="0.35" opacity="0.07">
|
||||
<line x1="0" x2="300" y1="10" y2="10"/> <line x1="0" x2="300" y1="20" y2="20"/>
|
||||
<line x1="0" x2="300" y1="30" y2="30"/> <line x1="0" x2="300" y1="40" y2="40"/>
|
||||
<line x1="0" x2="300" y1="50" y2="50"/> <line x1="0" x2="300" y1="60" y2="60"/>
|
||||
<line x1="0" x2="300" y1="70" y2="70"/> <line x1="0" x2="300" y1="80" y2="80"/>
|
||||
<line x1="0" x2="300" y1="90" y2="90"/> <line x1="0" x2="300" y1="100" y2="100"/>
|
||||
<line x1="0" x2="300" y1="110" y2="110"/> <line x1="0" x2="300" y1="120" y2="120"/>
|
||||
<line x1="0" x2="300" y1="130" y2="130"/> <line x1="0" x2="300" y1="140" y2="140"/>
|
||||
<line x1="0" x2="300" y1="150" y2="150"/> <line x1="0" x2="300" y1="160" y2="160"/>
|
||||
<line x1="0" x2="300" y1="170" y2="170"/> <line x1="0" x2="300" y1="180" y2="180"/>
|
||||
<line x1="0" x2="300" y1="190" y2="190"/> <line x1="0" x2="300" y1="200" y2="200"/>
|
||||
<line x1="0" x2="300" y1="210" y2="210"/> <line x1="0" x2="300" y1="220" y2="220"/>
|
||||
<line x1="0" x2="300" y1="230" y2="230"/> <line x1="0" x2="300" y1="240" y2="240"/>
|
||||
<line x1="0" x2="300" y1="250" y2="250"/> <line x1="0" x2="300" y1="260" y2="260"/>
|
||||
<line x1="0" x2="300" y1="270" y2="270"/> <line x1="0" x2="300" y1="280" y2="280"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="118" fill="none" stroke="#ffb300" stroke-width="1" opacity="0.4"/>
|
||||
<circle cx="150" cy="150" r="104" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.25" stroke-dasharray="4 6"/>
|
||||
|
||||
<!-- RING 2 — 6 between-axis hexes, centered on (150,150) instead of (170,170) -->
|
||||
<g fill="#0e0800" stroke="#ffb300" stroke-width="0.7" opacity="0.4">
|
||||
<polygon points="254,105 241,127.5 215,127.5 202,105 215,82.5 241,82.5"/>
|
||||
<polygon points="98,105 85,127.5 59,127.5 46,105 59,82.5 85,82.5"/>
|
||||
<polygon points="176,60 163,82.5 137,82.5 124,60 137,37.5 163,37.5"/>
|
||||
<polygon points="254,195 241,217.5 215,217.5 202,195 215,172.5 241,172.5"/>
|
||||
<polygon points="98,195 85,217.5 59,217.5 46,195 59,172.5 85,172.5"/>
|
||||
<polygon points="176,240 163,262.5 137,262.5 124,240 137,217.5 163,217.5"/>
|
||||
</g>
|
||||
|
||||
<!-- RING 1 — 6 hexes -->
|
||||
<g fill="#150c00" stroke="#ffb300" stroke-width="1.2" opacity="0.8">
|
||||
<polygon points="228,150 215,172.5 189,172.5 176,150 189,127.5 215,127.5"/>
|
||||
<polygon points="202,105 189,127.5 163,127.5 150,105 163,82.5 189,82.5"/>
|
||||
<polygon points="150,105 137,127.5 111,127.5 98,105 111,82.5 137,82.5"/>
|
||||
<polygon points="124,150 111,172.5 85,172.5 72,150 85,127.5 111,127.5"/>
|
||||
<polygon points="150,195 137,217.5 111,217.5 98,195 111,172.5 137,172.5"/>
|
||||
<polygon points="202,195 189,217.5 163,217.5 150,195 163,172.5 189,172.5"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER hex -->
|
||||
<polygon points="176,150 163,172.5 137,172.5 124,150 137,127.5 163,127.5"
|
||||
fill="#1a0f00" stroke="#ffb300" stroke-width="1.8"/>
|
||||
|
||||
<!-- connections -->
|
||||
<g stroke="#ffb300" stroke-width="1" opacity="0.6">
|
||||
<line x1="176" y1="150" x2="202" y2="150"/>
|
||||
<line x1="124" y1="150" x2="98" y2="150"/>
|
||||
<line x1="163" y1="128" x2="176" y2="105"/>
|
||||
<line x1="137" y1="128" x2="124" y2="105"/>
|
||||
<line x1="163" y1="173" x2="176" y2="195"/>
|
||||
<line x1="137" y1="173" x2="124" y2="195"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER node -->
|
||||
<circle cx="150" cy="150" r="10" fill="#ffb300" opacity="0.95"/>
|
||||
<circle cx="150" cy="150" r="5" fill="#0a0600"/>
|
||||
|
||||
<!-- ring 1 nodes -->
|
||||
<g fill="#ff8f00" opacity="0.9">
|
||||
<circle cx="202" cy="150" r="6"/>
|
||||
<circle cx="176" cy="105" r="6"/>
|
||||
<circle cx="124" cy="105" r="6"/>
|
||||
<circle cx="98" cy="150" r="6"/>
|
||||
<circle cx="124" cy="195" r="6"/>
|
||||
<circle cx="176" cy="195" r="6"/>
|
||||
</g>
|
||||
<g fill="#0a0600">
|
||||
<circle cx="202" cy="150" r="2.5"/>
|
||||
<circle cx="176" cy="105" r="2.5"/>
|
||||
<circle cx="124" cy="105" r="2.5"/>
|
||||
<circle cx="98" cy="150" r="2.5"/>
|
||||
<circle cx="124" cy="195" r="2.5"/>
|
||||
<circle cx="176" cy="195" r="2.5"/>
|
||||
</g>
|
||||
|
||||
<rect x="0" y="143" width="300" height="2" fill="#ffb300" opacity="0.07"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="140" fill="none" stroke="#ffb300" stroke-width="2.5"/>
|
||||
<circle cx="150" cy="150" r="145" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.4" stroke-dasharray="8 4"/>
|
||||
<g stroke="#ffb300" stroke-width="1.5" fill="none" opacity="0.8">
|
||||
<path d="M44,44 L20,44 L20,70"/>
|
||||
<path d="M256,44 L280,44 L280,70"/>
|
||||
<path d="M44,256 L20,256 L20,230"/>
|
||||
<path d="M256,256 L280,256 L280,230"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
97
static/hex-mark.svg
Normal file
97
static/hex-mark.svg
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<svg width="300" height="300" viewBox="0 0 300 300" role="img" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>HyperHive</title>
|
||||
<desc>HyperHive icon — hexagonal hive, amber on dark</desc>
|
||||
<defs>
|
||||
<clipPath id="clipH"><circle cx="150" cy="150" r="140"/></clipPath>
|
||||
</defs>
|
||||
|
||||
<g clip-path="url(#clipH)">
|
||||
<rect x="0" y="0" width="300" height="300" fill="#0a0600"/>
|
||||
<g stroke="#ffb300" stroke-width="0.35" opacity="0.07">
|
||||
<line x1="0" x2="300" y1="10" y2="10"/> <line x1="0" x2="300" y1="20" y2="20"/>
|
||||
<line x1="0" x2="300" y1="30" y2="30"/> <line x1="0" x2="300" y1="40" y2="40"/>
|
||||
<line x1="0" x2="300" y1="50" y2="50"/> <line x1="0" x2="300" y1="60" y2="60"/>
|
||||
<line x1="0" x2="300" y1="70" y2="70"/> <line x1="0" x2="300" y1="80" y2="80"/>
|
||||
<line x1="0" x2="300" y1="90" y2="90"/> <line x1="0" x2="300" y1="100" y2="100"/>
|
||||
<line x1="0" x2="300" y1="110" y2="110"/> <line x1="0" x2="300" y1="120" y2="120"/>
|
||||
<line x1="0" x2="300" y1="130" y2="130"/> <line x1="0" x2="300" y1="140" y2="140"/>
|
||||
<line x1="0" x2="300" y1="150" y2="150"/> <line x1="0" x2="300" y1="160" y2="160"/>
|
||||
<line x1="0" x2="300" y1="170" y2="170"/> <line x1="0" x2="300" y1="180" y2="180"/>
|
||||
<line x1="0" x2="300" y1="190" y2="190"/> <line x1="0" x2="300" y1="200" y2="200"/>
|
||||
<line x1="0" x2="300" y1="210" y2="210"/> <line x1="0" x2="300" y1="220" y2="220"/>
|
||||
<line x1="0" x2="300" y1="230" y2="230"/> <line x1="0" x2="300" y1="240" y2="240"/>
|
||||
<line x1="0" x2="300" y1="250" y2="250"/> <line x1="0" x2="300" y1="260" y2="260"/>
|
||||
<line x1="0" x2="300" y1="270" y2="270"/> <line x1="0" x2="300" y1="280" y2="280"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="118" fill="none" stroke="#ffb300" stroke-width="1" opacity="0.4"/>
|
||||
<circle cx="150" cy="150" r="104" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.25" stroke-dasharray="4 6"/>
|
||||
|
||||
<!-- RING 2 — 6 between-axis hexes, centered on (150,150) instead of (170,170) -->
|
||||
<g fill="#0e0800" stroke="#ffb300" stroke-width="0.7" opacity="0.4">
|
||||
<polygon points="254,105 241,127.5 215,127.5 202,105 215,82.5 241,82.5"/>
|
||||
<polygon points="98,105 85,127.5 59,127.5 46,105 59,82.5 85,82.5"/>
|
||||
<polygon points="176,60 163,82.5 137,82.5 124,60 137,37.5 163,37.5"/>
|
||||
<polygon points="254,195 241,217.5 215,217.5 202,195 215,172.5 241,172.5"/>
|
||||
<polygon points="98,195 85,217.5 59,217.5 46,195 59,172.5 85,172.5"/>
|
||||
<polygon points="176,240 163,262.5 137,262.5 124,240 137,217.5 163,217.5"/>
|
||||
</g>
|
||||
|
||||
<!-- RING 1 — 6 hexes -->
|
||||
<g fill="#150c00" stroke="#ffb300" stroke-width="1.2" opacity="0.8">
|
||||
<polygon points="228,150 215,172.5 189,172.5 176,150 189,127.5 215,127.5"/>
|
||||
<polygon points="202,105 189,127.5 163,127.5 150,105 163,82.5 189,82.5"/>
|
||||
<polygon points="150,105 137,127.5 111,127.5 98,105 111,82.5 137,82.5"/>
|
||||
<polygon points="124,150 111,172.5 85,172.5 72,150 85,127.5 111,127.5"/>
|
||||
<polygon points="150,195 137,217.5 111,217.5 98,195 111,172.5 137,172.5"/>
|
||||
<polygon points="202,195 189,217.5 163,217.5 150,195 163,172.5 189,172.5"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER hex -->
|
||||
<polygon points="176,150 163,172.5 137,172.5 124,150 137,127.5 163,127.5"
|
||||
fill="#1a0f00" stroke="#ffb300" stroke-width="1.8"/>
|
||||
|
||||
<!-- connections -->
|
||||
<g stroke="#ffb300" stroke-width="1" opacity="0.6">
|
||||
<line x1="176" y1="150" x2="202" y2="150"/>
|
||||
<line x1="124" y1="150" x2="98" y2="150"/>
|
||||
<line x1="163" y1="128" x2="176" y2="105"/>
|
||||
<line x1="137" y1="128" x2="124" y2="105"/>
|
||||
<line x1="163" y1="173" x2="176" y2="195"/>
|
||||
<line x1="137" y1="173" x2="124" y2="195"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER node -->
|
||||
<circle cx="150" cy="150" r="10" fill="#ffb300" opacity="0.95"/>
|
||||
<circle cx="150" cy="150" r="5" fill="#0a0600"/>
|
||||
|
||||
<!-- ring 1 nodes -->
|
||||
<g fill="#ff8f00" opacity="0.9">
|
||||
<circle cx="202" cy="150" r="6"/>
|
||||
<circle cx="176" cy="105" r="6"/>
|
||||
<circle cx="124" cy="105" r="6"/>
|
||||
<circle cx="98" cy="150" r="6"/>
|
||||
<circle cx="124" cy="195" r="6"/>
|
||||
<circle cx="176" cy="195" r="6"/>
|
||||
</g>
|
||||
<g fill="#0a0600">
|
||||
<circle cx="202" cy="150" r="2.5"/>
|
||||
<circle cx="176" cy="105" r="2.5"/>
|
||||
<circle cx="124" cy="105" r="2.5"/>
|
||||
<circle cx="98" cy="150" r="2.5"/>
|
||||
<circle cx="124" cy="195" r="2.5"/>
|
||||
<circle cx="176" cy="195" r="2.5"/>
|
||||
</g>
|
||||
|
||||
<rect x="0" y="143" width="300" height="2" fill="#ffb300" opacity="0.07"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="140" fill="none" stroke="#ffb300" stroke-width="2.5"/>
|
||||
<circle cx="150" cy="150" r="145" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.4" stroke-dasharray="8 4"/>
|
||||
<g stroke="#ffb300" stroke-width="1.5" fill="none" opacity="0.8">
|
||||
<path d="M44,44 L20,44 L20,70"/>
|
||||
<path d="M256,44 L280,44 L280,70"/>
|
||||
<path d="M44,256 L20,256 L20,230"/>
|
||||
<path d="M256,256 L280,256 L280,230"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
97
static/hyperhive.svg
Normal file
97
static/hyperhive.svg
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<svg width="300" height="300" viewBox="0 0 300 300" role="img" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>HyperHive</title>
|
||||
<desc>HyperHive icon — hexagonal hive, amber on dark</desc>
|
||||
<defs>
|
||||
<clipPath id="clipH"><circle cx="150" cy="150" r="140"/></clipPath>
|
||||
</defs>
|
||||
|
||||
<g clip-path="url(#clipH)">
|
||||
<rect x="0" y="0" width="300" height="300" fill="#0a0600"/>
|
||||
<g stroke="#ffb300" stroke-width="0.35" opacity="0.07">
|
||||
<line x1="0" x2="300" y1="10" y2="10"/> <line x1="0" x2="300" y1="20" y2="20"/>
|
||||
<line x1="0" x2="300" y1="30" y2="30"/> <line x1="0" x2="300" y1="40" y2="40"/>
|
||||
<line x1="0" x2="300" y1="50" y2="50"/> <line x1="0" x2="300" y1="60" y2="60"/>
|
||||
<line x1="0" x2="300" y1="70" y2="70"/> <line x1="0" x2="300" y1="80" y2="80"/>
|
||||
<line x1="0" x2="300" y1="90" y2="90"/> <line x1="0" x2="300" y1="100" y2="100"/>
|
||||
<line x1="0" x2="300" y1="110" y2="110"/> <line x1="0" x2="300" y1="120" y2="120"/>
|
||||
<line x1="0" x2="300" y1="130" y2="130"/> <line x1="0" x2="300" y1="140" y2="140"/>
|
||||
<line x1="0" x2="300" y1="150" y2="150"/> <line x1="0" x2="300" y1="160" y2="160"/>
|
||||
<line x1="0" x2="300" y1="170" y2="170"/> <line x1="0" x2="300" y1="180" y2="180"/>
|
||||
<line x1="0" x2="300" y1="190" y2="190"/> <line x1="0" x2="300" y1="200" y2="200"/>
|
||||
<line x1="0" x2="300" y1="210" y2="210"/> <line x1="0" x2="300" y1="220" y2="220"/>
|
||||
<line x1="0" x2="300" y1="230" y2="230"/> <line x1="0" x2="300" y1="240" y2="240"/>
|
||||
<line x1="0" x2="300" y1="250" y2="250"/> <line x1="0" x2="300" y1="260" y2="260"/>
|
||||
<line x1="0" x2="300" y1="270" y2="270"/> <line x1="0" x2="300" y1="280" y2="280"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="118" fill="none" stroke="#ffb300" stroke-width="1" opacity="0.4"/>
|
||||
<circle cx="150" cy="150" r="104" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.25" stroke-dasharray="4 6"/>
|
||||
|
||||
<!-- RING 2 — 6 between-axis hexes, centered on (150,150) instead of (170,170) -->
|
||||
<g fill="#0e0800" stroke="#ffb300" stroke-width="0.7" opacity="0.4">
|
||||
<polygon points="254,105 241,127.5 215,127.5 202,105 215,82.5 241,82.5"/>
|
||||
<polygon points="98,105 85,127.5 59,127.5 46,105 59,82.5 85,82.5"/>
|
||||
<polygon points="176,60 163,82.5 137,82.5 124,60 137,37.5 163,37.5"/>
|
||||
<polygon points="254,195 241,217.5 215,217.5 202,195 215,172.5 241,172.5"/>
|
||||
<polygon points="98,195 85,217.5 59,217.5 46,195 59,172.5 85,172.5"/>
|
||||
<polygon points="176,240 163,262.5 137,262.5 124,240 137,217.5 163,217.5"/>
|
||||
</g>
|
||||
|
||||
<!-- RING 1 — 6 hexes -->
|
||||
<g fill="#150c00" stroke="#ffb300" stroke-width="1.2" opacity="0.8">
|
||||
<polygon points="228,150 215,172.5 189,172.5 176,150 189,127.5 215,127.5"/>
|
||||
<polygon points="202,105 189,127.5 163,127.5 150,105 163,82.5 189,82.5"/>
|
||||
<polygon points="150,105 137,127.5 111,127.5 98,105 111,82.5 137,82.5"/>
|
||||
<polygon points="124,150 111,172.5 85,172.5 72,150 85,127.5 111,127.5"/>
|
||||
<polygon points="150,195 137,217.5 111,217.5 98,195 111,172.5 137,172.5"/>
|
||||
<polygon points="202,195 189,217.5 163,217.5 150,195 163,172.5 189,172.5"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER hex -->
|
||||
<polygon points="176,150 163,172.5 137,172.5 124,150 137,127.5 163,127.5"
|
||||
fill="#1a0f00" stroke="#ffb300" stroke-width="1.8"/>
|
||||
|
||||
<!-- connections -->
|
||||
<g stroke="#ffb300" stroke-width="1" opacity="0.6">
|
||||
<line x1="176" y1="150" x2="202" y2="150"/>
|
||||
<line x1="124" y1="150" x2="98" y2="150"/>
|
||||
<line x1="163" y1="128" x2="176" y2="105"/>
|
||||
<line x1="137" y1="128" x2="124" y2="105"/>
|
||||
<line x1="163" y1="173" x2="176" y2="195"/>
|
||||
<line x1="137" y1="173" x2="124" y2="195"/>
|
||||
</g>
|
||||
|
||||
<!-- CENTER node -->
|
||||
<circle cx="150" cy="150" r="10" fill="#ffb300" opacity="0.95"/>
|
||||
<circle cx="150" cy="150" r="5" fill="#0a0600"/>
|
||||
|
||||
<!-- ring 1 nodes -->
|
||||
<g fill="#ff8f00" opacity="0.9">
|
||||
<circle cx="202" cy="150" r="6"/>
|
||||
<circle cx="176" cy="105" r="6"/>
|
||||
<circle cx="124" cy="105" r="6"/>
|
||||
<circle cx="98" cy="150" r="6"/>
|
||||
<circle cx="124" cy="195" r="6"/>
|
||||
<circle cx="176" cy="195" r="6"/>
|
||||
</g>
|
||||
<g fill="#0a0600">
|
||||
<circle cx="202" cy="150" r="2.5"/>
|
||||
<circle cx="176" cy="105" r="2.5"/>
|
||||
<circle cx="124" cy="105" r="2.5"/>
|
||||
<circle cx="98" cy="150" r="2.5"/>
|
||||
<circle cx="124" cy="195" r="2.5"/>
|
||||
<circle cx="176" cy="195" r="2.5"/>
|
||||
</g>
|
||||
|
||||
<rect x="0" y="143" width="300" height="2" fill="#ffb300" opacity="0.07"/>
|
||||
</g>
|
||||
|
||||
<circle cx="150" cy="150" r="140" fill="none" stroke="#ffb300" stroke-width="2.5"/>
|
||||
<circle cx="150" cy="150" r="145" fill="none" stroke="#ff8f00" stroke-width="0.5" opacity="0.4" stroke-dasharray="8 4"/>
|
||||
<g stroke="#ffb300" stroke-width="1.5" fill="none" opacity="0.8">
|
||||
<path d="M44,44 L20,44 L20,70"/>
|
||||
<path d="M256,44 L280,44 L280,70"/>
|
||||
<path d="M44,256 L20,256 L20,230"/>
|
||||
<path d="M256,256 L280,256 L280,230"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
34
templates/base.html
Normal file
34
templates/base.html
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{{ config.title }}{% endblock %}</title>
|
||||
<meta name="description" content="{{ config.description }}">
|
||||
|
||||
{# Open Graph / social card. Reuses the SVG hex mark as the image. #}
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="{{ config.title }}">
|
||||
<meta property="og:description" content="{{ config.description }}">
|
||||
<meta property="og:url" content="{{ config.base_url }}">
|
||||
<meta property="og:image" content="{{ get_url(path='hyperhive.svg') }}">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="{{ get_url(path='favicon.svg') }}">
|
||||
<link rel="stylesheet" href="{{ get_url(path='main.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<main class="shell">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<pre class="banner-thin">░▒▓█▓▒░ HYPERHIVE ░▒▓█▓▒░</pre>
|
||||
<p class="footer-links">
|
||||
<a href="http://localhost:3000/hyperhive">code on the forge</a>
|
||||
<span class="sep">·</span>
|
||||
<a href="{{ get_url(path='') }}">home</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
64
templates/index.html
Normal file
64
templates/index.html
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{# Hero — hex motif left, headline + tagline + CTA right. Stacks
|
||||
vertically on narrow viewports via the .hero CSS grid. #}
|
||||
<section class="hero">
|
||||
<div class="hero-art" aria-hidden="true">
|
||||
{# Inline so the SVG inherits the page's font + can be styled
|
||||
(hover pulse animation on the rings). Same source as the
|
||||
dashboard branding/hyperhive.svg. #}
|
||||
{% set hex_svg = load_data(path="hex-mark.svg") %}
|
||||
{{ hex_svg | safe }}
|
||||
</div>
|
||||
<div class="hero-text">
|
||||
<h1>
|
||||
<span class="banner-glyph">░▒▓</span>
|
||||
hyperhive
|
||||
<span class="banner-glyph">▓▒░</span>
|
||||
</h1>
|
||||
<p class="hero-tagline">{{ config.description }}</p>
|
||||
<p class="hero-cta">
|
||||
<a class="cta-primary" href="http://localhost:3000/hyperhive/hyperhive">
|
||||
◆ explore the code →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Landing prose — pulled from _index.md so non-engineers can edit
|
||||
copy without touching templates. #}
|
||||
<section class="prose">
|
||||
{{ section.content | safe }}
|
||||
</section>
|
||||
|
||||
{# Three-column "what's inside" — quick orientation for visitors
|
||||
who clicked through from a link without context. Copy here is
|
||||
intentionally short; deep dives belong in /docs (future). #}
|
||||
<section class="grid-3">
|
||||
<article class="card">
|
||||
<h2><span class="card-glyph">▣</span> the swarm</h2>
|
||||
<p>
|
||||
Each agent is a NixOS container with its own claude session,
|
||||
a logical name, and a parent in the topology tree. Containers
|
||||
come and go; the topology is the operator's facts file.
|
||||
</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2><span class="card-glyph">⟁</span> the dashboard</h2>
|
||||
<p>
|
||||
One web page shows live agent state, the broker stream, the
|
||||
approval queue, scheduled prompts, and the rebuild pipeline.
|
||||
Everything that mutates the swarm passes through here.
|
||||
</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2><span class="card-glyph">◇</span> the boundary</h2>
|
||||
<p>
|
||||
Agents can ask, schedule, request approvals, and message peers
|
||||
— but never spawn / destroy / mutate config themselves. Those
|
||||
actions queue up and wait on the human at the dashboard.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue