File size: 18,234 Bytes
bcc50e3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tabby Tavern UNIFIED — one compose, one network, the whole lab</title>
<meta name="description" content="Taproot + Basecamp + Tabby Tavern merged: 15 default Docker services, Qwen3.5-9B llama.cpp, Open WebUI, SillyTavern, MCPO, code-server, RAG, n8n. One network. RTX 4070 lab.">
<style>
:root {
--navy: #070707;
--navy-2: #141413;
--blue: #1F5FA8;
--accent: #ff4c00;
--light: #EEF3F8;
--gray: #3E4C59;
--green: #1E8E5A;
--cream: #FFF7EC;
--tag: #FFD9A8;
--ink: #0B1F3A;
--line: #d5e0ec;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #f4f7fb;
color: var(--gray);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a { color: var(--blue); }
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 0.86em;
background: #e8eef5;
padding: 1px 6px;
border-radius: 4px;
}
.banner {
background: linear-gradient(165deg, #070707 0%, #141413 45%, #1a0c08 100%);
color: white;
text-align: center;
padding: 52px 24px 44px;
}
.badge-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-bottom: 16px; }
.badge {
display: inline-block; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em;
text-transform: uppercase; padding: 5px 10px; border-radius: 999px;
border: 1px solid rgba(255,76,0,0.45); color: var(--tag); background: rgba(255,76,0,0.08);
}
.banner h1 {
font-size: clamp(1.55rem, 4.4vw, 2.6rem); font-weight: 800; letter-spacing: 0.02em;
margin-bottom: 14px; line-height: 1.12;
}
.banner h1 em { color: var(--accent); font-style: normal; }
.banner .tagline { font-size: 1.08rem; color: var(--tag); max-width: 760px; margin: 0 auto 14px; }
.banner .contact { font-size: 0.9rem; color: var(--tag); opacity: 0.9; }
.banner .links { margin-top: 18px; display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.banner .links a {
color: #070707; text-decoration: none; background: var(--accent); font-weight: 800;
font-size: 0.85rem; padding: 10px 16px; border-radius: 6px;
}
.banner .links a.ghost { background: transparent; border: 1px solid rgba(255,217,168,0.5); color: var(--tag); }
.kicker-wrap { padding: 0 24px; }
.kicker {
background: white; border: 1.5px solid var(--accent); text-align: center;
padding: 14px 20px; margin: -18px auto 0; max-width: 920px; border-radius: 8px;
position: relative; z-index: 1; box-shadow: 0 8px 24px rgba(7,7,7,0.12);
}
.kicker p { font-size: 1.02rem; font-weight: 800; color: var(--navy); }
.container { max-width: 920px; margin: 0 auto; padding: 28px 24px 24px; }
.stats-bar {
display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;
background: #070707; color: white; border-radius: 10px; padding: 18px 12px; margin: 8px 0 28px;
}
@media (min-width: 700px) { .stats-bar { grid-template-columns: repeat(4, 1fr); } }
.stat { text-align: center; }
.stat .num { font-size: 1.7rem; font-weight: 800; color: var(--accent); }
.stat .label { font-size: 0.7rem; color: var(--tag); text-transform: uppercase; letter-spacing: 0.08em; }
.section { margin-bottom: 30px; }
.section h2 { font-size: 1.22rem; font-weight: 800; color: var(--ink); margin-bottom: 4px; }
.section h2::before { content: "\25B6"; color: var(--accent); margin-right: 8px; font-size: 0.8rem; }
.section hr { border: none; border-top: 1.5px solid #ff4c00; margin-bottom: 12px; opacity: 0.35; }
.section p { font-size: 0.95rem; margin-bottom: 10px; }
.section ul { list-style: none; }
.section ul li { font-size: 0.93rem; padding: 5px 0 5px 22px; position: relative; }
.section ul li::before { content: "\2022"; position: absolute; left: 4px; color: var(--accent); font-weight: bold; }
.section ul li b { color: var(--ink); }
.cap-grid { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 16px; }
@media (min-width: 640px) { .cap-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .cap-grid { grid-template-columns: 1fr 1fr 1fr; } }
.cap-card {
border: 1.5px solid var(--line); border-radius: 10px; padding: 14px; background: white; min-height: 128px;
}
.cap-card h3 { font-size: 0.76rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px; }
.cap-card p { font-size: 0.84rem; margin: 0; line-height: 1.45; }
.cap-card p b { color: var(--ink); }
.port { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.72rem; color: var(--accent); font-weight: 700; margin-bottom: 6px; }
.c1 { border-top: 3px solid var(--accent); } .c1 h3 { color: var(--accent); }
.c2 { border-top: 3px solid var(--blue); } .c2 h3 { color: var(--blue); }
.c3 { border-top: 3px solid var(--green); } .c3 h3 { color: var(--green); }
.c4 { border-top: 3px solid #6C3FA8; } .c4 h3 { color: #6C3FA8; }
.c5 { border-top: 3px solid #0E8E8E; } .c5 h3 { color: #0E8E8E; }
.c6 { border-top: 3px solid #C0392B; } .c6 h3 { color: #C0392B; }
pre.cmd {
background: #070707; color: #FFD9A8; padding: 14px 16px; border-radius: 8px;
overflow-x: auto; font-size: 0.82rem; line-height: 1.45; margin: 12px 0;
}
.note {
background: var(--cream); border: 1px solid #f0d2a8; border-radius: 8px;
padding: 12px 14px; font-size: 0.88rem; margin-top: 14px;
}
.note b { color: var(--ink); }
.quote {
font-style: italic; color: #4A5A6A; border-left: 3px solid var(--accent);
padding-left: 16px; margin: 14px 0 0; font-size: 0.92rem;
}
.pricing-header {
background: #070707; color: white; text-align: center; padding: 28px 24px; border-radius: 10px 10px 0 0;
}
.pricing-header h2 { font-size: 1.6rem; font-weight: 800; color: white; }
.pricing-header h2::before { display: none; }
.pricing-header p { color: var(--tag); font-size: 0.95rem; margin-top: 8px; }
.tiers { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 16px; }
@media (min-width: 768px) { .tiers { grid-template-columns: repeat(3, 1fr); } }
.tier-card { border: 2px solid; border-radius: 10px; padding: 20px 16px; text-align: center; background: white; }
.tier-card.blue { border-color: var(--blue); background: var(--light); }
.tier-card.accent { border-color: var(--accent); background: var(--cream); }
.tier-card.green { border-color: var(--green); background: #EAF7F0; }
.tier-card h3 { font-size: 1.0rem; font-weight: 800; color: var(--ink); margin-bottom: 6px; }
.tier-card .price { font-size: 1.55rem; font-weight: 800; color: var(--accent); }
.tier-card .price-sub { font-size: 0.78rem; margin-bottom: 8px; }
.tier-card .who { font-style: italic; font-size: 0.82rem; margin-bottom: 12px; min-height: 42px; }
.tier-card ul { list-style: none; text-align: left; }
.tier-card ul li { font-size: 0.85rem; padding: 3px 0 3px 16px; position: relative; }
.tier-card ul li::before { content: "\2022"; position: absolute; left: 2px; color: var(--ink); }
.bottom-line {
background: white; border-top: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
padding: 18px 20px; margin: 24px 0 8px; border-radius: 4px;
}
.bottom-line p { font-size: 0.93rem; } .bottom-line b { color: var(--ink); }
.footer { text-align: center; padding: 16px 24px 40px; font-size: 0.82rem; }
.footer .refs { margin-top: 8px; opacity: 0.85; }
@media (max-width: 639px) {
.banner { padding: 36px 16px 32px; }
.banner h1 { font-size: 1.32rem; letter-spacing: 0; }
.kicker p { font-size: 0.84rem; }
.container { padding: 22px 16px; }
.cap-card { min-height: 0; }
}
</style>
</head>
<body>
<div class="banner">
<div class="badge-row">
<span class="badge">v3.0 UNIFIED</span>
<span class="badge">15 default services</span>
<span class="badge">Qwen3.5-9B</span>
<span class="badge">one network</span>
</div>
<h1>THREE LABS.<br>ONE COMPOSE.<br><em>THE WHOLE BOX IS YOURS.</em></h1>
<p class="tagline">Taproot inference. Basecamp coding pack. Tabby Tavern chat, search, cards, and MCP. Hermes folded them onto one Docker network tonight. This is the stack that is actually running.</p>
<p class="contact">Tabby Tavern UNIFIED | Jeremy Panasuk | jpanasuk@gmail.com | 715.970.0204</p>
<div class="links">
<a href="https://huggingface.co/jpanasuk/tabby-tavern-stack">Model card + compose</a>
<a class="ghost" href="https://github.com/jpanasuk-netizen/tabby-tavern-stack">GitHub</a>
</div>
</div>
<div class="kicker-wrap">
<div class="kicker">
<p>STOP RENTING TWELVE SAAS SEATS. BUY THE ROOM ONCE. RUN THE LAB FOREVER.</p>
</div>
</div>
<div class="container">
<div class="stats-bar">
<div class="stat"><div class="num">15</div><div class="label">Default services live</div></div>
<div class="stat"><div class="num">1</div><div class="label">Compose + network</div></div>
<div class="stat"><div class="num">9B</div><div class="label">Qwen GGUF on CUDA</div></div>
<div class="stat"><div class="num">4070</div><div class="label">12 GB lab card</div></div>
</div>
<div class="section">
<h2>THE PAYDAY</h2>
<hr>
<p>Your team already pays for chat, search, a vector store, an IDE plugin, a workflow tool, and a second UI “just in case.” Every prompt leaves the building. Every seat is a recurring invoice. A 12 GB workstation can host the whole motion if someone will compose it, name the network, and refuse to run three GPU engines at once.</p>
<p>That is this lab. Not a slide. A running Docker project named <code>tabby-tavern</code> on <code>tabby-tavern_ai-network</code>. Primary inference is <b>Qwen3.5-9B</b> through llama.cpp CUDA. Chat, RAG, search, MCP, browser VS Code, n8n, and character cards sit on the same bridge. TabbyAPI EXL3 and Ollama stay in an <b>alternate-inference</b> profile so the 4070 does not eat itself.</p>
</div>
<div class="section">
<h2>WHAT GOT MERGED</h2>
<hr>
<ul>
<li><b>Taproot</b> — Qwen llama.cpp server, 262k context flags, flash-attn, q4 KV, OpenAI-compatible <code>/v1</code>.</li>
<li><b>Basecamp</b> — code-server, Continue, Qdrant, Chroma, n8n, Lobe, AnythingLLM, LibreChat, Mongo, Meilisearch, pgvector. Volumes kept.</li>
<li><b>Tabby Tavern</b> — SillyTavern + character cards, SearXNG JSON, MCPO FastMCP, Open WebUI as the canonical chat UI.</li>
<li><b>dockroot</b> — read-only Docker MCP, optional <code>diagnostics</code> profile. Socket stays internal.</li>
</ul>
<p>Old Taproot and qwen38-agent containers are stopped. Their YAML is folded in, not dangling as a second project.</p>
</div>
<div class="section">
<h2>THE BLOWOUT CONFIG — DEFAULT 15</h2>
<hr>
<p>Verified up on the lab box after the merge. Host URLs from WSL. Inside Docker, use the service name — never localhost.</p>
<div class="cap-grid">
<div class="cap-card c1"><div class="port">:1234</div><h3>qwen · llama.cpp CUDA</h3><p><b>Qwen3.5-9B</b> GGUF. Alias <code>Qwen3.5-9B</code>. Containers call <code>http://qwen:8080/v1</code>. This is the primary engine.</p></div>
<div class="cap-card c2"><div class="port">:3000</div><h3>Open WebUI</h3><p>Canonical chat UI. OpenAI API to Qwen. SearXNG RAG. One UI — not a second Taproot WebUI on 3001.</p></div>
<div class="cap-card c3"><div class="port">:8000</div><h3>SillyTavern + cards</h3><p>Character frontend. PNG cards ship in <code>cards/</code>. Import Seraphina. 401 on root is auth doing its job.</p></div>
<div class="cap-card c4"><div class="port">:8080</div><h3>SearXNG</h3><p>Private metasearch, JSON on. Open WebUI and MCPO search through it. No tracking SaaS.</p></div>
<div class="cap-card c5"><div class="port">:8001</div><h3>MCPO</h3><p>MCP → OpenAPI. Stack tools plus tavern connectivity. Swagger at <code>/docs</code>.</p></div>
<div class="cap-card c6"><div class="port">:8443</div><h3>code-server</h3><p>Browser VS Code. Continue + Tabby extensions. Wired to Qwen <code>/v1</code> for chat and autocomplete.</p></div>
<div class="cap-card c2"><div class="port">:6333</div><h3>Qdrant</h3><p>Vector store for RAG. Health <code>/healthz</code> 200 on the live lab.</p></div>
<div class="cap-card c3"><div class="port">:8005</div><h3>Chroma</h3><p>Lightweight embeddings DB. Basecamp volume preserved.</p></div>
<div class="cap-card c4"><div class="port">:5678</div><h3>n8n</h3><p>Workflow automation on the same network as the model. 400+ integrations, local.</p></div>
<div class="cap-card c5"><div class="port">:3210</div><h3>Lobe Chat</h3><p>Extra chat UI pointed at Qwen. Keep Open WebUI as the source of truth.</p></div>
<div class="cap-card c1"><div class="port">:3002</div><h3>AnythingLLM</h3><p>RAG workspace. Bring docs to the same box that runs the model.</p></div>
<div class="cap-card c6"><div class="port">:3080</div><h3>LibreChat + Mongo</h3><p>Multi-model frontend. Mongo on the bridge. JWT from your <code>.env</code>.</p></div>
<div class="cap-card c2"><div class="port">:7700</div><h3>Meilisearch</h3><p>Full-text search. Health 200 after merge.</p></div>
<div class="cap-card c3"><div class="port">:5432</div><h3>Postgres + pgvector</h3><p>Hermes memory backend. Healthy. Password is a placeholder in the public tree.</p></div>
<div class="cap-card c4"><div class="port">:27017</div><h3>Mongo</h3><p>LibreChat data. Named volume kept from Basecamp.</p></div>
</div>
<pre class="cmd">cd tabby-tavern
cp .env.example .env # generate real keys
docker compose up -d # 15 default services, Qwen only on GPU
# optional:
docker compose --profile alternate-inference up -d tabbyapi ollama
docker compose --profile diagnostics up -d --build dockroot</pre>
<div class="note">
<b>VRAM is the law.</b> Default is Qwen only. TabbyAPI EXL3 (:5000) and Ollama (:11435) are real, tested, and gated. Two heavy engines on a 12 GB card can block CUDA instead of erroring. Start them when Qwen is down, or when you mean to fight for VRAM.
</div>
</div>
<div class="section">
<h2>THE CONNECTION RULE</h2>
<hr>
<ul>
<li>Path is always <code>/v1</code> — <code>http://qwen:8080/v1</code> from another container.</li>
<li>Host is the <b>service name</b>, not localhost. Localhost inside a container is that container.</li>
<li>Model id is <code>Qwen3.5-9B</code>, not the word “qwen.”</li>
<li>If auth is on, send the key. Do not “fix” a 401 by changing the host.</li>
</ul>
</div>
<div class="section">
<h2>WHO SHIPS IT</h2>
<hr>
<p>Jeremy Panasuk — enterprise data / platform background: Kohl's Informatica (PowerCenter Grid/HA, AIX→commodity Cisco/IBM, DQ/MDM POCs, ~$2M software); Dawn, MF Global, BNY, Micron, NFCU, Mercedes, Smith & Nephew. Independent local-AI year from Aug 2024: this Docker lab, decode telemetry, multi-agent prototypes, Hermes on the same box.</p>
<p class="quote">"You sent one of the best that Informatica has to offer in Jeremy." — MF Global Infrastructure</p>
</div>
</div>
<div class="container" style="padding-top:0;">
<div class="pricing-header">
<h2>ENGAGEMENTS</h2>
<p>Three ways to put UNIFIED on your metal. 30 days email support after deploy.</p>
</div>
<div class="tiers">
<div class="tier-card blue">
<h3>SINGLE-GPU INSTALL</h3>
<div class="price">$12,500</div>
<div class="price-sub">one-time</div>
<div class="who">One RTX-class box. The 15-service default. Qwen on CUDA.</div>
<ul>
<li>Compose + network + .env keys that are yours</li>
<li>Open WebUI, SillyTavern cards, SearXNG, MCPO</li>
<li>code-server + Continue on Qwen</li>
<li>WSL2 / Linux bring-up</li>
<li>Half-day onboarding</li>
</ul>
</div>
<div class="tier-card accent">
<h3>PRODUCTION DEPLOYMENT</h3>
<div class="price">$25,000</div>
<div class="price-sub">one-time</div>
<div class="who">Hardened lab: profiles, backups, localhost binds, RAG volumes.</div>
<ul>
<li>Everything in Single-GPU</li>
<li>alternate-inference profile documented for EXL3/Ollama</li>
<li>dockroot diagnostics, optional</li>
<li>Reverse-proxy / bind-localhost guidance</li>
<li>Full-day runbook</li>
</ul>
</div>
<div class="tier-card green">
<h3>MANAGED PRIVATE AI</h3>
<div class="price">$3,500<span style="font-size:0.7em;">/mo</span></div>
<div class="price-sub">ongoing</div>
<div class="who">We keep UNIFIED current. You use the UIs.</div>
<ul>
<li>Everything in Production</li>
<li>Model pack and llama.cpp flag retunes</li>
<li>Quarterly VRAM / health report</li>
<li>New compose services as the lab grows</li>
<li>Priority phone / Slack, 4hr SLA</li>
</ul>
</div>
</div>
<div class="bottom-line">
<p><b>THE CLOSE.</b> This is not a multi-tenant SaaS. It is a private lab, production-shaped, that Hermes just reconciled onto one compose file. If the requirement is “one network, one Qwen endpoint, chat + RAG + IDE + MCP + character cards on hardware we own,” UNIFIED is the tree that matches the running box.</p>
</div>
</div>
<div class="footer">
<p>Jeremy Panasuk • jpanasuk@gmail.com • 715.970.0204 • <a href="https://huggingface.co/jpanasuk/tabby-tavern-stack">huggingface.co/jpanasuk/tabby-tavern-stack</a></p>
<p class="refs"><a href="https://huggingface.co/spaces/jpanasuk/dockroot-mcp">dockroot-mcp</a> · <a href="https://huggingface.co/spaces/jpanasuk/local-ai-stack-connectivity">connection rule</a> · GitHub release trail on <a href="https://github.com/jpanasuk-netizen/tabby-tavern-stack">tabby-tavern-stack</a></p>
</div>
</body>
</html>
|