From d83f00e4c19b3fa1d1fce8743edc2227d8ec1dc3 Mon Sep 17 00:00:00 2001 From: Rolando Santamaria Maso Date: Sun, 13 Sep 2026 01:15:57 +0200 Subject: [PATCH 1/4] feat(landing): add install.sh one-command installer for prebuilt binaries POSIX-sh installer that downloads the latest bodek release (and optionally odek) from GitHub releases, verifies checksums, and installs into /usr/local/bin or ~/.local/bin with PATH guidance. If odek is missing it asks before installing and prints provider setup steps. --- docs/index.html | 2 +- docs/install.sh | 192 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 docs/install.sh diff --git a/docs/index.html b/docs/index.html index d033e3e..661599d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -72,7 +72,7 @@

Stay in the terminal.
Stay in command.

ONE ENGINE. YOUR CHOICE OF INTERFACE.

Odek does the work.
Bodek keeps it in view.

Use your existing Odek provider configuration, sessions, and tools. The terminal connects to the same engine as the Web UI.

Meet the engine ↗
bodekterminal interface

WebSocket · live events & decisions

odek servetools · memory · sandbox · policy

03 / MAKE YOUR NEXT MOVE

One command.
Back in your flow.

Install Odek and Bodek, configure your provider,
then choose how you want to work.

- +

Start here. Build from here.

Starts Odek’s server and opens a fresh session in the current directory.

bodek

Pick up the thread.

Continue this directory’s last session instead of starting fresh.

