Un 3060 și zero buget de cloud. Modele AI în spatele unui singur endpoint: cinci provideri de cloud cu nivel gratuit, cinci motoare locale care rulează pe hardware-ul tău, restul pe abonamente sau plată la token, ca ultimă soluție.
Nu teoretic. Chiar acum. aigate e un stack de Docker în spatele unui singur port de nginx. Generare de text, generare de imagini, sinteză vocală, transcriere, căutare web, automatizare de browser, object storage, execuție agentică de cod, execuție de cod izolată în sandbox pe mai multe limbaje, un gateway de email, contul tău de Telegram ca tool MCP, forecasting pe serii de timp, decizii tipizate de tip da/nu și cu variante multiple, producție audio, o trusă video cu lipsync, o coadă de job-uri asincrone și o interfață web. Pe hardware care costă mai puțin decât o singură lună de factură la API-ul OpenAI.
Tot ce e aici e compatibil OpenAI. Îndreaptă orice client spre http://localhost:4000 și merge. Cod existent, SDK-uri existente, unelte existente: toate vorbesc cu el ca și cum ar fi OpenAI. Nu e. E al tău.
Modele, Majoritatea Gratis
Cinci provideri, Groq, OpenRouter, HuggingFace, Mistral, Cohere, au nivel gratuit. Fără card la înscriere. Dar hai să fim cinstiți cu ce înseamnă “gratis”, pentru că paginile de marketing n-au de gând: gratis înseamnă limitat ca rată și plafonat, nu nelimitat. Groq îți dă 30 RPM și undeva între 1K și 14,4K cereri pe zi, în funcție de model. OpenRouter e 50 de cereri pe zi la 0 dolari, 1K pe zi dacă ai băgat vreodată 10 dolari. HuggingFace îți întinde credite de 0,10 dolari pe lună, adică un buget de evaluare, nu un nivel gratuit. Trialul de la Cohere e 1K de apeluri pe lună și se termină repede. Nivelul “Experiment” de la Mistral nu publică deloc limite exacte. Cerebras era pe lista asta. Nu mai e: la ultimul audit fiecare model de acolo răspundea “payment required”, așa că stă în stack ca provider plătit cu trei modele, nu ca nivel gratuit. Asta e cealaltă chestie cu nivelurile gratuite, se retrag, iar un stack construit pe exact unul dintre ele e un stack care se rupe în ziua în care dispare.
Deci nu, nu îți ții firma pe tokeni gratuiți. Dar îți rulezi propriile treburi pe ei, iar când unul seacă îl preia următorul. Ăsta e tot rostul.
Încă trei, claudebox, pibox-zai și pibox, sunt containere de agent. Primele două merg pe abonamente, ceea ce nu e același lucru cu gratis: alocarea tot e contorizată, doar că plătești lunar în loc de per token. Anthropic și OpenAI sunt în stack, dar sunt ultima soluție. Cinci motoare locale rulează pe hardware-ul tău: fără rețea, fără limite de rată, fără niciun cost.
Filosofia de rutare e simplă: nu plăti niciodată un token pe care îl puteai lua gratis.
LiteLLM se ocupă. Ceri groq-gpt-oss-120b. Groq te limitează. LiteLLM cade în tăcere pe cerebras-gpt-oss-120b. Cerebras e picat. Cade pe mistral-large. Mistral răspunde. Primești răspunsul. Clientul n-a aflat niciodată că s-a întâmplat ceva. Majoritatea modelelor au un lanț de fallback: întâi cloud gratuit, apoi abonament, apoi plată la token, iar lanțurile de voce, imagini, embeddinguri și cod țin și un model local pe undeva prin ele. Lanțul se reconstruiește de fiecare dată când pornești stack-ul, filtrat doar pe providerii pe care i-ai activat efectiv.
groq-gpt-oss-120b → 429 rate limited
↓ fallback
cerebras-gpt-oss-120b → 503 unavailable
↓ fallback
mistral-large → 200 ✓N-ai scris logică de retry. N-ai scris logică de fallback. Ai trimis o cerere și ai primit un răspuns.
Arhitectura
nginx :4000 ┌──────────── always on ────────────┐
├─► /claudebox/ → claudebox │ nginx, LiteLLM, PostgreSQL, Redis │
├─► /pibox-zai/ → pibox-zai │ proxq — everything else is opt-in │
├─► /pibox/ → pibox └───────────────────────────────────┘
├─► /stealthy-auto-browse/ → HAProxy → [×5]
├─► /storage/ → hybrids3
├─► /q/ → proxq → LiteLLM (async, returns job ID)
├─► /librechat/ → LibreChat (web UI, LIBRECHAT=1)
├─► /searxng/ → SearXNG (meta-search, SEARXNG=1)
├─► /telethon/ → Telethon (Telegram client, TELETHON=1)
├─► /mailbox/ → mailbox (IMAP+SMTP gateway, MAILBOX=1)
├─► /piston/ → piston (sandboxed code execution, PISTON=1)
├─► /predictalot/ → predictalot (forecasting + tabular ML, PREDICTALOT=1)
├─► /decidealot/ → decidealot (typed decisions, DECIDEALOT=1)
├─► /audiolla/ → audiolla (audio production, AUDIOLLA=1)
├─► /flickies/ → flickies (video toolkit, FLICKIES=1)
└─► / → LiteLLM (sync)
├─ Groq (free: 30 RPM, 1K-14.4K RPD per model, GROQ=1)
├─ Cerebras (paid plan, 3 models, CEREBRAS=1)
├─ OpenRouter (free: 50 RPD $0 / 1K RPD with $10+, OPENROUTER=1)
├─ HuggingFace (free: $0.10/mo credits — eval only, HUGGINGFACE=1)
├─ Mistral (free "Experiment" tier, MISTRAL=1)
├─ Cohere (trial: 1K calls/MONTH, COHERE=1)
├─ Ollama (local CPU + CUDA, OLLAMA=1 / OLLAMA_CUDA=1)
├─ Talkies (local ASR + TTS, TALKIES=1 / TALKIES_CUDA=1)
├─ sd.cpp (local image gen, SDCPP=1 / SDCPP_CUDA=1)
├─ vLLM (local text LLM + embeddings, VLLM=1 / VLLM_CUDA=1)
├─ llama.cpp (local GGUF VLM + embeddings, LLAMACPP=1 / LLAMACPP_CUDA=1)
├─ claudebox (subscription, CLAUDEBOX=1)
├─ pibox-zai (subscription, PIBOX_ZAI=1)
├─ Anthropic (pay-per-token, ANTHROPIC=1)
└─ OpenAI (pay-per-token, OPENAI=1)
MCP servers (all optional):
├─ stealthy_auto_browse — run_script: multi-step browser automation (BROWSER=1)
├─ hybrids3 — upload, download, list, delete, presign (HYBRIDS3=1)
├─ claudebox — agentic Claude Code via OAuth or API key (CLAUDEBOX=1)
├─ pibox_zai — agentic pi-coding-agent via z.ai/GLM (PIBOX_ZAI=1)
├─ pibox — agentic pi-coding-agent on your own models (PIBOX=1,
direct at /pibox/mcp/ only, not in the aggregated /mcp/)
├─ telethon — your Telegram account as a tool (TELETHON=1)
├─ mailbox — IMAP+SMTP across N accounts (MAILBOX=1)
├─ predictalot — time-series forecasting (PREDICTALOT=1)
├─ decidealot — typed choice / score / yes-no decisions (DECIDEALOT=1)
├─ audiolla — audio production, MIR, mastering, MIDI (AUDIOLLA=1)
├─ flickies — lipsync, face restore, ffmpeg ops (FLICKIES=1)
└─ mcp_tools — generate_image + generate_tts + search_web
+ execute_code (auto-enabled)Totul e opt-in. Comuți flag-uri în .env. N-ai cheie de Anthropic? N-o seta. Ai doar CPU? Sari peste flag-urile de CUDA. Stack-ul se adaptează la ce ai și își reconstruiește configul în consecință. Nucleul mereu pornit e format din cinci lucruri: nginx, LiteLLM, PostgreSQL, Redis, proxq. Restul e flag.
Unelte Pe Care Le Poate Chema Orice Model
Asta e ce face din aigate mai mult decât un proxy cu lanț de fallback. Un morman întreg de servere MCP, zeci de unelte. Orice model cu function calling poate să le cheme singur pe oricare. Tu dai promptul. Modelul decide de ce unelte are nevoie. Tu primești rezultate.
Fluxul concret: trimiți un prompt la Groq, gratis, rapid. Modelul decide că trebuie să documenteze ceva. Cheamă search_web, SearXNG interoghează Google, Bing și DuckDuckGo simultan și întoarce rezultate. Modelul are nevoie de mai multe detalii pe un rezultat. Cheamă tool-ul de browser. O instanță de Camoufox deschide un Firefox adevărat, mișcă un cursor de mouse adevărat, încarcă pagina, extrage conținutul. Modelul citește, decide să salveze rezultatul. Cheamă tool-ul de storage. hybrids3 scrie fișierul și întoarce un URL public. Modelul decide că îi trebuie o imagine pentru raport. Cheamă generate_image. stable-diffusion.cpp o randează local, o urcă în storage, întoarce un URL. Modelul îți dă un răspuns structurat cu linkuri către tot ce a produs. Un singur apel de API. Zero tokeni plătiți. Clientul a văzut o cerere și un răspuns.
stealthy_auto_browse
Cinci replici de Camoufox în spatele unui HAProxy. Camoufox e un Firefox întărit: input real de mouse și tastatură la nivel de sistem prin PyAutoGUI, zero expunere CDP, amprente persistente per sesiune. Trece de Cloudflare. Trece de CreepJS. Trece de BrowserScan. Trece de Pixelscan. Nu “trece în mare parte”, chiar trece, pentru că nu e detectabil ca automatizare în felurile în care verifică sistemele alea.
O singură unealtă: run_script. Scripturi în mai mulți pași: navighează, dă click, tastează, extrage, face screenshot, derulează, așteaptă elemente, execută JavaScript. Modelul scrie scriptul, browserul îl execută, tu primești înapoi date structurate din pagina vie.
hybrids3
Object storage compatibil S3 care rulează local. Bucket-ul uploads e public-read: fișierele sunt accesibile direct prin URL, fără semnătură. URL-uri PUT presemnate pentru upload direct. Expirare automată. Unelte pentru put, get, list, delete, info, presign și listare de bucket-uri.
Asta rezolvă o problemă anume din fluxurile agentice. Când un model produce ceva mare, un set de date scrapuit, o imagine generată, un raport randat, nu îl îndeși în fereastra de context. Îl pui în storage, iei un URL, pasezi URL-ul. Pasul următor îl poate lua de acolo. Tu îl poți lua de acolo. Contextul rămâne curat.
Trei Agenți de Cod: claudebox, pibox-zai și pibox
Trei agenți de cod agentici diferiți, nu trei copii ale aceluiași. claudebox rulează Claude Code pe abonamentul sau cheia ta de API. pibox-zai rulează pi-coding-agent îndreptat spre z.ai pentru modelele GLM (glm-5.3 și glm-5.3-flash). pibox e același agent îndreptat înapoi spre LiteLLM-ul stack-ului ăstuia, deci scrie cod pe orice ai activat deja: numești modelele cu PIBOX_MODELS, alegi unul implicit cu PIBOX_DEFAULT_MODEL. Două avertismente acolo, și mușcă amândouă: un model pe care îl treci în listă chiar trebuie să suporte tool calling, altfel agentul n-are ce să conducă, și nu îi da unui agent propriul model înapoi în listă decât dacă îți place recursivitatea. Toți trei primesc acces complet la shell, workspace-uri persistente, I/O pe fișiere, tool use, și toți trei expun un API REST, un endpoint compatibil OpenAI și un server MCP. Pe toți trei, chat completions-urile cu streaming pot să care și evenimentele brute ale agentului: trimiți "stream_options": {"include_aicodebox_events": true} și primești evenimente SSE cu numele aicodebox.native amestecate printre chunk-urile OpenAI obișnuite, ca să vezi agentul cum muncește, nu doar să stai ca prostul până scuipă răspunsul.
Folosești Groq pentru viteză. Groq dă peste ceva care cere muncă serioasă de cod. Groq cheamă tool-ul claudebox. Claude Code preia, primește un shell, scrie cod, rulează teste, întoarce rezultate structurate. Înapoi în contextul lui Groq. Orchestrarea se întâmplă în bucla de function calling a modelului, iar tu n-ai scris nimic din logica aia.
piston: Execuție de Cod în Sandbox
LLM-urile sunt catastrofal de proaste la aritmetică, la hashuri și la parsat. Deci nu le pune să ghicească. execute_code rulează cod adevărat într-un sandbox nsjail, cu propriul user namespace, chroot, filtru seccomp, limite de cgroup și fără rețea, și îi întinde modelului un rezultat determinist.
Instalarea implicită e Python plus Node. Adaugi Bash, Deno, Go, Rust, TypeScript sau alte vreo 40 de limbaje prin PISTON_LANGUAGES și reconstruiești. Modelului îi trebuie un SHA-256, o diferență de date, un regex aplicat pe 10K de rânduri? Scrie cod, piston îl rulează în carceră, iar cifra vine înapoi corectă în loc de halucinată.
mcp_tools
generate_image, generate_tts, search_web și execute_code. Se activează automat când backendul potrivit e pornit, cu o capcană: PISTON=1 singur nu pornește serverul ăsta de unelte, deci execute_code apare abia când ai pornit și un backend de imagini, TTS sau căutare. Toate întorc JSON structurat, iar fișierele generate se urcă automat în hybrids3 și primești înapoi URL-uri publice, care trăiesc până le mătură TTL-ul bucket-ului de uploads, implicit o săptămână. Fără bucăți de base64 în fereastra de context.
Generarea de imagini merge întâi local: stable-diffusion.cpp cu flux-schnell pe CUDA sau sd-turbo pe CPU, iar un model găzduit, gen DALL-E, doar când n-ai nimic local activat. Un default găzduit îți bușește fiecare apel în ziua în care providerul scoate modelul, și exact asta a făcut HuggingFace cu FLUX. TTS-ul se duce pe Kokoro (CPU plus CUDA), Qwen3-TTS cu clonare de voce, design de voce și control al emoției (CUDA), Chatterbox Turbo (CUDA), sau OpenAI TTS. Căutarea web interoghează SearXNG. Execuția de cod se duce la piston. Uneltele descoperă dinamic din LiteLLM ce modele sunt disponibile, deci reflectă mereu ce rulează de fapt.
telethon
Contul tău real de Telegram, ca unealtă. Nu Bot API, ci MTProto complet, exact accesul pe care îl ai de pe telefon. Citește mesaje, trimite mesaje, listează conversații, administrează grupuri, redirecționează conținut, editează, șterge, marchează ca citit, trimite fișiere. Modelul decide când. Agentul se poartă ca tine.
Un model Groq de nivel gratuit care caută pe web, scrapuiește o pagină, generează o imagine și trimite rezultatul în Mesajele tale salvate: zero tokeni plătiți, o conversație, mai multe apeluri de unelte. Sau un cron care îți rezumă ultimele 24 de ore din grupul de muncă și ți-l dă pe privat în fiecare dimineață. Contul tău, programabil.
Pus la treabă de telethon-plus. Comuți TELETHON=1, setezi TELETHON_API_ID / TELETHON_API_HASH / TELETHON_SESSION în .env. Stringul de sesiune înseamnă acces complet la cont, deci tratează-l ca parola care de fapt și este.
mailbox: Emailul Ca Unealtă
IMAP plus SMTP fără stare, pe N conturi, dintr-un singur config YAML. Inbox unificat, listare, căutare, citire, marcare ca citit și ștergere per cont, trimitere pe SMTP. API REST plus un set plat de unelte MCP unde un parametru mailbox alege contul.
Ceea ce înseamnă că un model îți poate citi inboxul, poate găsi factura, îi poate extrage totalul și poate răspunde, fără să scrii tu o linie de manevrat IMAP. MAILBOX=1, îndrepți MAILBOX_CONFIG spre YAML-ul tău, gata.
predictalot: Forecasting și ML Tabular
Cinci modele fundaționale zero-shot pentru serii de timp, chronos-2, timesfm-2.5, moirai-2, toto-1, sundial-base-128m, pe șase tipuri de forecast (univariat, multivariat, covariate din trecut, covariate din viitor, covariate din trecut și din viitor deodată, și sample-uri, fiecare cu un ansamblu ponderat deasupra) la /v1/timeseries/<type>/….
Apoi o familie soră întreagă la /v1/tabular/*: nouă backenduri supervizate (lightgbm, xgboost, hist-gbt, random-forest, logistic, mlp, svm-rbf, knn, naive-bayes) și trei meta-learneri (calibrated, stacking, diversified). 27 de unelte MCP, 26 pentru modelele fundaționale plus unload_models; partea tabulară e doar pe REST. CPU sau CUDA.
Zero-shot înseamnă fără rulare de antrenare. Îi întinzi o serie, îți dă forecastul. Atât.
decidealot: Decizii Tipizate, Fără Eseuri
Răspunsul offline la Jev-ul de la TypeSafe. Trei modele locale de decizie, Laya, Von și CLM, toate pornite din oficiu, în spatele API-ului System One: trimiți un state și câteva întrebări cu nume, fiecare fie choice, fie score, fie un da/nu noul, și primești înapoi răspunsuri tipizate, cu probabilități reale pe ele. Nicio proză de parsat, niciun „Sigur! Uite JSON-ul”, iar chestia pe care o judeci nu pleacă niciodată de pe mașina ta. Paisprezece selectoare de model locale, zece dacă oprești CLM, un singur provider local încărcat per container din oficiu, eliberat după zece minute de stat degeaba. Bagi un DECIDEALOT_TYPESAFE_API_KEY în .env și îți servește și Jev-ul adevărat, cel găzduit, sub ce nume îți listează contul de TypeSafe, și asta e singura rută pe care state-ul chiar pleacă de pe mașina ta, direct la API-ul TypeSafe. POST /decidealot/v1/systemone pentru REST, POST /decidealot/v1/systemone/batch pentru o grămadă de requesturi independente dintr-o foaie, plus patru unelte MCP, system_one, system_one_batch, list_models și unload_models, la /decidealot/mcp, care intră și în /mcp/-ul agregat.
CPU la /decidealot/, CUDA la /decidealot-cuda/, unul lângă altul dacă le vrei pe amândouă, cu un singur director de modele de ~5.3 GB comun, ca greutățile să ajungă pe disc o singură dată. DECIDEALOT=1 / DECIDEALOT_CUDA=1. CLM e pornit din oficiu acum, iar oricare dintre cele două flaguri de decidealot îi pornește și llama.cpp CUDA, deci ai nevoie de un GPU NVIDIA. Ai doar CPU? Pune DECIDEALOT_CLM_ENABLED=false înainte să-l pornești. E un cap de proiecție de 75 MB care nu știe să citească singur nici măcar un cuvânt, așa că întreabă embeddings-urile Qwen3 8B ale stack-ului, de pe llama.cpp CUDA, prin rețeaua internă, iar chestia pe care o judeci tot nu pleacă de pe mașina ta. decidealot decide, codul tău execută. Toată povestea e în postarea despre decidealot.
audiolla: Producție Audio
Ăsta e absurd ca întindere. Separare de stem-uri (Demucs / UVR). Restaurare: de-reverb, de-echo, de-noise. Masterizare prin matchering și lanțuri pedalboard, cu presetări făcute de mână ca master-for-spotify, podcast-cleanup, vocal-cleanup. Analiză MIR: BPM, tonalitate, LUFS, bătăi, onset-uri, melodie, acorduri, segmente. Transformări DSP prin sox și ffmpeg. Normalizare de loudness. Îmbunătățire de voce (DeepFilterNet). VAD (silero). Diarizare (pyannote). Embeddinguri CLAP și clasificare audio zero-shot. Etichetare AudioSet. Audio→MIDI prin basic-pitch, plus compunere / inspectare / transformare / randare de MIDI prin fluidsynth.
Plus generare text-to-audio, stable-audio-open, musicgen, riffusion, audioldm2, doar pe CUDA.
Job-uri asincrone și webhook-uri peste tot. Contractul de la v1.0 încolo e strict: body JSON pe fiecare endpoint audio, octeți bruți doar la PUT /v1/files/{path}, și output_path xor output_url obligatoriu pe orice produce audio. Fișierele urcate și rezultatele se șterg la 24 de ore după ultima scriere, așa că descarcă ce vrei să păstrezi, sau pune AUDIOLLA_FILES_TTL=0 și rămân acolo pentru totdeauna.
flickies: Video și Lipsync
Lipsync prin LatentSync 1.5 (ByteDance, Apache-2.0, ~8 GB VRAM, implicit pe CUDA) și Wav2Lip / Wav2Lip-GAN (LRS2, necomercial, cu acces restricționat). Restaurare de fețe prin GFPGAN v1.4. Operații ffmpeg: trim, concat, transcodare inclusiv schimbări de gif/fps/codec, scalare, mux de audio, extragere de audio, grilă de thumbnail-uri. Info ffprobe. Job-uri asincrone și webhook-uri. 11 unelte MCP, același contract cu body JSON și output_path xor output_url ca la audiolla.
GFPGAN și LatentSync 1.5 merg doar pe CUDA. Imaginea de CPU tot face operații ffmpeg și un Wav2Lip foarte lent.
Inferență Locală: Mai Lentă, Dar A Ta
Cinci motoare locale. Fiecare dintre ele are mod de CPU.
Asta e partea de “calculatorul săracului”. Laptopul tău vechi cu 16GB de RAM poate să facă generare de text, generare de imagini, transcriere și sinteză vocală. Fără cheie de API. Fără rețea. Fără limită de rată. Fără factură. E mai lent decât cloudul. Uneori mult mai lent. Dar e al tău, e privat și merge offline.
Ollama: llama3.2:3b, qwen3:4b, smollm2:1.7b, qwen2.5-coder:1.5b, qwen2.5-coder:3b, phi4-mini (raționament, context de 128K), gemma4:e2b (vedere), gemma3:4b (vedere), nuextract-v1.5 (extragere de text structurat în JSON), dolphin-phi, plus două modele de embedding pentru RAG. Celui mai mic îi trebuie 1GB de RAM. OLLAMA_CUDA=1 adaugă setul greu: qwen3:8b, qwen3:30b-a3b (MoE), qwen2.5vl:7b (vedere), gemma4:e4b (vedere), deepseek-coder-v2:16b (MoE, context de 160K), deepseek-r1:8b și deepseek-r1:14b (raționament), phi4-reasoning:plus (raționament), qwen3-abliterated:16b (necenzurat), gemma4-abliterated:e4b (vedere necenzurată), qwen2.5-coder:7b, llama3.1:8b. Flash attention, cache KV cuantizat, storage de modele partajat cu serviciul de CPU, deci fără descărcări duble.
talkies: serviciul unificat de ASR plus TTS și înlocuitorul a ceea ce era Speaches în stack-ul ăsta. Pe CPU vine acum cu 13 modele: whisper-large-v3 și -turbo, canary-180m-flash, nemotron-3.5-asr-0.6b, patru variante Sherpa-ONNX Zipformer, Vosk small English și două recunoscătoare de foneme care îți dau un flux brut de foneme IPA cu timestamp per fonem în loc de cuvinte; Kokoro pentru TTS. Pe CUDA se ajunge la 22, adăugând parakeet-tdt-0.6b-v3, canary-1b-flash, canary-qwen-2.5b, Chatterbox Turbo și familia Qwen3-TTS, 0.6B și 1.7B, cu clonare de voce, design de voce și control al emoției prin câmpul instructions. Chatterbox e singurul dintre ele care își marchează ieșirea: watermarkul neural PerTh de la ResembleAI, pornit implicit, iar TALKIES_CHATTERBOX_WATERMARK=false îl oprește pentru audio curat, în timp ce Kokoro și Qwen3-TTS nu încorporează niciodată nimic. Endpointuri compatibile OpenAI, deci apelurile existente de Whisper merg nemodificate. TALKIES=1 / TALKIES_CUDA=1.
Adăugările Sherpa și Vosk aterizează ca zece aliasuri noi de transcriere: cele cinci modele sub local-talkies-, apoi aceleași cinci din nou sub local-talkies-cuda-. Build-urile int8 sunt cuantizate (mai mici și mai rapide, cu acuratețe puțin mai mică); left-64 față de left-128 setează fereastra de context stâng a atenției. Toate cinci fac ASR live nativ peste WebSocket-ul de streaming, pe lângă obișnuitul POST /v1/audio/transcriptions, iar imaginea de CUDA instalează un wheel Sherpa CUDA din upstream verificat prin hash, ca cele patru Sherpa să folosească efectiv execution providerul lui de CUDA în loc să cadă în tăcere pe CPU într-un container cu GPU. Vosk decodează oricum pe CPU.
O subtilitate de fallback care merită furată: șase lanțuri din fallbacks.json listau înainte un model talkies frate pe prima poziție, whisper-large-v3 → whisper-large-v3-turbo, plus echivalentele pentru varianta de CUDA și pentru ambele intrări de TTS. Așa ceva nu poate funcționa niciodată. Fiecare container talkies servește un singur model odată și îl evacuează pe cel anterior la admitere, așa că un salt către un frate nu găsește capacitate liberă, ci forțează o schimbare de model, iar sub retry-uri asta e doar evacuare în buclă. Lanțurile se duc acum întâi spre celălalt container talkies, apoi afară spre providerii din cloud. Salturile CPU↔CUDA rămân, pentru că alea chiar sunt procese independente.
stable-diffusion.cpp: generare locală de imagini. Pe CPU merge sd-turbo și sdxl-turbo din start. SDCPP_CUDA=1 pentru accelerare hardware și setul complet de modele: sd-turbo, sdxl-turbo, sdxl-lightning, flux-schnell, juggernaut-xi. Un sidecar de pull trage modelele o singură dată, înainte să pornească serverul prima oară, și le cachează local. Endpointul compatibil OpenAI /images/generations înseamnă că din codul existent merge ca atare.
vLLM: LLM-uri locale de text plus embeddinguri. qwen3-0.6b pentru generare, pe ambele. Embeddingurile sunt nomic-embed-v2 pe CUDA, iar pe CPU primești bge-m3 (multilingv) și nomic-embed-v1.5, pentru că Nomic v2 e un model MoE, buildul de CPU al vLLM n-are kerneluri MoE, iar vechiul alias de CPU crăpa la absolut fiecare request. Ai indexat ceva cu el? Refă embeddingurile, vectorii de la modele diferite nu se amestecă. VLLM=1 / VLLM_CUDA=1.
llama.cpp: un wrapper GGUF care acum vine cu două modele. Surya OCR 2 se ocupă de înțelegerea documentelor, pe CPU și pe CUDA. Pe CUDA mai primești și local-llamacpp-cuda-qwen3-8b, Qwen3 8B în Q8_0, doar pentru embeddings: 4096 de dimensiuni, pooling pe ultimul token, normalizare L2, și e encoderul prin care gândește CLM-ul din decidealot. Nu-i trimite chat, că de chat nu se ocupă. Fiecare descărcare e fixată pe o revizie exactă și pe un SHA-256, iar profilele CPU și CUDA au fiecare sidecar-ul lor de pull, care trage doar fișierele lui, deci o mașină doar cu CPU nu descarcă niciodată cei 8.7 GB de Qwen, decât dacă ai decidealot pornit pe ea cu CLM lăsat pe default, pentru că ăla pornește oricum profilul CUDA.LLAMACPP=1 / LLAMACPP_CUDA=1.
Modelele locale stau în lanțurile de fallback de voce, imagini, embeddinguri și cod. Cade cloudul acolo? Preia localul. Majoritatea lanțurilor de chat generale se termină în cloud, așa că pentru alea țintești localul direct: "model": "local-ollama-cpu-llama3.2-3b". Zero rețea. Zero cost. Mai lent, dar răspunde.
Un Singur GPU, Tot
Uite problema de inginerie: ai un singur GPU. Ollama vrea VRAM pentru LLM. sd.cpp vrea VRAM pentru generare de imagini. talkies vrea VRAM pentru transcriere și voce. audiolla îl vrea pentru separare de stem-uri. flickies vrea vreo 8GB din el pentru LatentSync. Le încarci pe toate și dai în OOM.
Managerul de resurse rezolvă asta automat. Un callback de LiteLLM impune excludere mutuală per hardware: un singur job CUDA odată. Lock-ul stă în Redis, deci ține peste toți workerii LiteLLM, în loc ca fiecare worker să se bazeze pe semaforul lui privat și patru dintre ei să se înghesuie pe același GPU. Pică Redis? Requestul pică și el. Nu se strecoară nimic fără lock. Când vine o cerere de generare de imagini în timp ce e încărcat un LLM, managerul de resurse ia lock-ul, descarcă LLM-ul, apoi lasă generarea de imagini să meargă mai departe. Când vine după aia o cerere de TTS, descarcă întâi generatorul de imagini. Aceeași logică și pe CPU.
Fiecare serviciu are propriul API de descărcare, iar managerul de resurse le știe pe toate: Ollama ia keep_alive: 0, sd.cpp are POST /sdcpp/v1/unload, talkies / vllm-cuda / llamacpp-cuda iau DELETE /api/ps/{model_id} per model sau POST /unload ca să omoare orice e încărcat, audiolla are POST /v1/unload ca să evacueze în bloc orice motor încărcat, iar flickies n-are niciun apel în bloc, așa că managerul îi listează motoarele cu GET /v1/engines și le omoară pe cele încărcate unul câte unul cu DELETE /v1/engines/{slug}. predictalot și decidealot iau amândouă POST /v1/models/unload și răspund cu 409 când sunt în mijlocul unui request, caz în care managerul notează asta în log, trece mai departe și le lasă propriul timer de inactivitate să elibereze modelul mai târziu.
Există și endpointuri pentru operator, când vrei să faci curat manual: POST /v1/unload/cuda se împrăștie concurent spre ollama-cuda, sdcpp-cuda, talkies-cuda, vllm-cuda, llamacpp-cuda, audiolla-cuda, flickies-cuda, predictalot-cuda și decidealot-cuda. POST /v1/unload/cpu face același lucru pentru aceleași nouă pe partea de CPU. POST /v1/unload le rulează pe amândouă în ordine și îți dă înapoi un raport pe servicii cu ce a fost evacuat efectiv, iar un serviciu ocupat cu un request raportează "status": "busy" și își păstrează modelul. Uneltele de inferență din predictalot, apelate prin /mcp/-ul agregat, iau același lock ca tot restul, iar decidealot îl ia acum singur pentru Laya și Von pe orice rută: REST direct, MCP și fiecare item dintr-un batch. Gaura care rămâne: audiolla și flickies nu iau deloc lock-ul, iar predictalot, dacă îi trimiți requesturi direct pe ruta lui, sare și el peste lock. Niciunul dintre ăștia nu evacuează nimic când intră, iar decidealot dă afară doar encoderul lui de llama.cpp înainte să încarce ceva pe CUDA, deci pe un GPU mic un cold start acolo tot poate da OOM lângă un model Ollama încărcat.
Tu nu administrezi nimic din asta. Trimiți cereri. Platforma jonglează cu VRAM-ul automat. Singurul cost e latența: prima cerere de după o schimbare include timpul de încărcare a modelului. După aia e rapid, până când timeoutul de inactivitate descarcă modelul ca să elibereze memorie pentru următorul lucru.
Căutare Web
SearXNG la /searxng/. Meta-căutare self-hosted: interoghează Google, Bing, DuckDuckGo și Wikipedia simultan. Fără cheie de API. Rulează complet local.
Repară-ți secret_key dacă ai pus asta în funcțiune devreme. Cea de la SearXNG era hardcodată în searxng/settings.yml, care era în repo. Acum se generează per instalare și se citește din SEARXNG_SECRET_KEY în .env: setează-o cu openssl rand -hex 32 când comuți SEARXNG=1, altfel SearXNG pornește pe placeholderul din upstream. Fișierul settings.yml din repo a dispărut de tot; setările se randează dintr-o intrare searxng_config din blocul configs:, la fel cum proxq_config lua deja ${REDIS_PASSWORD}. Expunerea era limitată, /searxng/ stă în spatele autentificării de admin din nginx, containerul nu publică porturi pe host, iar limiter: false însemna că cheia nu păzea limitele de rată, dar valoarea veche tot stă în istoricul de git, și partea aia nu se mai des-întâmplă.
Unealta MCP search_web înseamnă că orice model cu function calling poate căuta singur pe web. Modelul decide că trebuie să verifice ceva, cheamă unealta, primește rezultate, merge mai departe cu raționamentul. N-ai construit o integrare de căutare. Ai comutat SEARXNG=1.
LibreChat: Ăla de Zi cu Zi
Tot ce e mai sus merge din API. Dar pentru uz zilnic ai LibreChat la /librechat/.
Toate modelele în dropdown. Toate uneltele MCP legate. Alegi un model, începi să vorbești. Modelul tot poate să cheme singur browserul, storage-ul, agenții de cod, generarea de imagini, TTS-ul și căutarea web: tot ce e disponibil din API e disponibil și în interfață. Istoricul conversațiilor stă pe MongoDB. Upload de fișiere. Streaming pe WebSocket.
Primul utilizator înregistrat devine admin. Setezi LIBRECHAT_ALLOW_REGISTRATION=false după aia și rămâi singurul dinăuntru.
Îl activezi: LIBRECHAT=1 în .env.
Coadă Asincronă
Cererile lungi de inferență dau timeout. Lovești /q/ în loc de / și cererea intră într-o coadă pe Redis. Primești instant un ID de job. Inferența propriu-zisă rulează în fundal. Interoghezi statusul, iei rezultatul când e gata.
# submit — returns 202 immediately
curl http://localhost:4000/q/v1/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "cerebras-gpt-oss-120b", "messages": [{"role":"user","content":"write a novel"}]}'
# → {"jobId": "550e8400-e29b-41d4-a716-446655440000"}
# check status
curl http://localhost:4000/q/__jobs/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
# get the result
curl http://localhost:4000/q/__jobs/550e8400-e29b-41d4-a716-446655440000/content \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"Concurență, retenție, timeouturi, retry-uri și cache de răspunsuri, toate configurabile. Doar căile de API OpenAI intră în coadă; verificările de sănătate și cererile de admin trec direct. LiteLLM mai are și propriul cache de răspunsuri peste asta, tot în Redis: trimiți exact același request de două ori în 10 minute și al doilea vine direct din cache, fără să atingă modelul. Bun pentru factură, de căcat dacă tot rulezi același prompt sperând la alt răspuns.
Vine cu Propriul Lui Agent Skill
Repo-ul cară .agents/skills/aigate/, un agent skill publicat pe ClawHub care învață un agent de cod cum să conducă stack-ul. Deci în loc să îi explici propria ta infrastructură unui asistent în fiecare sesiune, instalezi skill-ul și el știe deja endpointurile, flag-urile și contractele uneltelor.
Securitate
Serviciile interne, PostgreSQL, MongoDB, Redis, clusterul de browsere, backendul de storage, n-au porturi pe host. Stau pe rețele Docker izolate. Nimic nu ajunge la ele din afara stack-ului. Singura suprafață expusă e nginx pe portul 4000, iar aia cere autentificare cu bearer token. Redis nici măcar nu mai are user default: proxq și LiteLLM se loghează fiecare cu userul lui de ACL, care poate atinge doar cheile lui. Ai ceva de-al tău care vorbește cu Redis-ul din aigate doar cu REDIS_PASSWORD? Acum îi trebuie și username-ul proxq, iar în parolă n-ai voie cu spații.
Containerele de aplicație rulează cu no-new-privileges:true. Două excepții, ambele intenționate și ambele documentate în fișierul de compose: piston are nevoie de privileged: true pentru că nsjail trebuie să construiască user namespace-uri și chroot-uri la fiecare execuție, izolarea propriu-zisă stă înăuntrul subprocesului nsjail, iar containerul privilegiat e exact ce îi trebuie lui nsjail ca să ridice carcera aia. tailscale are nevoie de NET_ADMIN și NET_RAW pentru dispozitivul lui tun din kernel. Tot restul renunță la privilegii. make run validează că orice cale de fișier din .env chiar există înainte să pornească, deci fără volume mount-uri rupte în tăcere.
Îl vrei accesibil public fără să deschizi un port în firewall? CLOUDFLARED=1, adică Cloudflare Tunnel. Protecție DDoS, terminare TLS, fără porturi deschise, fără IP de scanat. Tunel rapid pentru un URL aleatoriu *.trycloudflare.com, sau tunel cu nume pentru un domeniu fix.
Nu îl vrei public deloc, dar tot vrei să ajungi la el de pe laptop, de pe telefon sau de pe altă mașină? TAILSCALE=1 cu TS_AUTHKEY=tskey-auth-... și un TS_HOSTNAME. Un sidecar de Tailscale intră în tailnetul tău și rulează tailscale serve în mod de forwarding TCP L4 direct spre nginx:4000: fără potrivire pe Host header, fără configurare de FQDN pe partea de tailscale, fără auto-certificat HTTPS (terminarea TLS, dacă o vrei, stă în nginx). nginx primește octeții cererii originale ca atare și îi rutează prin logica lui existentă de vhost și cale. Acces prin http://<TS_HOSTNAME>.<tailnet>.ts.net, iar HTTP simplu e în regulă aici, pentru că WireGuard deja criptează fiecare octet din tailnet. Merge cu Tailscale găzduit sau cu Headscale self-hosted (folosești TS_EXTRA_ARGS=--login-server=...). Starea persistă în .data/tailscale/, deci repornirile refolosesc loginul existent. Combină-l cu autentificarea pe bearer token și ai două straturi complet independente de control al accesului.
Ăsta e traficul care intră. Traficul care iese e altă treabă, pe care acum o poți porni: egress prin tailnet pentru agenții de cod, ca să poată claudebox, pibox-zai și pibox să ajungă la mașini din tailnetul tău, nu doar la internetul public. Vine ca un overlay de compose (docker-compose.tailscale.yml) și mai cere două valori, TS_MAGICDNS_SUFFIX (sufixul MagicDNS al tailnetului tău, direct din tailscale status) și TS_FALLBACK_DNS (implicit 1.1.1.1). A doua există pentru că DNS-ul ajunge împărțit: MagicDNS răspunde pentru numele din tailnet și dă SERVFAIL pentru tot restul, deci numelor publice le trebuie un resolver pe care să cadă mai departe.
Sute de teste. Verificări de sănătate, rutare, autentificare, validare de unelte MCP, CRUD pe storage, automatizare de browser, rulări agentice de cod, ciclul de viață al job-urilor asincrone, dus-întors de TTS/STT local, verificarea managerului de resurse CUDA, generare locală de imagini, tool calling cap-coadă de la LLM la MCP, căutare pe SearXNG, dus-întors MTProto pe Telethon cu un cont real. Plus securitate: izolare între tokenuri, încercări de deturnare de sesiune, HTTP request smuggling (CL.TE/TE.CL), h2c smuggling, SSRF prin browser și prin MCP spre servicii interne, extragere de chei prin prompt injection, path traversal, abuz de presign pe S3, XSS stocat, injecție de nume de model, injecție de headere, izolarea socketului de Docker. Asta nu e suita de teste a unui proiect de hobby. Asta e paranoia ca funcționalitate.
Instalare
git clone https://github.com/psyb0t/aigate && cd aigate
make bootstrap # seeds .env; then edit it: add keys, flip flags
make run-bgFiecare variabilă e documentată în .env.example. Activează ce ai, ignoră ce n-ai. Nici nu mai trebuie să copiezi fișierul ăla de mână: make bootstrap îți seamănă .env, iar orice alt target îl seamănă întâi, deci make run pe un checkout proaspăt pur și simplu merge.
Când vrei să schimbi ceva la stack-ul în sine, nu doar un flag, pui în docker-compose.override.yml. Asta e cusătura suportată acum: Makefile-ul asamblează COMPOSE_FILE din fișierul de bază, overlay-ul de tailscale când l-ai activat, și overrideul tău la final. Editezi direct fișierul de compose de bază și următorul update îți mănâncă modificările; overrideul supraviețuiește.
Dacă resursele contează, și pe un calculator normal chiar contează, fiecare serviciu are o limită fixă de memorie și CPU, defaultul din fișierul compose, și oricare o suprascrii în .env (TALKIES_CUDA_MEM_LIMIT=16g). Nimic nu se scalează după RAM-ul tău, pentru că un model are nevoie de aceeași memorie pe orice mașină, iar o limită sub cât îi trebuie ca să se încarce doar îi aduce containerului un OOM-kill. make limits afișează fiecare serviciu activat cu limita lui, te avertizează când cel mai rău caz nu încape și scrie în .env.limits doar limite de CPU, acolo unde un default cere mai multe nuclee decât ai. Serviciile CUDA știu de managerul de resurse, deci bugetul socotește cel mai mare dintre ele, nu fiecare serviciu de GPU la alocare maximă simultan. Faci upgrade de la un aigate mai vechi? Rulează din nou make limits, pentru că un .env.limits vechi încă ține limite de memorie în procente care bat noile defaulturi și îl pot lăsa pe talkies-cuda sub cât le trebuie modelelor lui ca măcar să se încarce.
# free tier, auto-fallback
curl http://localhost:4000/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "groq-gpt-oss-120b", "messages": [{"role":"user","content":"hello"}]}'
# local, no network, no limits
curl http://localhost:4000/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "local-ollama-cpu-llama3.2-3b", "messages": [{"role":"user","content":"hello"}]}'
# image generation (FLUX, local CUDA)
curl http://localhost:4000/images/generations \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "local-sdcpp-cuda-flux-schnell", "prompt": "a cat riding a skateboard"}'
# local image generation (no network, no cost)
curl http://localhost:4000/images/generations \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "local-sdcpp-cpu-sd-turbo", "prompt": "a red panda in a forest", "size": "512x512"}'
# transcription (local, CPU)
curl http://localhost:4000/audio/transcriptions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-F "model=local-talkies-whisper-large-v3-turbo" -F "[email protected]"
# text-to-speech (local, multiple voices)
curl http://localhost:4000/audio/speech \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "local-talkies-kokoro-tts", "input": "Hello world", "voice": "af_heart"}' \
-o speech.mp3
# web search (no API key, self-hosted)
curl http://localhost:4000/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "groq-qwen3.8-27b", "messages": [{"role":"user","content":"search the web for latest rust release notes"}]}'
# async — submit and poll
curl http://localhost:4000/q/v1/chat/completions \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{"model": "cerebras-gpt-oss-120b", "messages": [{"role":"user","content":"write a novel"}]}'Cinci provideri cu nivel gratuit, cinci motoare locale, restul ca fallback. Mai lent pe un calculator normal, dar merge, e privat și nu te poate da nimeni afară din propria ta infrastructură cu o limită de rată.
github.com/psyb0t/aigate
Cum Îl Instalezi în Agentul Tău
Skill-ul ăla nu mai e doar pentru OpenClaw. Tot ce e sub .agents/ e catalogat într-un singur marketplace, deci sunt două comenzi:
claude plugin marketplace add psyb0t/agents
claude plugin install aigate@psyb0tCodex folosește același marketplace cu alt verb, codex plugin add aigate@psyb0t, pentru că nu există codex plugin install. Îl mai și găsește singur într-un checkout al repo-ului, pentru că scanează nativ .agents/skills/ fără să fie instalat absolut nimic.