Gladex Agent Logs
Agent run logs & app logs · env: prod · LAN-only investor surface
Overview
| Run logs | 753 files, 35 MB |
| Latest run log | run-20260929-224605-351.log |
| Log directory | /data/agent-logs |
| App log directory | /opt/startup/prod/logs |
Run logs (newest first, last 50)
| File | Size | Modified (UTC) |
|---|---|---|
| run-20260929-224605-351.log | 149 KB | 2026-09-29 20:55:23 |
| run-20260929-201447-350.log | 508 KB | 2026-09-29 20:36:05 |
| run-20260929-192011-349.log | 227 KB | 2026-09-29 18:04:47 |
| run-20260929-184400-348.log | 464 KB | 2026-09-29 17:10:11 |
| run-20260929-175208-347.log | 226 KB | 2026-09-29 16:34:00 |
| run-20260929-171135-346.log | 238 KB | 2026-09-29 15:42:08 |
| run-20260929-162028-345.log | 263 KB | 2026-09-29 15:01:35 |
| run-20260929-161028-344.log | 153 B | 2026-09-29 14:10:28 |
| run-20260929-160027-343.log | 190 B | 2026-09-29 14:00:27 |
| run-20260929-155026-342.log | 190 B | 2026-09-29 13:50:27 |
| run-20260929-154025-341.log | 153 B | 2026-09-29 13:40:26 |
| run-20260929-153025-340.log | 153 B | 2026-09-29 13:30:25 |
| run-20260929-152024-339.log | 153 B | 2026-09-29 13:20:25 |
| run-20260929-151023-338.log | 153 B | 2026-09-29 13:10:24 |
| run-20260929-150021-337.log | 153 B | 2026-09-29 13:00:23 |
| run-20260929-145020-336.log | 153 B | 2026-09-29 12:50:21 |
| run-20260929-144019-335.log | 153 B | 2026-09-29 12:40:20 |
| run-20260929-143018-334.log | 153 B | 2026-09-29 12:30:19 |
| run-20260929-142017-333.log | 153 B | 2026-09-29 12:20:18 |
| run-20260929-141017-332.log | 153 B | 2026-09-29 12:10:17 |
| run-20260929-140016-331.log | 153 B | 2026-09-29 12:00:17 |
| run-20260929-135015-330.log | 153 B | 2026-09-29 11:50:16 |
| run-20260929-134014-329.log | 153 B | 2026-09-29 11:40:15 |
| run-20260929-133014-328.log | 153 B | 2026-09-29 11:30:14 |
| run-20260929-132013-327.log | 153 B | 2026-09-29 11:20:14 |
| run-20260929-131012-326.log | 153 B | 2026-09-29 11:10:13 |
| run-20260929-121024-325.log | 296 KB | 2026-09-29 11:00:12 |
| run-20260929-110953-324.log | 242 KB | 2026-09-29 10:00:24 |
| run-20260929-095926-323.log | 329 KB | 2026-09-29 08:59:53 |
| run-20260929-072444-322.log | 382 KB | 2026-09-29 07:49:26 |
| run-20260929-065102-321.log | 175 KB | 2026-09-29 05:14:44 |
| run-20260929-052828-320.log | 333 KB | 2026-09-29 04:41:02 |
| run-20260929-040138-319.log | 298 KB | 2026-09-29 03:18:28 |
| run-20260929-020936-318.log | 217 KB | 2026-09-29 01:51:38 |
| run-20260929-015935-317.log | 153 B | 2026-09-28 23:59:36 |
| run-20260929-014935-316.log | 153 B | 2026-09-28 23:49:35 |
| run-20260929-011234-315.log | 247 KB | 2026-09-28 23:39:35 |
| run-20260928-234838-314.log | 263 KB | 2026-09-28 23:02:34 |
| run-20260928-222402-313.log | 319 KB | 2026-09-28 21:38:38 |
| run-20260928-211218-312.log | 234 KB | 2026-09-28 20:14:02 |
| run-20260928-201031-311.log | 248 KB | 2026-09-28 19:02:18 |
| run-20260928-184021-310.log | 439 KB | 2026-09-28 18:00:31 |
| run-20260928-171725-309.log | 236 KB | 2026-09-28 16:30:21 |
| run-20260928-161526-308.log | 183 KB | 2026-09-28 15:07:25 |
| run-20260928-160525-307.log | 153 B | 2026-09-28 14:05:26 |
| run-20260928-155524-306.log | 153 B | 2026-09-28 13:55:25 |
| run-20260928-154524-305.log | 153 B | 2026-09-28 13:45:24 |
| run-20260928-153523-304.log | 153 B | 2026-09-28 13:35:24 |
| run-20260928-152522-303.log | 153 B | 2026-09-28 13:25:23 |
| run-20260928-151521-302.log | 153 B | 2026-09-28 13:15:22 |
Tail — run-20260929-224605-351.log (last 200 lines)
return 0
}
echo "=== A. investor app over HTTP: dev ($DEV) and prod ($PROD) ==="
for base in "$DEV" "$PROD"; do
[ "$base" = "$DEV" ] && env=dev || env=prod
check_page "$env /" 200 "$base/" \
'<title>gladex.de</title>' '<h1>gladex.de</h1>' '<html lang="en">' 'name="viewport"'
check_page "$env /team" 200 "$base/team" \
'<title>Gladex — Team</title>' '<h1>The Team</h1>' \
'Lena Hartmann' 'Jonas Weber' 'Mia Schneider' 'Leon Fischer'
check_page "$env /info" 200 "$base/info" \
'<title>Gladex — Unified AI Developer Workspace</title>'
check_page "$env /stats" 200 "$base/stats" \
'<title>Gladex — Container Statistics</title>'
check_page "$env /changelog" 200 "$base/changelog" \
'<title>Gladex.de Changelog</title>'
check_page "$env /mailbox" 200 "$base/mailbox" \
'<title>Gladex.de Mailbox</title>'
# The two gates: neither may render a page.
got=$(http_get "$base/login")
if [ "$got" = "302" ]; then ok "$env /login -> HTTP 302 (auth gate intact)"
else bad "$env /login -> HTTP $got, want 302"; fi
got=$(http_get "$base/vhost-ui-smoke-no-such-route")
if [ "$got" = "302" ]; then ok "$env unknown path -> HTTP 302 (catch-all intact)"
else bad "$env unknown path -> HTTP $got, want 302"; fi
if has "$base/investor" || has 'Location: /investor'; then
ok "$env unknown path redirects to /investor"
else
# curl hides response headers; follow the Location instead.
got=$(curl -sS -o "$BODY" -w '%{http_code}' --max-time "$TMO" \
"$base/vhost-ui-smoke-no-such-route" -L 2>/dev/null || echo "000")
if has '<title>' || [ "$got" = "200" ]; then
ok "$env unknown path redirects to a rendered page"
else
bad "$env unknown path redirect target did not render"
fi
fi
got=$(http_get "$base/healthz")
if [ "$got" = "200" ] && has '"status":"ok"'; then
ok "$env /healthz -> 200 + status ok"
else
bad "$env /healthz -> HTTP $got + status ok (want 200)"
fi
done
echo
echo "=== B. HTTPS vhosts after the wildcard narrowing ==="
# The seven names gladex-ssl.conf still declares, each with the page its Host
# header selects (app.php routes on Host for info/log/stats).
check_host "apex gladex.de" gladex.de "/" 200 \
'<title>gladex.de</title>' '<h1>gladex.de</h1>'
check_host "dev.gladex.de" dev.gladex.de "/" 200 \
'<title>gladex.de</title>'
check_host "team.gladex.de /team" team.gladex.de "/team" 200 \
'<title>Gladex — Team</title>' 'Jonas Weber' 'Leon Fischer'
# team.gladex.de's ROOT currently renders the landing page, not the team page.
# Pinned as-is on purpose: if someone makes the bare hostname serve /team,
# that is a real product decision and this line should go red and be changed
# deliberately, not drift.
check_host "team.gladex.de / (root)" team.gladex.de "/" 200 \
'<title>gladex.de</title>'
check_host "info.gladex.de" info.gladex.de "/" 200 \
'<title>Gladex — Unified AI Developer Workspace</title>'
check_host "stats.gladex.de" stats.gladex.de "/" 200 \
'<title>Gladex — Container Statistics</title>'
check_host "log.gladex.de" log.gladex.de "/" 200 \
'<title>Gladex — Agent Logs</title>'
# The two vhosts the change added: they must serve their own apps, NOT ours.
check_host "photos.gladex.de" photos.gladex.de "/" 200 \
'Immich'
# cloud.gladex.de / answered 200 directly for as long as Nextcloud was NOT
# installed. Once INBOX line 468 installed it (2026-09-29), an unauthenticated
# GET / is a single 302 to Nextcloud's own login page — correct Nextcloud
# behaviour, not a failure and not a loop — so this line now asserts WHERE THE
# REQUEST LANDS instead of the status of the first hop. The hop count is read
# explicitly because `-L` alone would swallow a redirect loop into a bare
# `000`; two assertions, exactly the two check_host() used to make (status,
# marker), so the suite's assertion count does not move.
cloud_res=$(curl -skL -o "$BODY" -w '%{http_code} %{num_redirects}' --max-time "$TMO" \
--resolve "cloud.gladex.de:443:$IP" "https://cloud.gladex.de/" 2>/dev/null || echo "000 99")
cloud_code=${cloud_res% *}
cloud_hops=${cloud_res#* }
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && sed -n '78,100p' tests/test_cli_version.php; echo "=== grep download markers in tests ==="; grep -rn "download-btn\|install-box\|Download Gladex CLI\|Download — Gladex" tests/ | head -20
}
/** Render download.php in a fresh PHP process; return the badge version ('' = no badge). */
function render_badge(string $file, ?string $const): string {
$prefix = $const !== null ? 'const GLADEX_APP_VERSION = ' . var_export($const, true) . '; ' : '';
$code = $prefix . 'ob_start(); include $argv[1]; $h = ob_get_clean(); '
. 'if (preg_match(\'/version-badge">v([^<]+)</\', $h, $m)) echo $m[1];';
$out = [];
$rc = 1;
exec('php -r ' . escapeshellarg($code) . ' ' . escapeshellarg($file), $out, $rc);
return ($rc === 0 && $out) ? trim(implode('', $out)) : '';
}
/** All distinct versions of the two /docs CLI mentions: [download-line[], ascii-diagram[]]. */
function docs_cli_mentions(string $src): array {
preg_match_all('/Go CLI binary \(v(\d+\.\d+\.\d+)\)/', $src, $a);
preg_match_all('/gladex v(\d+\.\d+\.\d+)/', $src, $b);
return [array_values(array_unique($a[1])), array_values(array_unique($b[1]))];
}
$REPO = dirname(__DIR__);
$CHANGELOG = "$REPO/CHANGELOG.md";
$BUILD = "$REPO/app/src/go/build.sh";
=== grep download markers in tests ===
[0m$ [0mcd /data/repo && sed -n '1,40p' app/src/php/download.php; echo "=== md5 checks ==="; md5sum app/bin/gladex /opt/startup/dev/bin/gladex /opt/startup/prod/bin/gladex app/src/vscode/gladex-0.1.0.vsix
<?php
/**
* Gladex CLI Download Page — public landing for binary downloads
*
* CLI + app share ONE version train: the CHANGELOG top entry, surfaced by
* app.php's GLADEX_APP_VERSION const (app.php includes this file, so the
* const is always defined in-app). The old '$version = 0.2.0' literal went
* permanently stale — see CHANGELOG 0.4.28. '0.0.0' is a loud sentinel for
* standalone rendering without the const; the test suite asserts it never
* reaches a served badge.
*/
$version = defined('GLADEX_APP_VERSION') ? GLADEX_APP_VERSION : '0.0.0';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Download the Gladex CLI — unified AI developer workspace for context, workflows, and tool connectivity.">
<meta name="theme-color" content="#0a0a0f">
<meta property="og:title" content="Download Gladex CLI">
<meta property="og:description" content="Unified AI developer workspace. Store context, run workflows, connect AI tools.">
<meta property="og:type" content="website">
<title>Download — Gladex CLI</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%230a0a0f'/><text x='50' y='68' font-size='52' font-family='system-ui' font-weight='200' fill='white' text-anchor='middle'>G</text></svg>">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
min-height: 100vh;
background: #0a0a0f;
color: #e8e8ed;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
line-height: 1.6;
}
.container {
max-width: 680px;
margin: 0 auto;
padding: 4rem 2rem;
}
h1 {
=== md5 checks ===
50c2b4b611d086bdae268578c876cc0d app/bin/gladex
50c2b4b611d086bdae268578c876cc0d /opt/startup/dev/bin/gladex
50c2b4b611d086bdae268578c876cc0d /opt/startup/prod/bin/gladex
75dc7565c4f4e2131101808ded53e086 app/src/vscode/gladex-0.1.0.vsix
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && grep -n "download" tests/test_app_contrast.php tests/test_app_contrast_meta.php tests/test_grid_320.php tests/test_page_lang.php tests/test_investor_heading.php tests/test_docs_mobile.php tests/test_chat_a11y.php 2>/dev/null | head -30; echo "=== contrast files ==="; grep -n "files\|scan\|\$pages\|docs.php" tests/test_app_contrast.php | head -25
=== contrast files ===
233: * is precisely the `}` the NEXT selector stands behind, so the scan lands
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && grep -n "app.php\|landing.php\|stats.php\|glob\|scandir\|SOURCE\|\\.php'" tests/test_app_contrast.php | head -30; echo "=== meta ==="; grep -n "app.php\|files\|SOURCES" tests/test_app_contrast_meta.php | head -20
3: * Text contrast in app.php's four documents (WCAG 1.4.3 — 4.5:1 for normal text).
6: * app.php still draws accent-coloured TEXT with `--accent` (#6c5ce7), a colour
8: * a second token (`--accent-text: #9385f5`) in [0.4.58]; app.php — the four
11: * app.php is ONE file containing FOUR complete documents:
24: * - splits app.php into its documents on `<!DOCTYPE html>`,
39: * 1. app.php splits into exactly four documents, each with a `:root` and a
42: * 2. repo == dev == prod byte-identical for app.php (an undeployed fix cannot
67: global $pass, $fail;
73: global $skip;
378: global $pass, $fail;
404:echo "=== 1. app.php splits into four documents, each with a :root and a sheet ===\n";
406:$repo = '/data/repo/app/src/php/app.php';
407:assert_true(is_file($repo), 'app.php present in the repo');
443:echo "\n=== 3. repo == dev == prod (byte-identical app.php) ===\n";
446: 'repo' => '/data/repo/app/src/php/app.php',
447: 'dev' => '/opt/startup/dev/src/php/app.php',
448: 'prod' => '/opt/startup/prod/src/php/app.php',
453: if (!is_file($p)) { assert_true(false, "$label copy of app.php present"); $present = false; continue; }
455: assert_true(true, "$label copy of app.php present");
499: * [0.4.58] made in templates.php. app.php has four `:root` blocks, so all four
=== meta ===
16: * against healthy files — a healthy run has nothing to skip. So this suite
34: * F3 the REAL app.php (healthy). Section 6 must show 0 skips and all 12
39: * Hermetic by design: all three copies of app.php are redirected at the
47: * temp tree; the suite under test and app.php are never written to.
85:const APPSRC = '/data/repo/app/src/php/app.php';
162: '/data/repo/app/src/php/app.php' => $fixture,
163: '/opt/startup/dev/src/php/app.php' => $fixture,
164: '/opt/startup/prod/src/php/app.php' => $fixture,
196:assert_true($src !== '', 'app.php readable at ' . APPSRC);
284:echo "\n=== F3: healthy app.php — section 6 must be fully checked, never skipped ===\n";
> build · mimo-v2.6-flash-free
[0m→ [0mRead repo/app/src/php/download.php [90m[offset=40, limit=102][0m
Select another run log from the list above. Only files matching run-YYYYMMDD-HHMMSS-N.log are readable.
App log tail — prod-8001.log (last 60 lines)
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47442 Accepted [Tue Sep 29 22:34:35 2026] 127.0.0.1:47442 Closing [Tue Sep 29 22:34:35 2026] 127.0.0.1:47452 Accepted [Tue Sep 29 22:34:35 2026] 127.0.0.1:47452 Closing [Tue Sep 29 22:34:35 2026] 127.0.0.1:47454 Accepted [Tue Sep 29 22:34:35 2026] 127.0.0.1:47454 Closing [Tue Sep 29 22:34:35 2026] 127.0.0.1:47456 Accepted [Tue Sep 29 22:34:35 2026] 127.0.0.1:47456 Closing [Tue Sep 29 22:34:35 2026] 127.0.0.1:47464 Accepted [Tue Sep 29 22:34:35 2026] 127.0.0.1:47464 Closing [Tue Sep 29 22:34:35 2026] 127.0.0.1:47472 Accepted [Tue Sep 29 22:34:36 2026] 127.0.0.1:47472 Closing [Tue Sep 29 22:34:36 2026] 127.0.0.1:47484 Accepted [Tue Sep 29 22:34:36 2026] 127.0.0.1:47484 Closing [Tue Sep 29 22:35:15 2026] 127.0.0.1:44644 Accepted [Tue Sep 29 22:35:15 2026] 127.0.0.1:44644 Closing [Tue Sep 29 22:35:15 2026] 127.0.0.1:44648 Accepted [Tue Sep 29 22:35:15 2026] 127.0.0.1:44648 Closing [Tue Sep 29 22:38:29 2026] 127.0.0.1:45408 Accepted [Tue Sep 29 22:38:29 2026] 127.0.0.1:45408 Closing [Tue Sep 29 22:41:09 2026] 127.0.0.1:50328 Accepted [Tue Sep 29 22:41:09 2026] 127.0.0.1:50328 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36674 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36674 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36678 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36678 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36684 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36684 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36686 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36686 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36700 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36700 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36710 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36710 Closing [Tue Sep 29 22:47:12 2026] 127.0.0.1:36718 Accepted [Tue Sep 29 22:47:12 2026] 127.0.0.1:36718 Closing [Tue Sep 29 22:47:13 2026] 127.0.0.1:36730 Accepted [Tue Sep 29 22:47:13 2026] 127.0.0.1:36730 Closing [Tue Sep 29 22:47:13 2026] 127.0.0.1:36732 Accepted [Tue Sep 29 22:47:13 2026] 127.0.0.1:36732 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50126 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50126 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50136 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50136 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50152 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50152 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50166 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50166 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50168 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50168 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50178 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50178 Closing [Tue Sep 29 22:52:01 2026] 127.0.0.1:50190 Accepted [Tue Sep 29 22:52:01 2026] 127.0.0.1:50190 Closing [Tue Sep 29 22:53:53 2026] 127.0.0.1:41574 Accepted [Tue Sep 29 22:53:53 2026] 127.0.0.1:41574 Closing [Tue Sep 29 22:55:25 2026] 127.0.0.1:54030 Accepted [Tue Sep 29 22:55:25 2026] 127.0.0.1:54030 Closing [Tue Sep 29 22:55:25 2026] 127.0.0.1:54038 Accepted
Generated 2026-09-29 20:55:25 UTC · Gladex.de