bodek --resume
diff --git a/docs/install.sh b/docs/install.sh new file mode 100644 index 0000000..192e8bd --- /dev/null +++ b/docs/install.sh @@ -0,0 +1,192 @@ +#!/bin/sh +# bodek installer — downloads prebuilt release binaries from GitHub. +# +# Usage: +# curl -fsSL https://bodek.21no.de/install.sh | sh +# sh install.sh [--with-odek] # install odek without asking +# +# Installs bodek (and optionally odek) for the current platform into +# ~/.local/bin (or /usr/local/bin when writable). Verifies every download +# against the release checksums.txt when a sha256 tool is available. +set -eu + +BODEK_REPO="BackendStack21/bodek" +ODEK_REPO="BackendStack21/odek" +GH_API="https://api.github.com/repos" +GH_DL="https://github.com" + +say() { printf '==> %s\n' "$*"; } +warn() { printf 'warning: %s\n' "$*" >&2; } +die() { printf 'error: %s\n' "$*" >&2; exit 1; } + +# ---------------------------------------------------------------- platform +OS=$(uname -s) +ARCH=$(uname -m) +case "$OS" in + Darwin) os=darwin ;; + Linux) os=linux ;; + *) die "unsupported OS '$OS' — this installer covers macOS and Linux." ;; +esac +case "$ARCH" in + x86_64|amd64) arch=amd64 ;; + aarch64|arm64) arch=arm64 ;; + *) die "unsupported architecture '$ARCH'." ;; +esac + +command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 \ + || die "need curl or wget to download." + +fetch() { # fetch -> stdout + if command -v curl >/dev/null 2>&1; then curl -fsSL "$1" + else wget -qO- "$1"; fi +} +download() { # download + if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$2" "$1" + else wget -qO "$2" "$1"; fi +} + +checksum() { # checksum + if command -v sha256sum >/dev/null 2>&1; then + actual=$(sha256sum "$1" | awk '{print $1}') + elif command -v shasum >/dev/null 2>&1; then + actual=$(shasum -a 256 "$1" | awk '{print $1}') + else + warn "no sha256 tool found — skipping checksum verification." + return 0 + fi + [ "$actual" = "$2" ] || die "checksum mismatch for $(basename "$1") — download corrupted or tampered. Aborting." +} + +# ---------------------------------------------------------------- install dir +install_dir="" +pick_install_dir() { + for d in /usr/local/bin "$HOME/.local/bin"; do + if mkdir -p "$d" 2>/dev/null && [ -w "$d" ]; then install_dir=$d; return; fi + done + die "no writable install directory found (tried /usr/local/bin, ~/.local/bin)." +} + +path_has_dir() { case ":$PATH:" in *":$1:"*) return 0 ;; *) return 1 ;; esac; } + +# ---------------------------------------------------------------- releases +latest_tag() { # latest_tag -> "vX.Y.Z" (empty on failure) + # Resolve via the redirect of /releases/latest — no API rate limits. + url="$GH_DL/$1/releases/latest" + if command -v curl >/dev/null 2>&1; then + loc=$(curl -fsSI -o /dev/null -w '%{redirect_url}' "$url" 2>/dev/null || true) + else + loc=$(wget -qS --spider "$url" 2>&1 | sed -n 's/^ *Location: *//p' | tail -1) + fi + case "$loc" in + */tag/*) printf '%s\n' "${loc##*/}" ;; + *) printf '' ;; + esac +} + +checksum_line() { # checksum_line -> hex digest or "" + fetch "$GH_DL/$1/releases/download/$2/checksums.txt" 2>/dev/null \ + | awk -v a="$3" '$2 == a {print $1; exit}' +} + +TMP=$(mktemp -d) || die "cannot create temp dir." +trap 'rm -rf "$TMP"' EXIT INT TERM + +install_asset() { # install_asset + repo=$1 tag=$2 asset=$3 bin=$4 + say "Downloading $asset ($tag)" + download "$GH_DL/$repo/releases/download/$tag/$asset" "$TMP/$asset" + digest=$(checksum_line "$repo" "$tag" "$asset") + if [ -n "$digest" ]; then + checksum "$TMP/$asset" "$digest" + say "Checksum verified." + else + warn "no checksum entry for $asset — skipping verification." + fi + case "$asset" in + *.tar.gz) tar -xzf "$TMP/$asset" -C "$TMP" "$bin" 2>/dev/null \ + || tar -xzf "$TMP/$asset" -C "$TMP" ;; + *) cp "$TMP/$asset" "$TMP/$bin" && chmod +x "$TMP/$bin" ;; + esac + [ -f "$TMP/$bin" ] || die "binary '$bin' not found in archive." + mv -f "$TMP/$bin" "$install_dir/$bin" + chmod +x "$install_dir/$bin" + say "Installed $install_dir/$bin" +} + +# ---------------------------------------------------------------- odek +install_odek() { + tag=$(latest_tag "$ODEK_REPO") + [ -n "$tag" ] || die "cannot resolve the latest odek release (network or GitHub problem)." + install_asset "$ODEK_REPO" "$tag" "odek-$os-$arch" odek + cat </dev/null 2>&1; then + say "Odek found: $(command -v odek) — skipping." + return + fi + printf 'Odek (the engine bodek drives) is not installed.\n' + if [ "${1:-}" = "--with-odek" ]; then + install_odek + return + fi + printf 'Install it now from prebuilt binaries? [y/N] ' + read -r answer || read -r answer > ~/.profile && source ~/.profile +EOF +fi + +cat < Date: Sun, 13 Sep 2026 01:24:10 +0200 Subject: [PATCH 2/4] fix(landing): fail closed on missing checksums and make prompt tty-safe - refuse to install when checksums.txt has no entry for an asset instead of warn-and-continue - never read the script's own stdin for the odek prompt: answer from the terminal only when stdout is a tty, default No otherwise (curl | sh safe) - skip-odek message now points at --with-odek; landing copy clarifies macOS/Linux installer vs Windows binaries and mentions provider key --- docs/index.html | 2 +- docs/install.sh | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/index.html b/docs/index.html index 661599d..69addcf 100644 --- a/docs/index.html +++ b/docs/index.html @@ -72,7 +72,7 @@

Stay in the terminal.
Stay in command.

ONE ENGINE. YOUR CHOICE OF INTERFACE.

Odek does the work.
Bodek keeps it in view.

