Skip to content

🧭 NeXuS Compass — 2026-07-28 — Universal API Proxy + NeXuS Web Server

Theme: Built the sovereign serving+key layer. One portable pure-Python HTTPS server that serves any app AND fronts every AI provider through one /api/* proxy that injects keys server-side (no key ever in the browser). Grew it into a universal API server (declare any provider from an env file). Loaded all of Anon's keys. Started wiring the web char-gen to it.

Prev compass: NEXUS_COMPASS_2026-07-24_ai-home-web-and-python-chargens.md. Export of this session: ~/Projects/adv-ai-nexus/advanced-ai-character-generator-terminal-access/2026-07-28-214801-created-api-universal-proxy.txt


⭐ What shipped (DONE + verified)

1. Security — Pollinations key rotated ✅

  • Anon revoked leaked sk_jOK7… at enter.pollinations.ai. Keeper sk_6ZnG… (name backend-rotten-cicada) validated live (no rate limit). 9 plaintext copies in ~/Projects/beta/ai-character-generator/ now inert → beta archive unblocked.

2. NeXuS Web Server — the deliverable

  • ~/Projects/nexus-web-server/nexus_web_server.py — one file, pure stdlib (no node/npm/pip). Own Fossil ~/museum/nexus-web-server.fossil (commits 7a158386c2, 4ce3ea5b74, 2783886d0b; models-endpoint + CSP fix still UNCOMMITTED).
  • Two jobs, split: (A) STATIC serve --root (per-app SPA fallback, multi-app landing); (B) PROXY /api/* injects keys from nexus.env/.local.env server-side.
  • Retired node from char-gen production: launch.sh now calls $NEXUS_WEB_SERVER --root dist --cert … --key …; Python-first, node/npm now OPTIONAL (dev/build). server-production.js kept as fallback. In-project server copies archived (.migrated/.superseded).
  • Portable/versatile: --root <dir> (default ./dist), serves any app folder, --env, --cert/--key.

3. UNIVERSAL API SERVER (the leap)

  • Dynamic providers from the env file — no code edit: scan for PROVIDER_<ID>_BASE_URL (+_API_KEY optional → keyed/keyless, _KIND, _LABEL). Registered on the fly, appears in /api/providers, callable at /api/llm/<id>/v1/chat/completions. No restart.
  • Secure .local.env: precedence process-env > .local.env > nexus.env > legacy. Guards: never web-served (static 404s any .env/.key/.pem/dotfile even inside docroot); auto-.gitignore (startup appends secret patterns to a .gitignore in the folder, append-only); never logged/returned; chmod-600 warning. Template .local.env.example.
  • Routes: /api/health, /api/providers (sanitized), /api/models/{image,text} (Pollinations), /api/models/provider/{id} (NEW — live per-provider /models, normalized), /api/pollinations/image (streamed), /api/llm (body-style) + /api/llm/{provider}/v1/chat/completions (vanilla OpenAI body).
  • CSP fix: added worker-src 'self' blob: (app web-workers were being blocked).

4. All of Anon's API keys loaded → ~/.config/nexus/secrets/nexus.env (chmod 600, backed up)

From /home/user/API/hackenstacks-apis.txt (masked-parse; skipped 2FA/backup codes, Porkbun, GitHub tokens, model-name lists): - Built-in keyed: MISTRAL_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY. - Stored (wire later): GEMINI_API_KEY/GOOGLE_API_KEY, HUGGINGFACE_API_KEY, STABILITY_API_KEY, IMAGEROUTER_API_KEY. - Dynamic providers (live): deepseek, together, hyperbolic, cerebras, google (Gemini via its OpenAI-compat endpoint), grok (free via Pollinations). - 12 providers now READY (only openai lacks a key). Pollinations kept the good sk_6ZnG… (ignored the corrupted 6sk_… in the file). - Live /models verified: mistral 60, google 57, cerebras 3, deepseek 2, pollinations 157.

5. Web char-gen wiring (partial — see PENDING)

  • services/nexusProxy.ts (NEW): fetch interceptor (OpenCharacters new Proxy(fetch) idea) — rewrites cloud chat hosts → same-origin /api/llm/<provider> and strips the client key. Installed first-thing in index.tsx. Verified live in log: [nexus-proxy] gen.pollinations.ai/… → /api/llm/pollinations (key server-side).
  • Terminal bridges (fileSystemService.ts callAichat/callOllama) → proxy.
  • Summarizer (geminiService.ts generateContent) → proxy; default/aihorde fall back to Pollinations, not Gemini (killed the Default Gemini API key not configured error).
  • Terminal awareness in the TEXT system prompt (buildSystemInstruction, when terminalEnabled) for ALL providers — fixes non-Gemini characters (A.I.M.E on AI Horde) wrongly claiming "I can't browse." An assertive version is written (counters strong personas + "paste it yourself" deferral).
  • Proven: connected to A.I.M.E through the proxy with her real persona — she emitted search latest AI buzz instead of refusing. In the live app she now emits search … too.

6. Docs

  • ~/Projects/nexus-web-server/docs/nexus-web-server_HELP.md — visual manual + 100% requirements checklist (Python ≥3.8 stdlib-only, cert, root, port; keys conditional; node only to rebuild JS).
  • ~/claude/docs/pollinations-api-reference.md refreshed from newest upstream capture (~/claude/pollinations/latest-pollinations-llm-info.md): 3D/video/voice/embeddings, prompt caching, safety redaction, media storage, BYOP OAuth; refreshed model lists; pk_ = BYOP App Key.

⏳ PENDING — "B" not finished + a live bug

B (server-driven UI) — half done

  • ✅ Server /api/models/provider/{id} built.
  • ❌ geminiService.ts streamChatResponse dispatch: new dynamic providers (deepseek/google/grok/together/hyperbolic/cerebras) currently fall through to AI Horde — must route ALL OpenAI-compatible services through /api/llm/{service} (make streamOpenAIChatResponse target the proxy URL from config.service, drop client auth). gemini→SDK, aihorde/default→AIHorde.
  • ❌ UI dropdowns: replace hardcoded API_PRESETS in CharacterForm.tsx (chat + summary) and the image provider in PluginManager.tsx with a fetch of /api/providers (+ key_present readiness) and models from /api/models/provider/{id} (or /api/models/{text,image}). Remove the key + endpoint input fields (add a "managed server-side" note). Single source of truth = server (kills the API_PRESETS dual-source-of-truth — the [[feedback_dankshell_owns_settings]] trap).

Live A.I.M.E bug (diagnosed, NOT fixed)

  • Symptom: she emits search …, but results don't display; auto-summary loops (Auto-summarizing: 50 → 44 → 37 messages) and the terminal search sits at approval.
  • Mechanics (components/ChatInterface.tsx): autoSummarizeIfNeeded (L201) fires every turn once messages.length >= L1_THRESHOLD, trims the last L1_THRESHOLD msgs (L257) → likely eats the terminal output/response. Terminal search needs approval via permissionManager.checkPermission (L407) → modal.
  • Fixes to try: (a) auto-approve safe read-only terminal cmds (search/curl/http) or set always-approve; (b) make auto-summary non-destructive / not fire mid terminal-loop / raise threshold / guard re-entrancy so it doesn't trim the just-produced result.

Rebuild pending

  • Latest source edits (assertive terminal instruction, generateContent proxy, terminal bridges) are only partly in the running bundle. Running build = index-DY9YfE47.js. Need npm run build to bake the assertive terminal awareness + confirm everything.

🔧 UNCOMMITTED (review + commit next session)

  • nexus-web-server.fossil: nexus_web_server.py EDITED (models endpoint + CSP + .local.env + dynamic providers — earlier .local.env/dynamic already committed 2783886d0b; models+CSP not yet).
  • nexus-ai-home.fossil (char-gen): services/nexusProxy.ts (new), index.tsx, launch.sh, services/fileSystemService.ts, services/geminiService.ts — all EDITED, uncommitted. dist/ rebuilt. Backups made for each (.bak-*).

🚦 NEXT SESSION order

  1. Fix streamChatResponse dispatch → route all OpenAI-compat (incl dynamic) via /api/llm/{service}.
  2. npm run build; verify deepseek/google/grok/mistral chat + summarizer via the new keys.
  3. B UI: server-driven provider/model dropdowns in CharacterForm + PluginManager; strip key/endpoint fields.
  4. Fix A.I.M.E auto-summary vs terminal-result display + terminal auto-approve for read-only cmds.
  5. Commit everything (both repos) with detailed messages; update reports.
  6. (Deferred) archive beta dir; Fossilize nexus-charcard.

🗝️ Gotchas / notes

  • Server reads secrets on-demand → adding a key to nexus.env needs no restart; adding a route (code) does need a restart. Launch it with run_in_background: true + no exec (exec/& get reaped).
  • curl -I (HEAD) is NOT implemented → check headers with curl -D - … -o /dev/null (a GET).
  • fish shell prints exit 144 noise on piped/pkill commands — output still valid.
  • Provider ids must match server registry; grok = Pollinations-backed (no xAI key on file); AI Horde file entry was just z → uses keyless anon 0000000000.