basecamp / index.html
jpanasuk's picture
v1.0.3: indigo identity (skin+branding+basecamp/model), boot race fix, external-ollama auto-select, alias verification
94e4c89
Raw
History Blame Contribute Delete
22.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Basecamp β€” Portable AI Agent with Auto-Discovery</title>
<style>
:root {
--navy: #0B1F3A;
--blue: #1F5FA8;
--accent: #E8730C;
--light: #EEF3F8;
--gray: #3E4C59;
--green: #1E8E5A;
--cream: #FFF7EC;
--tag: #FFD9A8;
--purple: #6C3FA8;
--teal: #0E8E8E;
--red: #C0392B;
--dark: #0a0e1a;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background: #f5f7fa;
color: var(--gray);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* ---- BANNER ---- */
.banner {
background: linear-gradient(135deg, var(--dark) 0%, var(--navy) 50%, #152845 100%);
color: white;
text-align: center;
padding: 50px 24px 40px;
}
.banner .logo {
font-size: 2.8rem;
font-weight: 900;
letter-spacing: 2px;
margin-bottom: 8px;
background: linear-gradient(90deg, var(--accent), var(--tag));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.banner .tagline {
font-size: 1.2rem;
color: var(--tag);
max-width: 700px;
margin: 0 auto 16px;
line-height: 1.5;
}
.banner .contact {
font-size: 0.85rem;
color: var(--tag);
opacity: 0.7;
}
.banner .links {
margin-top: 18px;
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
.banner .links a {
display: inline-block;
padding: 10px 20px;
background: var(--accent);
color: white;
text-decoration: none;
border-radius: 6px;
font-weight: 700;
font-size: 0.9rem;
transition: transform 0.15s, box-shadow 0.15s;
}
.banner .links a:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(232,115,12,0.3);
}
.banner .links a.secondary {
background: transparent;
border: 1.5px solid var(--blue);
color: var(--tag);
}
/* ---- KICKER ---- */
.kicker-wrap { padding: 0 24px; }
.kicker {
background: var(--light);
border: 1.5px solid var(--blue);
text-align: center;
padding: 14px 20px;
margin: -18px auto 0;
max-width: 820px;
border-radius: 6px;
position: relative;
z-index: 1;
}
.kicker p {
font-size: 1.1rem;
font-weight: 700;
color: var(--navy);
}
.kicker code {
background: var(--navy);
color: var(--tag);
padding: 3px 8px;
border-radius: 4px;
font-size: 0.9rem;
font-family: 'Courier New', monospace;
}
/* ---- MAIN ---- */
.container {
max-width: 820px;
margin: 0 auto;
padding: 28px 24px 60px;
}
.section { margin-bottom: 32px; }
.section h2 {
font-size: 1.3rem;
font-weight: 800;
color: var(--navy);
margin-bottom: 4px;
}
.section h2::before {
content: "\25B6";
color: var(--accent);
margin-right: 8px;
font-size: 0.85rem;
}
.section hr {
border: none;
border-top: 1.5px solid var(--blue);
margin-bottom: 12px;
}
.section p {
font-size: 0.95rem;
margin-bottom: 10px;
}
.section ul {
list-style: none;
padding: 0;
}
.section ul li {
font-size: 0.93rem;
padding: 5px 0 5px 22px;
position: relative;
}
.section ul li::before {
content: "\2022";
position: absolute;
left: 4px;
top: 0;
color: var(--blue);
font-weight: bold;
}
.section ul li b { color: var(--navy); }
/* ---- CODE BLOCK ---- */
.code-block {
background: var(--dark);
color: #c8d6e5;
padding: 16px 20px;
border-radius: 6px;
font-family: 'Courier New', monospace;
font-size: 0.88rem;
margin: 12px 0;
overflow-x: auto;
border-left: 3px solid var(--accent);
white-space: pre;
line-height: 1.5;
}
.code-block .comment { color: #5a7a9a; }
.code-block .cmd { color: var(--accent); font-weight: bold; }
.code-block .flag { color: var(--teal); }
.code-block .str { color: var(--green); }
.code-block .prompt { color: var(--tag); }
/* ---- CONNECT SCREEN MOCK ---- */
.connect-mock {
background: #0d1117;
color: #c9d1d9;
border-radius: 8px;
padding: 20px 24px;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
margin: 14px 0;
border: 1px solid #1f2937;
line-height: 1.65;
}
.connect-mock .header { color: var(--accent); font-weight: bold; }
.connect-mock .svc { color: var(--blue); }
.connect-mock .svc-icon { color: var(--green); font-weight: bold; }
.connect-mock .label { color: #8b949e; }
.connect-mock .prompt { color: var(--tag); }
.connect-mock .selected { color: var(--accent); }
/* ---- DISCOVERY GRID ---- */
.disc-grid {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
margin-top: 14px;
}
@media (min-width: 640px) {
.disc-grid { grid-template-columns: 1fr 1fr; }
}
.disc-card {
background: white;
border: 1px solid #d1d9e0;
border-radius: 6px;
padding: 14px 16px;
font-size: 0.88rem;
}
.disc-card .icon {
display: inline-block;
font-weight: bold;
font-size: 0.75rem;
padding: 2px 8px;
border-radius: 3px;
margin-right: 8px;
color: white;
}
.disc-card .icon.llm { background: var(--blue); }
.disc-card .icon.exl { background: var(--purple); }
.disc-card .icon.src { background: var(--teal); }
.disc-card .icon.mcp { background: var(--accent); }
.disc-card .icon.ui { background: var(--green); }
.disc-card .icon.cht { background: var(--red); }
.disc-card b { color: var(--navy); }
.disc-card .auth {
font-size: 0.78rem;
color: var(--accent);
margin-left: 4px;
}
/* ---- ARCHITECTURE ---- */
.arch {
background: #0d1117;
color: #8b949e;
border-radius: 8px;
padding: 20px;
font-family: 'Courier New', monospace;
font-size: 0.82rem;
margin: 14px 0;
line-height: 1.5;
overflow-x: auto;
white-space: pre;
}
.arch .box { color: var(--blue); }
.arch .highlight { color: var(--accent); font-weight: bold; }
.arch .arrow { color: var(--green); }
/* ---- COMPARISON ---- */
.compare-table {
width: 100%;
border-collapse: collapse;
margin-top: 14px;
font-size: 0.9rem;
}
.compare-table th {
background: var(--navy);
color: white;
padding: 10px 14px;
text-align: left;
font-weight: 700;
}
.compare-table td {
padding: 10px 14px;
border-bottom: 1px solid #e0e4e8;
}
.compare-table tr:nth-child(even) td { background: var(--light); }
.compare-table .yes { color: var(--green); font-weight: bold; }
.compare-table .no { color: var(--red); }
/* ---- FOOTER ---- */
.footer {
text-align: center;
padding: 30px 24px;
background: var(--navy);
color: var(--tag);
font-size: 0.85rem;
}
.footer a { color: var(--tag); text-decoration: none; }
.footer a:hover { text-decoration: underline; }
.footer .links { margin-top: 10px; }
.footer .links a {
margin: 0 8px;
}
/* ---- BADGE ---- */
.badge {
display: inline-block;
padding: 3px 10px;
background: var(--green);
color: white;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 700;
margin-left: 8px;
vertical-align: middle;
}
</style>
</head>
<body>
<div class="banner">
<div class="logo">BASECAMP</div>
<div class="tagline">The first portable AI agent container that auto-discovers your local AI stack β€” Hermes Agent + Ollama in one box that finds your whole stack and just works.</div>
<div class="contact">No hardcoded URLs. No config files. Just <code style="color:var(--tag);">docker run</code>.</div>
<div class="links">
<a href="https://hub.docker.com/r/jpanasuk/basecamp">Get the image</a>
<a href="https://github.com/jpanasuk-netizen" class="secondary">GitHub</a>
</div>
</div>
<div class="kicker-wrap">
<div class="kicker">
<p>One command to connect: <code>docker run -it --rm --network your-ai-network local/basecamp</code></p>
</div>
</div>
<div class="container">
<!-- PROBLEM -->
<div class="section">
<h2>The Problem</h2>
<hr>
<p>You've got local AI services running β€” Ollama, maybe TabbyAPI or vLLM, maybe SearXNG. They work. But to actually <b>use</b> them together, you're either:</p>
<ul>
<li>Opening 5 browser tabs and copy-pasting between them</li>
<li>Hardcoding API URLs and keys into config files</li>
<li>Writing glue code every time you add a service</li>
</ul>
<p style="margin-top:8px;color:var(--accent);font-weight:600;">Nothing ties your stack together. Until now.</p>
</div>
<!-- SOLUTION -->
<div class="section">
<h2>What Basecamp Does <span class="badge">Auto-Discovery</span></h2>
<hr>
<p>Basecamp is a Docker image containing <b>Hermes Agent</b> + <b>Ollama</b>. When you run it on a Docker network, it:</p>
<ul>
<li><b>Scans</b> for AI services using DNS probes, port scanning, and Docker network inspection</li>
<li><b>Identifies</b> service types by fingerprinting HTTP responses (Ollama, TabbyAPI, vLLM, SearXNG, MCPO, and more)</li>
<li><b>Shows a connect screen</b> where you pick which services to use</li>
<li><b>Prompts for API keys</b> when a service needs auth β€” no hardcoded secrets</li>
<li><b>Generates a <code>tavern</code> CLI</b> dynamically from what it found</li>
<li><b>Drops you into Hermes Agent</b> connected to your entire stack</li>
</ul>
</div>
<!-- CONNECT SCREEN -->
<div class="section">
<h2>The Connect Screen</h2>
<hr>
<p>First run, basecamp scans your network and shows you what it found:</p>
<div class="connect-mock">
<span class="header">============================================================</span>
<span class="header"> BASECAMP β€” AI Agent + Local Inference</span>
<span class="header"> Connect Screen</span>
<span class="header">============================================================</span>
Discovered 5 service(s):
[ 0] <span class="svc-icon">LLM</span> <span class="svc">Ollama (GGUF inference)</span> [1 model(s)]
<span class="label">-> http://ollama:11434</span>
[ 1] <span class="svc-icon">EXL</span> <span class="svc">TabbyAPI / OpenAI-compatible (EXL3/EXL2)</span> [1 model(s)] [needs auth]
<span class="label">-> http://tabbyapi:5000</span>
[ 2] <span class="svc-icon">SRC</span> <span class="svc">SearXNG (private search)</span>
<span class="label">-> http://searxng:8080</span>
[ 3] <span class="svc-icon">MCP</span> <span class="svc">MCPO (MCP OpenAPI proxy)</span>
<span class="label">-> http://mcpo:8000</span>
[ 4] <span class="svc-icon">UI </span> <span class="svc">Open WebUI (LLM workspace)</span>
<span class="label">-> http://open-webui:8080</span>
<span class="prompt">PRIMARY inference engine:
1. Ollama (GGUF inference) (http://ollama:11434)
2. TabbyAPI / OpenAI-compatible (http://tabbyapi:5000)
0. Use basecamp's own Ollama
Choice [1]:</span> <span class="selected">2</span>
<span class="prompt">TabbyAPI requires authentication (bearer).
Enter API key (or press Enter to skip):</span> <span class="selected">your-key-here</span>
<span class="prompt">Save and continue? [Y/n]:</span> <span class="selected">Y</span>
</div>
<p style="font-size:0.85rem;color:#8b949e;">Subsequent runs skip this β€” config is saved to a persistent volume. Run <code>tavern rediscover</code> to re-scan.</p>
</div>
<!-- QUICK START -->
<div class="section">
<h2>Quick Start</h2>
<hr>
<div class="code-block"><span class="comment"># Pull the image (Docker Hub)</span>
<span class="cmd">docker pull</span> <span class="str">jpanasuk/basecamp:1.0.2</span>
<span class="comment"># Run against your AI network</span>
<span class="cmd">docker run</span> <span class="flag">-it --rm</span> \
<span class="flag">--network</span> <span class="str">your-ai-network</span> \
<span class="flag">--gpus all</span> \
<span class="flag">-v</span> <span class="str">basecamp-ollama:/root/.ollama</span> \
<span class="flag">-v</span> <span class="str">basecamp-hermes:/root/.hermes</span> \
<span class="str">jpanasuk/basecamp:1.0.2</span>
<span class="comment"># First run: connect screen appears
# Pick services, enter API keys if needed
# Then you're in Hermes Agent with tavern CLI</span>
<span class="prompt">tavern status</span> <span class="comment"># show connected services</span>
<span class="prompt">tavern chat "hello"</span> <span class="comment"># chat with EXL3 model (streaming)</span>
<span class="prompt">tavern search "AI news"</span> <span class="comment"># search via SearXNG</span>
<span class="prompt">tavern mcp</span> <span class="comment"># list MCP tools</span>
<span class="prompt">tavern models</span> <span class="comment"># list available models</span></div>
</div>
<!-- DISCOVERY TABLE -->
<div class="section">
<h2>What It Discovers</h2>
<hr>
<div class="disc-grid">
<div class="disc-card"><span class="icon llm">LLM</span><b>Ollama</b><br>GGUF inference<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon exl">EXL</span><b>TabbyAPI</b><br>EXL3/EXL2 inference<span class="auth">needs API key</span><br><span style="font-size:0.8rem;color:#8b949e;">Prompted during connect</span></div>
<div class="disc-card"><span class="icon llm">LLM</span><b>vLLM</b><br>High-throughput inference<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon llm">PXY</span><b>LiteLLM</b><br>Multi-provider proxy<span class="auth">needs API key</span><br><span style="font-size:0.8rem;color:#8b949e;">Prompted during connect</span></div>
<div class="disc-card"><span class="icon llm">LLM</span><b>LocalAI</b><br>OpenAI replacement<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon llm">LLM</span><b>llama.cpp</b><br>Lightweight server<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon src">SRC</span><b>SearXNG</b><br>Private metasearch<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon mcp">MCP</span><b>MCPO</b><br>MCP OpenAPI proxy<span class="auth">needs API key</span><br><span style="font-size:0.8rem;color:#8b949e;">Prompted during connect</span></div>
<div class="disc-card"><span class="icon ui">UI</span><b>Open WebUI</b><br>LLM workspace<br><span style="font-size:0.8rem;color:#8b949e;">Auto-discovered, no auth</span></div>
<div class="disc-card"><span class="icon cht">CHT</span><b>SillyTavern</b><br>Character chat<span class="auth">needs basic auth</span><br><span style="font-size:0.8rem;color:#8b949e;">Tries default, prompts if fails</span></div>
</div>
</div>
<!-- WHY DIFFERENT -->
<div class="section">
<h2>Why It's Different</h2>
<hr>
<table class="compare-table">
<tr>
<th>Feature</th>
<th>Other tools</th>
<th>Basecamp</th>
</tr>
<tr>
<td>Service discovery</td>
<td class="no">Manual config</td>
<td class="yes">Auto-discover</td>
</tr>
<tr>
<td>API keys</td>
<td class="no">Hardcoded in config</td>
<td class="yes">Prompted at connect</td>
</tr>
<tr>
<td>Works with any stack</td>
<td class="no">Tied to one app</td>
<td class="yes">Stack-agnostic</td>
</tr>
<tr>
<td>Agent included</td>
<td class="no">BYO agent</td>
<td class="yes">Hermes Agent built-in</td>
</tr>
<tr>
<td>Streaming chat</td>
<td class="no">Usually no</td>
<td class="yes">Yes, by default</td>
</tr>
<tr>
<td>Re-scan after changes</td>
<td class="no">Edit config again</td>
<td class="yes">tavern rediscover</td>
</tr>
<tr>
<td>Secrets in image</td>
<td class="no">Often yes</td>
<td class="yes">Zero hardcoded keys</td>
</tr>
</table>
</div>
<!-- ARCHITECTURE -->
<div class="section">
<h2>Architecture</h2>
<hr>
<div class="arch"><span class="highlight">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span>
<span class="highlight">β”‚ basecamp container β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ Ollama β”‚</span> <span class="box">β”‚ Hermes Agent β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ (GGUF) β”‚</span> <span class="box">β”‚ (CLI AI assistant) β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ discover.py β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - scans network for AI services β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - connect screen TUI β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - generates tavern CLI dynamically β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ tavern (auto-generated) β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - chat, search, mcp, models, status β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - streaming responses β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β”‚ - rediscover on demand β”‚</span> <span class="highlight">β”‚</span>
<span class="highlight">β”‚</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="highlight">β”‚</span>
<span class="highlight">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span>
<span class="arrow">β”‚</span> <span class="arrow">β”‚</span> <span class="arrow">β”‚</span>
<span class="arrow">β–Ό</span> <span class="arrow">β–Ό</span> <span class="arrow">β–Ό</span>
<span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span>
<span class="box">β”‚ TabbyAPI β”‚</span> <span class="box">β”‚ Ollama β”‚</span> <span class="box">β”‚ SearXNG β”‚</span>
<span class="box">β”‚ (EXL3) β”‚</span> <span class="box">β”‚ (GGUF) β”‚</span> <span class="box">β”‚ (search) β”‚</span>
<span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span>
<span class="arrow">β”‚</span> <span class="arrow">β”‚</span>
<span class="arrow">β–Ό</span> <span class="arrow">β–Ό</span>
<span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span> <span class="box">β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</span>
<span class="box">β”‚ MCPO β”‚</span> <span class="box">β”‚Open WebUIβ”‚</span>
<span class="box">β”‚ (tools) β”‚</span> <span class="box">β”‚ (UI) β”‚</span>
<span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span> <span class="box">β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</span></div>
</div>
<!-- RELATED -->
<div class="section">
<h2>Related Projects</h2>
<hr>
<ul>
<li><b>Tabby Tavern Stack</b> β€” the full 6-service local AI infrastructure (TabbyAPI, SillyTavern, Open WebUI, Ollama, SearXNG, MCPO) β†’ <a href="https://huggingface.co/jpanasuk/tabby-tavern-stack" style="color:var(--blue);">huggingface.co/jpanasuk/tabby-tavern-stack</a></li>
<li><b>Basecamp</b> β€” this project, the portable agent container β†’ <a href="https://huggingface.co/jpanasuk/basecamp" style="color:var(--blue);">huggingface.co/jpanasuk/basecamp</a></li>
</ul>
</div>
</div>
<div class="footer">
<div><b>Jeremy Panasuk</b> β€” enterprise data architect turned local AI systems engineer</div>
<div class="links">
<a href="https://huggingface.co/jpanasuk">HuggingFace</a>
<a href="https://github.com/jpanasuk-netizen">GitHub</a>
<a href="https://www.linkedin.com/in/jeremy-p-34203322">LinkedIn</a>
</div>
<div style="margin-top:8px;opacity:0.6;font-size:0.78rem;">MIT License Β· No secrets shipped Β· Built on Hermes Agent + Ollama</div>
<div style="margin-top:4px;opacity:0.6;font-size:0.78rem;">Agent by <a href="https://nousresearch.com" style="color:inherit;">Nous Research</a> β€” this box just wraps it. All props to the Hermes team. πŸ™</div>
</div>
</body>
</html>