Use your existing Odek provider configuration, sessions, and tools. The terminal connects to the same engine as the Web UI.

Meet the engine ↗
bodekterminal interface

WebSocket · live events & decisions

odek servetools · memory · sandbox · policy

03 / MAKE YOUR NEXT MOVE

One command.
Back in your flow.

Install Odek and Bodek, configure your provider,
then choose how you want to work.

- +

Start here. Build from here.

Starts Odek’s server and opens a fresh session in the current directory.

bodek

Pick up the thread.

Continue this directory’s last session instead of starting fresh.

bodek --resume
diff --git a/docs/install.sh b/docs/install.sh index 192e8bd..0843e3a 100644 --- a/docs/install.sh +++ b/docs/install.sh @@ -3,8 +3,11 @@ # # Usage: # curl -fsSL https://bodek.21no.de/install.sh | sh +# curl -fsSL https://bodek.21no.de/install.sh | sh -s -- --with-odek # sh install.sh [--with-odek] # install odek without asking # +# macOS and Linux. Windows users: grab a binary from the releases page. +# # Installs bodek (and optionally odek) for the current platform into # ~/.local/bin (or /usr/local/bin when writable). Verifies every download # against the release checksums.txt when a sha256 tool is available. @@ -100,7 +103,9 @@ install_asset() { # install_asset checksum "$TMP/$asset" "$digest" say "Checksum verified." else - warn "no checksum entry for $asset — skipping verification." + # Fail closed: a missing/unfetchable checksum line is suspicious, not a + # reason to install unverified code. + die "no checksum entry for $asset — refusing to install unverified." fi case "$asset" in *.tar.gz) tar -xzf "$TMP/$asset" -C "$TMP" "$bin" 2>/dev/null \ @@ -116,7 +121,7 @@ install_asset() { # install_asset # ---------------------------------------------------------------- odek install_odek() { tag=$(latest_tag "$ODEK_REPO") - [ -n "$tag" ] || die "cannot resolve the latest odek release (network or GitHub problem)." + [ -n "$tag" ] || die "cannot resolve the latest odek release (network or GitHub problem — install curl if it is missing)." install_asset "$ODEK_REPO" "$tag" "odek-$os-$arch" odek cat < Date: Sun, 13 Sep 2026 09:42:52 +0200 Subject: [PATCH 3/4] fix(landing): stack install buttons below the curl command box --- docs/landing.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/landing.css b/docs/landing.css index 8802358..6f9390e 100644 --- a/docs/landing.css +++ b/docs/landing.css @@ -1,3 +1,3 @@ :root{--bg:#08090b;--panel:#111317;--line:#ffffff19;--text:#f3f1eb;--muted:#a7a9b0;--amber:#ffbb52;--mono:'JetBrains Mono',ui-monospace,monospace;--sans:'Space Grotesk',system-ui,sans-serif;color-scheme:dark} *{box-sizing:border-box}html{scroll-padding-top:32px}body{margin:0;background:var(--bg);color:var(--text);font:16px/1.7 var(--sans)}a{color:var(--amber);text-decoration:none}a:hover{text-decoration:underline}a:focus-visible,button:focus-visible,summary:focus-visible{outline:2px solid var(--amber);outline-offset:5px}button{font:inherit}::selection{background:#ffbb5244}.wrap{max-width:1248px;margin:auto;padding:0 32px}header{border-bottom:1px solid var(--line)}header .wrap{min-height:88px;display:flex;align-items:center;justify-content:space-between}.brand{font-size:26px;font-weight:700;letter-spacing:-1px}.brand b{color:var(--amber)}nav{display:flex;gap:28px;font-size:14px}nav a{color:var(--muted)}main{padding:80px 0 0}.eyebrow{font:12px/1.5 var(--mono);letter-spacing:.12em;color:var(--amber);margin:0 0 24px}h1{font-size:clamp(44px,6.5vw,82px);line-height:1.06;letter-spacing:-.055em;font-weight:600;margin:0 0 28px}h1 span{color:var(--amber)}.lede{max-width:640px;font-size:20px;line-height:1.7;color:var(--muted);margin:0 0 30px}.hero-actions{display:flex;gap:12px;flex-wrap:wrap}.button{display:inline-flex;align-items:center;gap:38px;padding:12px 20px;border:1px solid var(--line);border-radius:7px;color:var(--text);font-weight:500}.button:hover{text-decoration:none;border-color:var(--amber)}.button.primary{background:var(--amber);color:#231805;border-color:var(--amber)}.hero-meta{font:12px/1.7 var(--mono);color:var(--muted);margin:22px 0 50px}.shot{margin:0 0 36px;border:1px solid #ffbb5233;border-radius:12px;overflow:hidden;box-shadow:0 25px 90px -45px #ffbb5240}.shot img{display:block;width:100%;height:auto}.term{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:24px;overflow:auto}.term code{font:14px/1.9 var(--mono);white-space:pre;display:block}.cm,.hint{color:var(--muted)}.ps{color:var(--amber)}.hint{font-size:14px}section{margin-top:80px}h2{font-size:36px;line-height:1.15;letter-spacing:-.04em;font-weight:500;margin:0 0 24px}h3{font-size:23px;font-weight:500;line-height:1.3;letter-spacing:-.025em}p{margin:0 0 16px}.plain,.grid{padding:0;list-style:none}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:24px}.plain li{margin-bottom:20px}footer{margin-top:80px;padding:30px 0;border-top:1px solid var(--line);color:var(--muted);font-size:14px}footer .wrap{display:flex;justify-content:space-between;gap:30px}footer nav{flex-wrap:wrap}code,kbd{font-family:var(--mono)}[hidden]{display:none!important}@media(max-width:760px){.wrap{padding:0 20px}main{padding-top:48px}header .wrap{min-height:76px;gap:16px;flex-wrap:wrap}nav{gap:16px}.lede{font-size:18px}.grid{grid-template-columns:1fr}footer .wrap{flex-direction:column}h2{font-size:30px}}@media(prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}} -.skip{position:absolute;top:-100px;left:20px;padding:10px;background:var(--panel);z-index:5}.skip:focus{top:10px}.brand{color:var(--text)}.brand:hover{text-decoration:none}.nav-start{color:var(--amber)}.hero-meta span{color:#62636d;padding:0 10px}.hero{position:relative}.hero:after{content:'';position:absolute;pointer-events:none;inset:-80px -20px 0 25%;z-index:-1;background:radial-gradient(ellipse at top right,#ffbb5210,transparent 65%)}.showcase{margin-top:64px}.section-head{display:flex;justify-content:space-between;align-items:end;gap:30px;margin-bottom:30px}.section-head h2{margin-bottom:0}.section-head>p{color:var(--muted);font-size:16px;margin:0}.tabs{display:flex;gap:4px;flex-wrap:wrap;border-bottom:1px solid var(--line);padding:0 16px}.tabs button{color:var(--muted);background:none;border:0;border-bottom:2px solid transparent;padding:18px 16px;cursor:pointer;font-size:14px}.tabs button[aria-selected=true]{color:var(--amber);border-color:var(--amber)}.tabs button:hover{color:var(--text)}.theme-gallery{border:1px solid #ffbb5230;border-radius:12px;overflow:hidden;background:#111216;box-shadow:0 30px 100px -60px #ffbb5250}.theme-swatch{display:inline-block;width:9px;height:9px;margin-right:8px;border-radius:50%;background:var(--amber)}.theme-swatch.ember-light{background:#f4ead5}.theme-swatch.high-contrast{background:#fff}.theme-swatch.classic{background:#bd8dfa}.terminal-bar{display:flex;justify-content:space-between;gap:16px;padding:14px 20px;font:12px/1.5 var(--mono);color:var(--muted);border-bottom:1px solid var(--line)}.theme-panel img{width:100%;height:auto;display:block}.theme-panel>a{display:block}.gallery-caption{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:16px 0 0;color:var(--muted);font-size:12px}.gallery-caption p{margin:0 auto 0 0}.gallery-caption code{color:var(--amber)}.workflow{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:40px;border-bottom:1px solid var(--line);padding-bottom:64px;margin-top:60px}.workflow p{color:var(--muted);font-size:16px}.feature-key{display:block;min-height:32px;font-size:13px;color:var(--muted)}kbd{display:inline-block;min-width:26px;text-align:center;border:1px solid #ffffff28;border-bottom-width:3px;border-radius:5px;padding:3px 7px;font-size:12px;color:var(--text);background:#17191d}.why-section{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.2fr);gap:88px}.why-intro p{color:var(--muted);max-width:350px}.why-intro .eyebrow{color:var(--amber)}.why-intro h2{font-size:clamp(32px,4vw,46px)}.why-intro h2 span{color:var(--amber)}.why-list{list-style:none;padding:0;margin:0}.why-list li{display:grid;grid-template-columns:32px minmax(0,1fr);gap:20px;padding:34px 0;border-top:1px solid var(--line)}.why-list li:first-child{padding-top:0;border-top:0}.why-list h3{font-size:32px;line-height:1.12;margin:0 0 20px}.why-list .eyebrow{font-size:11px;color:var(--muted);margin-bottom:16px}.why-list p:not(.eyebrow){color:var(--muted)}.why-list a{font-size:14px;margin-right:15px}.number{font:13px var(--mono);color:var(--amber);padding-top:2px}.engine-section{display:grid;grid-template-columns:1.2fr 1fr;gap:80px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:56px 0}.engine-section p{color:var(--muted)}.engine-section .eyebrow{color:var(--amber)}.connection{align-self:center}.connection>div{border:1px solid var(--line);background:var(--panel);border-radius:8px;padding:20px 24px;display:flex;justify-content:space-between;align-items:center;gap:16px}.connection strong{font:18px var(--mono);color:var(--amber)}.connection span{font-size:12px;color:var(--muted)}.connection p{text-align:center;margin:14px 0;font-size:24px}.connection p span{vertical-align:middle;margin-left:8px}.install-links{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:32px 0}.install-links>span{display:block;width:100%;font-size:13px;color:var(--muted);margin-top:4px}.launch-examples{border:1px solid var(--line);border-radius:10px;background:var(--panel);overflow:hidden}.launch-examples [data-panel]{padding:28px}.launch-examples h3{margin:0 0 10px}.launch-examples p{color:var(--muted)}.command{display:flex;align-items:center;gap:20px;border-top:1px solid var(--line);padding-top:18px}.command pre{margin:0;overflow:auto;flex:1;min-width:0;font-size:15px;color:var(--amber)}.command button{background:#ffffff08;color:var(--text);border:1px solid var(--line);border-radius:5px;padding:7px 14px;cursor:pointer;font-size:13px}.hint{margin-top:20px}.closing{margin-top:90px;padding-top:48px;border-top:1px solid var(--line);display:flex;gap:30px;align-items:center;justify-content:space-between}.closing p{font-size:30px;line-height:1.15;letter-spacing:-.035em;margin:0}.closing p span{color:var(--amber)}[role=tabpanel]:focus-visible{outline:2px solid var(--amber);outline-offset:-3px}@media(max-width:900px){.why-section{gap:40px}.engine-section{gap:32px}.connection>div{align-items:start;flex-direction:column;gap:6px}.workflow{gap:24px}.section-head{align-items:start;flex-direction:column;gap:20px}}@media(max-width:650px){nav{font-size:12px}header .wrap{padding-top:14px;padding-bottom:14px}.hero-meta span{padding:0 2px}.tabs{padding:0 8px;gap:0}.tabs button{padding:14px 10px;font-size:12px}.terminal-bar{font-size:10px;padding:12px;flex-wrap:wrap}.workflow,.why-section,.engine-section{grid-template-columns:1fr}.workflow{gap:28px}.workflow h3{margin-top:14px}.why-list h3{font-size:30px}.why-intro p{max-width:none}.why-list li{gap:12px;grid-template-columns:24px minmax(0,1fr)}.engine-section{gap:30px}.connection>div{flex-direction:row;align-items:center}.closing{align-items:start;flex-direction:column;gap:24px}.launch-examples [data-panel]{padding:20px}.button{gap:20px}.command{gap:10px}}@media(prefers-reduced-motion:no-preference){.tabs button,.button{transition:background-color .16s,border-color .16s,color .16s}} +.skip{position:absolute;top:-100px;left:20px;padding:10px;background:var(--panel);z-index:5}.skip:focus{top:10px}.brand{color:var(--text)}.brand:hover{text-decoration:none}.nav-start{color:var(--amber)}.hero-meta span{color:#62636d;padding:0 10px}.hero{position:relative}.hero:after{content:'';position:absolute;pointer-events:none;inset:-80px -20px 0 25%;z-index:-1;background:radial-gradient(ellipse at top right,#ffbb5210,transparent 65%)}.showcase{margin-top:64px}.section-head{display:flex;justify-content:space-between;align-items:end;gap:30px;margin-bottom:30px}.section-head h2{margin-bottom:0}.section-head>p{color:var(--muted);font-size:16px;margin:0}.tabs{display:flex;gap:4px;flex-wrap:wrap;border-bottom:1px solid var(--line);padding:0 16px}.tabs button{color:var(--muted);background:none;border:0;border-bottom:2px solid transparent;padding:18px 16px;cursor:pointer;font-size:14px}.tabs button[aria-selected=true]{color:var(--amber);border-color:var(--amber)}.tabs button:hover{color:var(--text)}.theme-gallery{border:1px solid #ffbb5230;border-radius:12px;overflow:hidden;background:#111216;box-shadow:0 30px 100px -60px #ffbb5250}.theme-swatch{display:inline-block;width:9px;height:9px;margin-right:8px;border-radius:50%;background:var(--amber)}.theme-swatch.ember-light{background:#f4ead5}.theme-swatch.high-contrast{background:#fff}.theme-swatch.classic{background:#bd8dfa}.terminal-bar{display:flex;justify-content:space-between;gap:16px;padding:14px 20px;font:12px/1.5 var(--mono);color:var(--muted);border-bottom:1px solid var(--line)}.theme-panel img{width:100%;height:auto;display:block}.theme-panel>a{display:block}.gallery-caption{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:16px 0 0;color:var(--muted);font-size:12px}.gallery-caption p{margin:0 auto 0 0}.gallery-caption code{color:var(--amber)}.workflow{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:40px;border-bottom:1px solid var(--line);padding-bottom:64px;margin-top:60px}.workflow p{color:var(--muted);font-size:16px}.feature-key{display:block;min-height:32px;font-size:13px;color:var(--muted)}kbd{display:inline-block;min-width:26px;text-align:center;border:1px solid #ffffff28;border-bottom-width:3px;border-radius:5px;padding:3px 7px;font-size:12px;color:var(--text);background:#17191d}.why-section{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.2fr);gap:88px}.why-intro p{color:var(--muted);max-width:350px}.why-intro .eyebrow{color:var(--amber)}.why-intro h2{font-size:clamp(32px,4vw,46px)}.why-intro h2 span{color:var(--amber)}.why-list{list-style:none;padding:0;margin:0}.why-list li{display:grid;grid-template-columns:32px minmax(0,1fr);gap:20px;padding:34px 0;border-top:1px solid var(--line)}.why-list li:first-child{padding-top:0;border-top:0}.why-list h3{font-size:32px;line-height:1.12;margin:0 0 20px}.why-list .eyebrow{font-size:11px;color:var(--muted);margin-bottom:16px}.why-list p:not(.eyebrow){color:var(--muted)}.why-list a{font-size:14px;margin-right:15px}.number{font:13px var(--mono);color:var(--amber);padding-top:2px}.engine-section{display:grid;grid-template-columns:1.2fr 1fr;gap:80px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:56px 0}.engine-section p{color:var(--muted)}.engine-section .eyebrow{color:var(--amber)}.connection{align-self:center}.connection>div{border:1px solid var(--line);background:var(--panel);border-radius:8px;padding:20px 24px;display:flex;justify-content:space-between;align-items:center;gap:16px}.connection strong{font:18px var(--mono);color:var(--amber)}.connection span{font-size:12px;color:var(--muted)}.connection p{text-align:center;margin:14px 0;font-size:24px}.connection p span{vertical-align:middle;margin-left:8px}.install-links{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:32px 0}.install-links>.command{flex:1 1 100%;min-width:0}.install-links>span{display:block;width:100%;font-size:13px;color:var(--muted);margin-top:4px}.launch-examples{border:1px solid var(--line);border-radius:10px;background:var(--panel);overflow:hidden}.launch-examples [data-panel]{padding:28px}.launch-examples h3{margin:0 0 10px}.launch-examples p{color:var(--muted)}.command{display:flex;align-items:center;gap:20px;border-top:1px solid var(--line);padding-top:18px}.command pre{margin:0;overflow:auto;flex:1;min-width:0;font-size:15px;color:var(--amber)}.command button{background:#ffffff08;color:var(--text);border:1px solid var(--line);border-radius:5px;padding:7px 14px;cursor:pointer;font-size:13px}.hint{margin-top:20px}.closing{margin-top:90px;padding-top:48px;border-top:1px solid var(--line);display:flex;gap:30px;align-items:center;justify-content:space-between}.closing p{font-size:30px;line-height:1.15;letter-spacing:-.035em;margin:0}.closing p span{color:var(--amber)}[role=tabpanel]:focus-visible{outline:2px solid var(--amber);outline-offset:-3px}@media(max-width:900px){.why-section{gap:40px}.engine-section{gap:32px}.connection>div{align-items:start;flex-direction:column;gap:6px}.workflow{gap:24px}.section-head{align-items:start;flex-direction:column;gap:20px}}@media(max-width:650px){nav{font-size:12px}header .wrap{padding-top:14px;padding-bottom:14px}.hero-meta span{padding:0 2px}.tabs{padding:0 8px;gap:0}.tabs button{padding:14px 10px;font-size:12px}.terminal-bar{font-size:10px;padding:12px;flex-wrap:wrap}.workflow,.why-section,.engine-section{grid-template-columns:1fr}.workflow{gap:28px}.workflow h3{margin-top:14px}.why-list h3{font-size:30px}.why-intro p{max-width:none}.why-list li{gap:12px;grid-template-columns:24px minmax(0,1fr)}.engine-section{gap:30px}.connection>div{flex-direction:row;align-items:center}.closing{align-items:start;flex-direction:column;gap:24px}.launch-examples [data-panel]{padding:20px}.button{gap:20px}.command{gap:10px}}@media(prefers-reduced-motion:no-preference){.tabs button,.button{transition:background-color .16s,border-color .16s,color .16s}} From 40a66cec59672bcfb67bd275fec9f38625af2d9b Mon Sep 17 00:00:00 2001 From: Rolando Santamaria Maso Date: Sun, 13 Sep 2026 09:45:25 +0200 Subject: [PATCH 4/4] feat(landing): surface the install command in the hero section --- docs/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.html b/docs/index.html index 69addcf..322962f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -37,6 +37,7 @@

Stay in the terminal.
Stay in command.

Your agent is working. You’re in the loop. Follow the tools, inspect the changes, and make the call—with Odek’s power at your fingertips.

+
curl -fsSL https://bodek.21no.de/install.sh | sh

Go + Bubble Tea / MIT licensed / Powered by Odek